author | Tero Marttila <terom@fixme.fi> |
Wed, 26 Mar 2008 01:12:11 +0200 | |
changeset 15 | e31e38d654b6 |
parent 6 | 614161f85d9b |
permissions | -rw-r--r-- |
4 | 1 |
from twisted.internet import protocol, reactor |
2 |
from twisted.python import log |
|
1 | 3 |
from datetime import datetime |
6
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
4 |
import sys |
1 | 5 |
|
6 |
import buffer |
|
7 |
||
4 | 8 |
PORT = 34888 |
9 |
SERVER_HOST = "127.0.0.1" |
|
1 | 10 |
|
6
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
11 |
from api_secret import secret |
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
12 |
|
1 | 13 |
class ModuleInfo (object) : |
14 |
""" |
|
15 |
Some info about a module |
|
16 |
""" |
|
17 |
||
18 |
# module's name |
|
19 |
name = None |
|
20 |
||
21 |
# module's version, as a 16-bit integer |
|
22 |
version = None |
|
23 |
||
24 |
# list of valid event types (strings) |
|
25 |
event_types = None |
|
26 |
||
27 |
def __str__ (self) : |
|
28 |
return "Module %s:%d" % (self.name, self.version) |
|
29 |
||
30 |
def __repr__ (self) : |
|
31 |
return "<module %s:%d with events: %s>" % (self.name, self.version, ", ".join(self.event_types)) |
|
32 |
||
33 |
class Event (object) : |
|
34 |
# the ModuleInfo object |
|
35 |
module = None |
|
36 |
||
37 |
# the event type as a string |
|
38 |
type = None |
|
39 |
||
40 |
# event message as a string (under 255 bytes in length!) |
|
41 |
msg = None |
|
42 |
||
43 |
# timestamp as a datetime.datetime |
|
44 |
when = None |
|
45 |
||
46 |
def __init__ (self, module, type, msg) : |
|
47 |
assert type in module.event_types, "Invalid event-type %s for %r" % (type, self.module) |
|
48 |
||
49 |
self.module = module |
|
50 |
self.type = type |
|
51 |
self.msg = msg |
|
52 |
||
53 |
self.when = datetime.now() |
|
54 |
||
55 |
def __str__ (self) : |
|
56 |
return "[%s] %s" % (self.type, self.msg) |
|
57 |
||
58 |
def __repr__ (self) : |
|
59 |
return "%s @ %s" % (self.type, self.when) |
|
4 | 60 |
|
61 |
CLIENT_COMMANDS = [ |
|
62 |
"module_init", |
|
63 |
"module_event", |
|
64 |
] |
|
65 |
||
66 |
SERVER_COMMANDS = [ |
|
67 |
"module_ok", |
|
68 |
] |
|
69 |
||
1 | 70 |
class ServerProtocol (buffer.StreamProtocol, protocol.Protocol) : |
4 | 71 |
RECV_COMMANDS = CLIENT_COMMANDS |
72 |
SEND_COMMANDS = SERVER_COMMANDS |
|
1 | 73 |
|
74 |
VALID_STATES = [ |
|
75 |
"wait_init", |
|
76 |
"wait_event" |
|
77 |
] |
|
78 |
||
79 |
# proto state |
|
80 |
state = None |
|
81 |
||
82 |
# module info |
|
83 |
module = None |
|
84 |
||
85 |
def _assert (self, condition, msg) : |
|
86 |
if not condition : |
|
87 |
self.transport.loseConnection() |
|
88 |
log.err("assert failed in APIProtocol for %s: %s" % (self.module, msg)) |
|
89 |
||
90 |
def connectionMade (self) : |
|
91 |
log.msg("Client connected") |
|
92 |
||
4 | 93 |
def connectionLost (self, reason) : |
94 |
log.msg("Connection lost: %s" % reason) |
|
95 |
||
96 |
if self.module : |
|
97 |
self.factory.nexus.unregisterModule(self.module, reason.getErrorMessage()) |
|
98 |
||
1 | 99 |
def on_module_init (self, i) : |
100 |
self._assert(not self.module, "module_init with non-None self.module") |
|
101 |
||
6
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
102 |
peer_secret = i.readVarLen('B') |
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
103 |
|
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
104 |
self._assert(peer_secret == secret, "Mismatching API secrets!") |
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
105 |
|
4 | 106 |
m = ModuleInfo() |
1 | 107 |
|
108 |
m.name = i.readVarLen('B') |
|
109 |
m.version = i.readItem('H') |
|
110 |
||
4 | 111 |
m.event_types = list(buffer.readStringStream(i, 'B')) |
1 | 112 |
m.addr = self.transport.getPeer() |
113 |
||
4 | 114 |
self.module_name = m.name |
1 | 115 |
|
4 | 116 |
log.msg("Got mod_init for %r" % m) |
117 |
||
118 |
self.factory.nexus.registerModule(m, self) |
|
1 | 119 |
|
4 | 120 |
self.module = m |
121 |
||
122 |
o = self.startCommand('module_ok') |
|
123 |
||
124 |
self.send(o) |
|
1 | 125 |
|
126 |
def on_module_event (self, i) : |
|
127 |
self._assert(self.module, "module_event with None self.module!") |
|
128 |
||
129 |
event_type = i.readEnum(self.module.event_types) |
|
130 |
event_msg = i.readVarLen('B') |
|
131 |
||
4 | 132 |
e = Event(self.module, event_type, event_msg) |
1 | 133 |
|
4 | 134 |
log.msg("Got mod_event of %r" % (e)) |
1 | 135 |
|
136 |
self.factory.nexus.handleEvent(e) |
|
137 |
||
138 |
def logPrefix (self) : |
|
139 |
if self.module : |
|
140 |
return str(self.module) |
|
141 |
else : |
|
6
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
142 |
return super(ServerProtocol, self).logPrefix() |
1 | 143 |
|
4 | 144 |
class ClientProtocol (buffer.StreamProtocol, protocol.Protocol) : |
145 |
RECV_COMMANDS = SERVER_COMMANDS |
|
146 |
SEND_COMMANDS = CLIENT_COMMANDS |
|
1 | 147 |
|
4 | 148 |
def connectionMade (self) : |
149 |
log.msg("Connected to API server, sending module init message") |
|
150 |
||
151 |
o = self.startCommand('module_init') |
|
6
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
152 |
o.writeVarLen('B', secret) |
4 | 153 |
o.writeVarLen('B', self.factory.name) |
154 |
o.writeItem("H", self.factory.version) |
|
155 |
buffer.writeStringStream(o, 'B', self.factory.event_types) |
|
156 |
||
157 |
self.send(o) |
|
158 |
||
159 |
def sendEvent (self, event) : |
|
160 |
o = self.startCommand('module_event') |
|
161 |
o.writeEnum(self.factory.event_types, event.type) |
|
162 |
o.writeVarLen('B', event.msg) |
|
163 |
||
164 |
self.send(o) |
|
165 |
||
166 |
def on_module_ok (self, i) : |
|
167 |
log.msg("Registration OK") |
|
168 |
||
169 |
self.factory.connected(self) |
|
170 |
||
171 |
def logPrefix (self) : |
|
172 |
return "module %s:%d client" % (self.factory.name, self.factory.version) |
|
173 |
||
174 |
class Module (ModuleInfo, protocol.ClientFactory) : |
|
175 |
protocol = ClientProtocol |
|
176 |
||
177 |
def __init__ (self) : |
|
178 |
log.msg("Connecting to %s:%d" % (SERVER_HOST, PORT)) |
|
179 |
reactor.connectTCP(SERVER_HOST, PORT, self) |
|
180 |
||
181 |
self.connection = None |
|
6
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
182 |
|
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
183 |
def run (self) : |
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
184 |
log.startLogging(sys.stderr) |
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
185 |
|
614161f85d9b
some cleanup, bugfixes, commands for the irc bot, shared-secret for the API
Tero Marttila <terom@paivola.fi>
parents:
4
diff
changeset
|
186 |
reactor.run() |
4 | 187 |
|
188 |
def connected (self, connection) : |
|
189 |
log.msg("Connected!") |
|
190 |
self.connection = connection |
|
191 |
||
192 |
self.handleConnect() |
|
193 |
||
194 |
def disconnect (self) : |
|
195 |
self.connection.transport.loseConnection() |
|
196 |
||
197 |
def sendEvent (self, type, msg) : |
|
198 |
self.connection.sendEvent(self.buildEvent(type, msg)) |
|
199 |
||
200 |
def buildEvent (self, type, msg) : |
|
201 |
return Event(self, type, msg) |
|
202 |
||
203 |
def handleConnect (self) : |
|
204 |
""" |
|
205 |
Do something |
|
206 |
""" |
|
207 |
||
208 |
pass |
|
209 |