Mercurial > bitten > bitten-test
annotate bitten/util/beep.py @ 14:1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
author | cmlenz |
---|---|
date | Thu, 16 Jun 2005 20:37:38 +0000 |
parents | 21aa17f97522 |
children | 06207499c58c |
rev | line source |
---|---|
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
1 # -*- coding: iso8859-1 -*- |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
2 # |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
3 # Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de> |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
4 # |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
5 # Bitten is free software; you can redistribute it and/or |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
6 # modify it under the terms of the GNU General Public License as |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
7 # published by the Free Software Foundation; either version 2 of the |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
8 # License, or (at your option) any later version. |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
9 # |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
10 # Trac is distributed in the hope that it will be useful, |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
13 # General Public License for more details. |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
14 # |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
15 # You should have received a copy of the GNU General Public License |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
16 # along with this program; if not, write to the Free Software |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
18 # |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
19 # Author: Christopher Lenz <cmlenz@gmx.de> |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
20 |
11 | 21 """Minimal implementation of the BEEP protocol (IETF RFC 3080) based on the |
22 `asyncore` module. | |
23 | |
24 Current limitations: | |
25 * No support for the TSL and SASL profiles. | |
26 * No support for mapping frames (SEQ frames for TCP mapping). | |
27 """ | |
28 | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
29 import asynchat |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
30 import asyncore |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
31 from email.Message import Message |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
32 from email.Parser import Parser |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
33 import socket |
10 | 34 import sys |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
35 import time |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
36 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
37 from bitten.util.xmlio import Element, parse_xml |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
38 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
39 __all__ = ['Listener', 'Initiator', 'Profile'] |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
40 |
10 | 41 |
11 | 42 BEEP_XML = 'application/beep+xml' |
43 | |
44 | |
45 class ProtocolError(Exception): | |
46 """Generic root class for BEEP exceptions.""" | |
47 | |
48 | |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
49 class TerminateSession(Exception): |
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
50 """Signal termination of a session.""" |
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
51 |
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
52 |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
53 class Listener(asyncore.dispatcher): |
10 | 54 """BEEP peer in the listener role. |
55 | |
56 This peer opens a socket for listening to incoming connections. For each | |
57 connection, it opens a new session: an instance of `Session` that handle | |
58 communication with the connected peer. | |
59 """ | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
60 def __init__(self, ip, port): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
61 asyncore.dispatcher.__init__(self) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
62 self.create_socket(socket.AF_INET, socket.SOCK_STREAM) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
63 self.set_reuse_addr() |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
64 self.bind((ip, port)) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
65 self.profiles = {} |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
66 self.listen(5) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
67 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
68 def writable(self): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
69 return False |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
70 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
71 def handle_read(self): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
72 pass |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
73 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
74 def readable(self): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
75 return True |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
76 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
77 def handle_connect(self): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
78 pass |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
79 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
80 def handle_accept(self): |
10 | 81 """Start a new BEEP session.""" |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
82 conn, addr = self.accept() |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
83 print 'Connected to %s:%s' % addr |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
84 Session(conn, addr, self.profiles, first_channelno=2) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
85 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
86 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
87 class Session(asynchat.async_chat): |
10 | 88 """A BEEP session between two peers.""" |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
89 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
90 def __init__(self, conn, addr, profiles, first_channelno=1): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
91 asynchat.async_chat.__init__(self, conn) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
92 self.addr = addr |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
93 self.set_terminator('\r\n') |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
94 |
10 | 95 self.profiles = profiles or {} |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
96 self.inbuf = [] |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
97 self.header = self.payload = None |
11 | 98 |
99 self.channelno = cycle_through(first_channelno, 2147483647, step=2) | |
100 self.channels = {0: Channel(self, 0, ManagementProfile())} | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
101 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
102 def handle_connect(self): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
103 pass |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
104 |
10 | 105 def handle_error(self): |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
106 """Called by asyncore when an exception is raised.""" |
10 | 107 t, v = sys.exc_info()[:2] |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
108 if t is TerminateSession: |
10 | 109 raise t, v |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
110 asynchat.async_chat.handle_error(self) |
10 | 111 |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
112 def collect_incoming_data(self, data): |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
113 """Called by async_chat when data is received. |
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
114 |
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
115 Buffer the data and wait until a terminator is found.""" |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
116 self.inbuf.append(data) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
117 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
118 def found_terminator(self): |
10 | 119 """Called by async_chat when a terminator is found in the input |
11 | 120 stream. |
121 | |
122 Parse the incoming data depending on whether it terminated on the frame | |
123 header, playload or trailer. For the header, extract the payload size | |
124 parameter and use it as terminator or the payload. When the trailer has | |
125 been received, delegate to `_handle_frame()`. | |
126 """ | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
127 if self.header is None: |
11 | 128 # Frame header received |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
129 self.header = ''.join(self.inbuf).split(' ') |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
130 self.inbuf = [] |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
131 if self.header[0] == 'SEQ': |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
132 # TCP mapping frame |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
133 raise NotImplementedError |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
134 else: |
11 | 135 # Extract payload size to use as next terminator |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
136 try: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
137 size = int(self.header[int(self.header[0] != 'ANS') - 2]) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
138 except ValueError: |
11 | 139 # TODO: Malformed frame... should we terminate the session |
140 # here? | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
141 self.header = None |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
142 return |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
143 if size == 0: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
144 self.payload = '' |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
145 self.set_terminator('END\r\n') |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
146 else: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
147 self.set_terminator(size) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
148 elif self.payload is None: |
11 | 149 # Frame payload received |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
150 self.payload = ''.join(self.inbuf) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
151 self.inbuf = [] |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
152 self.set_terminator('END\r\n') |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
153 else: |
11 | 154 # Frame trailer received |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
155 try: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
156 self._handle_frame(self.header, self.payload) |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
157 finally: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
158 self.header = self.payload = None |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
159 self.inbuf = [] |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
160 self.set_terminator('\r\n') |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
161 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
162 def _handle_frame(self, header, payload): |
10 | 163 """Handle an incoming frame. |
164 | |
165 This parses the frame header and decides which channel to pass it to. | |
166 """ | |
11 | 167 msgno = None |
168 channel = None | |
169 try: | |
170 cmd = header[0].upper() | |
171 channel = int(header[1]) | |
172 msgno = int(header[2]) | |
173 more = header[3] == '*' | |
174 seqno = int(header[4]) | |
175 size = int(header[5]) | |
10 | 176 ansno = None |
11 | 177 if cmd == 'ANS': |
178 ansno = int(header[6]) | |
179 self.channels[channel].handle_frame(cmd, msgno, more, seqno, | |
180 ansno, payload) | |
181 except (ValueError, TypeError, ProtocolError), e: | |
182 if channel == 0 and msgno is not None: | |
183 self.channels[0].profile.send_error(msgno, 550, e) | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
184 |
10 | 185 def send_frame(self, cmd, channel, msgno, more, seqno, ansno=None, |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
186 payload=''): |
10 | 187 """Send the specified data frame to the peer.""" |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
188 headerbits = [cmd, channel, msgno, more and '*' or '.', seqno, |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
189 len(payload)] |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
190 if cmd == 'ANS': |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
191 assert ansno is not None |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
192 headerbits.append(ansno) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
193 header = ' '.join([str(hb) for hb in headerbits]) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
194 self.push('\r\n'.join((header, payload, 'END', ''))) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
195 |
11 | 196 |
197 class Initiator(Session): | |
198 """Root class for BEEP peers in the initiating role.""" | |
199 | |
200 def __init__(self, ip, port, profiles=None): | |
201 """Create the BEEP session. | |
202 | |
203 @param ip: The IP address to connect to | |
204 @param port: The port to connect to | |
205 @param profiles: A dictionary of the supported profiles, where the key | |
206 is the URI identifying the profile, and the value is a | |
207 `Profile` instance that will handle the communication | |
208 for that profile | |
209 """ | |
210 Session.__init__(self, None, None, profiles or {}) | |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
211 self.terminated = False |
11 | 212 self.create_socket(socket.AF_INET, socket.SOCK_STREAM) |
213 self.connect((ip, port)) | |
10 | 214 |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
215 def handle_close(self): |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
216 self.terminated = True |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
217 |
10 | 218 def greeting_received(self, profiles): |
11 | 219 """Sub-classes should override this to start the channels they need. |
10 | 220 |
221 @param profiles: A list of URIs of the profiles the peer claims to | |
222 support. | |
223 """ | |
224 | |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
225 def run(self): |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
226 """Start this peer, which will try to connect to the server and send a |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
227 greeting. |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
228 """ |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
229 while not self.terminated: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
230 try: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
231 asyncore.loop() |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
232 print 'Normal exit' |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
233 self.terminated = True |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
234 except (KeyboardInterrupt, TerminateSession): |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
235 self._quit() |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
236 time.sleep(.25) |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
237 |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
238 def _quit(self): |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
239 channelno = max(self.channels.keys()) |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
240 def handle_ok(): |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
241 if channelno == 0: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
242 self.terminated = True |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
243 else: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
244 self._quit() |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
245 def handle_error(code, message): |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
246 raise ProtocolError, '%s (%d)' % (message, code) |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
247 self.channels[0].profile.send_close(channelno, handle_ok=handle_ok, |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
248 handle_error=handle_error) |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
249 |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
250 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
251 class Channel(object): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
252 """A specific channel of a BEEP session.""" |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
253 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
254 def __init__(self, session, channelno, profile): |
11 | 255 """Create the channel. |
256 | |
257 @param session The `Session` object that the channel belongs to | |
258 @param channelno The channel number | |
259 @param profile The associated `Profile` object | |
260 """ | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
261 self.session = session |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
262 self.channelno = channelno |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
263 self.inqueue = {} |
11 | 264 self.outqueue = [] |
10 | 265 self.reply_handlers = {} |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
266 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
267 self.msgno = cycle_through(0, 2147483647) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
268 self.msgnos = {} # message numbers currently in use |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
269 self.ansnos = {} # answer numbers keyed by msgno, each 0-2147483647 |
11 | 270 self.seqno = [serial(), serial()] # incoming, outgoing sequence numbers |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
271 self.mime_parser = Parser() |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
272 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
273 self.profile = profile |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
274 self.profile.session = self.session |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
275 self.profile.channel = self |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
276 self.profile.handle_connect() |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
277 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
278 def handle_frame(self, cmd, msgno, more, seqno, ansno, payload): |
11 | 279 """Process a single data frame. |
280 | |
281 @param cmd: The frame keyword (MSG, RPY, ERR, ANS or NUL) | |
282 @param msgno: The message number | |
283 @param more: `True` if more frames are pending for this message | |
284 @param seqno: Sequence number of the frame | |
285 @param ansno: The answer number for 'ANS' messages, otherwise `None` | |
286 @param payload: The frame payload as a string | |
287 """ | |
10 | 288 # Validate and update sequence number |
289 if seqno != self.seqno[0]: | |
11 | 290 raise ProtocolError, 'Out of sync with peer' # TODO: Be nice |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
291 self.seqno[0] += len(payload) |
10 | 292 |
293 if more: | |
294 # More of this message pending, so push it on the queue | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
295 self.inqueue.setdefault(msgno, []).append(payload) |
10 | 296 return |
297 | |
298 # Complete message received, so handle it | |
299 if msgno in self.inqueue.keys(): | |
300 # Recombine queued messages | |
301 payload = ''.join(self.inqueue[msgno]) + payload | |
302 del self.inqueue[msgno] | |
303 if cmd == 'RPY' and msgno in self.msgnos.keys(): | |
304 # Final reply using this message number, so dealloc | |
305 del self.msgnos[msgno] | |
306 message = None | |
307 if payload: | |
308 message = self.mime_parser.parsestr(payload) | |
309 | |
310 if cmd == 'MSG': | |
311 self.profile.handle_msg(msgno, message) | |
312 else: | |
313 if msgno in self.reply_handlers.keys(): | |
314 self.reply_handlers[msgno](cmd, msgno, message) | |
315 del self.reply_handlers[msgno] | |
316 elif cmd == 'RPY': | |
317 self.profile.handle_rpy(msgno, message) | |
318 elif cmd == 'ERR': | |
319 self.profile.handle_err(msgno, message) | |
320 elif cmd == 'ANS': | |
321 self.profile.handle_ans(msgno, ansno, message) | |
322 elif cmd == 'NUL': | |
323 self.profile.handle_nul(msgno) | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
324 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
325 def _send(self, cmd, msgno, ansno=None, message=None): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
326 # TODO: Fragment and queue the message if necessary; |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
327 # First need TCP mapping (RFC 3081) for that to make real sense |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
328 payload = '' |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
329 if message is not None: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
330 payload = message.as_string() |
10 | 331 self.session.send_frame(cmd, self.channelno, msgno, False, |
332 self.seqno[1].value, payload=payload, | |
333 ansno=ansno) | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
334 self.seqno[1] += len(payload) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
335 |
10 | 336 def send_msg(self, message, handle_reply=None): |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
337 while True: # Find a unique message number |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
338 msgno = self.msgno.next() |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
339 if msgno not in self.msgnos.keys(): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
340 break |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
341 self.msgnos[msgno] = True # Flag the chosen message number as in use |
10 | 342 if handle_reply is not None: |
343 self.reply_handlers[msgno] = handle_reply | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
344 self._send('MSG', msgno, None, message) |
10 | 345 return msgno |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
346 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
347 def send_rpy(self, msgno, message): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
348 self._send('RPY', msgno, None, message) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
349 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
350 def send_err(self, msgno, message): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
351 self._send('ERR', msgno, None, message) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
352 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
353 def send_ans(self, msgno, message): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
354 if not msgno in self.ansnos.keys(): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
355 ansno = cycle_through(0, 2147483647) |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
356 self.ansnos[msgno] = ansno |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
357 else: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
358 ansno = self.ansnos[msgno] |
10 | 359 next_ansno = ansno.next() |
360 self._send('ANS', msgno, next_ansno, message) | |
361 return next_ansno | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
362 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
363 def send_nul(self, msgno): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
364 self._send('NUL', msgno) |
10 | 365 del self.ansnos[msgno] # dealloc answer numbers for the message |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
366 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
367 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
368 class Profile(object): |
11 | 369 """Abstract base class for handlers of specific BEEP profiles. |
370 | |
371 Concrete subclasses need to at least implement the `handle_msg()` method, | |
372 and may override any of the others. | |
373 """ | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
374 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
375 def __init__(self): |
11 | 376 """Create the profile.""" |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
377 self.session = None |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
378 self.channel = None |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
379 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
380 def handle_connect(self): |
11 | 381 """Called when the channel this profile is associated with is |
382 initially started.""" | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
383 pass |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
384 |
10 | 385 def handle_msg(self, msgno, message): |
386 raise NotImplementedError | |
387 | |
388 def handle_rpy(self, msgno, message): | |
11 | 389 pass |
10 | 390 |
391 def handle_err(self, msgno, message): | |
11 | 392 pass |
10 | 393 |
394 def handle_ans(self, msgno, ansno, message): | |
11 | 395 pass |
10 | 396 |
397 def handle_nul(self, msgno): | |
11 | 398 pass |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
399 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
400 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
401 class ManagementProfile(Profile): |
11 | 402 """Implementation of the BEEP management profile.""" |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
403 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
404 def handle_connect(self): |
11 | 405 """Send a greeting reply directly after connecting to the peer.""" |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
406 greeting = Element('greeting')[ |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
407 [Element('profile', uri=k) for k in self.session.profiles.keys()] |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
408 ] |
11 | 409 self.channel.send_rpy(0, MIMEMessage(greeting, BEEP_XML)) |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
410 |
10 | 411 def handle_msg(self, msgno, message): |
11 | 412 assert message.get_content_type() == BEEP_XML |
413 elem = parse_xml(message.get_payload()) | |
414 | |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
415 if elem.tagname == 'start': |
11 | 416 for profile in elem['profile']: |
10 | 417 if profile.uri in self.session.profiles.keys(): |
11 | 418 print 'Start channel %s for profile <%s>' % (elem.number, |
419 profile.uri) | |
420 channel = Channel(self.session, int(elem.number), | |
421 self.session.profiles[profile.uri]) | |
422 self.session.channels[int(elem.number)] = channel | |
423 message = MIMEMessage(Element('profile', uri=profile.uri), | |
424 BEEP_XML) | |
425 self.channel.send_rpy(msgno, message) | |
426 return | |
427 self.send_error(msgno, 550, | |
428 'All requested profiles are unsupported') | |
429 | |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
430 elif elem.tagname == 'close': |
11 | 431 channelno = int(elem.number) |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
432 if not channelno in self.session.channels: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
433 self.send_error(msgno, 550, 'Channel not open') |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
434 return |
11 | 435 if channelno == 0: |
436 if len(self.session.channels) > 1: | |
437 self.send_error(msgno, 550, 'Other channels still open') | |
438 return | |
439 if self.session.channels[channelno].msgnos: | |
440 self.send_error(msgno, 550, 'Channel waiting for replies') | |
441 return | |
442 del self.session.channels[channelno] | |
443 message = MIMEMessage(Element('ok'), BEEP_XML) | |
10 | 444 self.channel.send_rpy(msgno, message) |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
445 if not self.session.channels: |
11 | 446 self.session.close() |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
447 |
10 | 448 def handle_rpy(self, msgno, message): |
11 | 449 assert message.get_content_type() == BEEP_XML |
450 elem = parse_xml(message.get_payload()) | |
451 | |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
452 if elem.tagname == 'greeting': |
11 | 453 if isinstance(self.session, Initiator): |
454 profiles = [profile.uri for profile in elem['profile']] | |
455 self.session.greeting_received(profiles) | |
456 | |
457 else: # <profile/> and <ok/> are handled by callbacks | |
458 self.send_error(msgno, 501, 'What are you replying to, son?') | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
459 |
10 | 460 def handle_err(self, msgno, message): |
11 | 461 # Probably an error on connect, because other errors should get handled |
462 # by the corresponding callbacks | |
463 # TODO: Terminate the session, I guess | |
464 assert message.get_content_type() == BEEP_XML | |
465 elem = parse_xml(message.get_payload()) | |
13
21aa17f97522
Initial code for build master and slave... these don't do a lot yet.
cmlenz
parents:
12
diff
changeset
|
466 assert elem.tagname == 'error' |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
467 print 'Received error in response to message #%d: %s (%s)' \ |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
468 % (msgno, elem.gettext(), elem.code) |
10 | 469 |
11 | 470 def send_close(self, channelno=0, code=200, handle_ok=None, |
471 handle_error=None): | |
10 | 472 def handle_reply(cmd, msgno, message): |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
473 if cmd == 'RPY': |
11 | 474 del self.session.channels[channelno] |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
475 if handle_ok is not None: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
476 handle_ok() |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
477 if not self.session.channels: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
478 self.session.close() |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
479 elif cmd == 'ERR': |
11 | 480 elem = parse_xml(message.get_payload()) |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
481 if handle_error is not None: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
482 handle_error(int(elem.code), elem.gettext()) |
11 | 483 xml = Element('close', number=channelno, code=code) |
484 return self.channel.send_msg(MIMEMessage(xml, BEEP_XML), handle_reply) | |
10 | 485 |
11 | 486 def send_error(self, msgno, code, message=''): |
487 xml = Element('error', code=code)[message] | |
488 self.channel.send_err(msgno, MIMEMessage(xml, BEEP_XML)) | |
489 | |
490 def send_start(self, profiles, handle_ok=None, handle_error=None): | |
10 | 491 channelno = self.session.channelno.next() |
492 def handle_reply(cmd, msgno, message): | |
493 if handle_ok is not None and cmd == 'RPY': | |
11 | 494 elem = parse_xml(message.get_payload()) |
495 for profile in [p for p in profiles if p.URI == elem.uri]: | |
496 self.session.channels[channelno] = Channel(self.session, | |
497 channelno, | |
498 profile()) | |
499 break | |
500 handle_ok(channelno, elem.uri) | |
10 | 501 if handle_error is not None and cmd == 'ERR': |
11 | 502 elem = parse_xml(message.get_payload()) |
503 handle_error(int(elem.code), elem.gettext()) | |
12 | 504 |
10 | 505 xml = Element('start', number=channelno)[ |
506 [Element('profile', uri=profile.URI) for profile in profiles] | |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
507 ] |
11 | 508 return self.channel.send_msg(MIMEMessage(xml, BEEP_XML), handle_reply) |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
509 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
510 |
14
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
511 class MIMEMessage(Message): |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
512 """Simplified construction of generic MIME messages for transmission as |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
513 payload with BEEP.""" |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
514 |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
515 def __init__(self, payload, content_type=None): |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
516 Message.__init__(self) |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
517 if content_type: |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
518 self.set_type(content_type) |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
519 self.set_payload(str(payload)) |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
520 del self['MIME-Version'] |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
521 |
1733c601d2f8
Refactored the asyncore loop and shutdown procedure into {{{beep.Initiator}}}.
cmlenz
parents:
13
diff
changeset
|
522 |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
523 def cycle_through(start, stop=None, step=1): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
524 """Utility generator that cycles through a defined range of numbers.""" |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
525 if stop is None: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
526 stop = start |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
527 start = 0 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
528 cur = start |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
529 while True: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
530 yield cur |
11 | 531 cur += step |
7
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
532 if cur > stop: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
533 cur = start |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
534 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
535 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
536 class serial(object): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
537 """Serial number (RFC 1982).""" |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
538 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
539 def __init__(self, limit=4294967295L): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
540 self.value = 0L |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
541 self.limit = limit |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
542 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
543 def __ne__(self, num): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
544 return self.value != num |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
545 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
546 def __eq__(self, num): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
547 return self.value == num |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
548 |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
549 def __iadd__(self, num): |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
550 self.value += num |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
551 if self.value > self.limit: |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
552 self.value -= self.limit |
8442bcb47a03
Initial draft of a minimal [http://www.beepcore.org/ BEEP] protocol implementation for communication between the build master and build slaves.
cmlenz
parents:
diff
changeset
|
553 return self |