--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/fixbot/api.py Mon Sep 15 00:27:05 2008 +0300
@@ -0,0 +1,212 @@
+from twisted.internet import protocol, reactor
+from twisted.python import log
+from datetime import datetime
+import sys
+
+import buffer
+
+from api_secret import secret
+
+class ModuleInfo (object) :
+ """
+ Some info about a module
+ """
+
+ # module's name
+ name = None
+
+ # module's version, as a 16-bit integer
+ version = None
+
+ # list of valid event types (strings)
+ event_types = None
+
+ def __str__ (self) :
+ return "Module %s:%d" % (self.name, self.version)
+
+ def __repr__ (self) :
+ return "<module %s:%d with events: %s>" % (self.name, self.version, ", ".join(self.event_types))
+
+class Event (object) :
+ # the ModuleInfo object
+ module = None
+
+ # the event type as a string
+ type = None
+
+ # event message as a string (under 255 bytes in length!)
+ msg = None
+
+ # timestamp as a datetime.datetime
+ when = None
+
+ def __init__ (self, module, type, msg) :
+ assert type in module.event_types, "Invalid event-type %s for %r" % (type, self.module)
+
+ self.module = module
+ self.type = type
+ self.msg = msg
+
+ self.when = datetime.now()
+
+ def __str__ (self) :
+ return "[%s] %s" % (self.type, self.msg)
+
+ def __repr__ (self) :
+ return "%s @ %s" % (self.type, self.when)
+
+CLIENT_COMMANDS = [
+ "module_init",
+ "module_event",
+]
+
+SERVER_COMMANDS = [
+ "module_ok",
+]
+
+class ServerProtocol (buffer.StreamProtocol, protocol.Protocol) :
+ RECV_COMMANDS = CLIENT_COMMANDS
+ SEND_COMMANDS = SERVER_COMMANDS
+
+ VALID_STATES = [
+ "wait_init",
+ "wait_event"
+ ]
+
+ # proto state
+ state = None
+
+ # module info
+ module = None
+
+ def _assert (self, condition, msg) :
+ if not condition :
+ self.transport.loseConnection()
+ log.err("assert failed in APIProtocol for %s: %s" % (self.module, msg))
+
+ def connectionMade (self) :
+ log.msg("Client connected")
+
+ def connectionLost (self, reason) :
+ log.msg("Connection lost: %s" % reason)
+
+ if self.module :
+ self.factory.nexus.unregisterModule(self.module, reason.getErrorMessage())
+
+ def on_module_init (self, i) :
+ self._assert(not self.module, "module_init with non-None self.module")
+
+ peer_secret = i.readVarLen('B')
+
+ self._assert(peer_secret == secret, "Mismatching API secrets!")
+
+ m = ModuleInfo()
+
+ m.name = i.readVarLen('B')
+ m.version = i.readItem('H')
+
+ m.event_types = list(buffer.readStringStream(i, 'B'))
+ m.addr = self.transport.getPeer()
+
+ self.module_name = m.name
+
+ log.msg("Got mod_init for %r" % m)
+
+ self.factory.nexus.registerModule(m, self)
+
+ self.module = m
+
+ o = self.startCommand('module_ok')
+
+ self.send(o)
+
+ def on_module_event (self, i) :
+ self._assert(self.module, "module_event with None self.module!")
+
+ event_type = i.readEnum(self.module.event_types)
+ event_msg = i.readVarLen('B')
+
+ e = Event(self.module, event_type, event_msg)
+
+# log.msg("Got mod_event of %r" % (e))
+
+ self.factory.nexus.handleEvent(e)
+
+ def logPrefix (self) :
+ if self.module :
+ return str(self.module)
+ else :
+ return super(ServerProtocol, self).logPrefix()
+
+class ClientProtocol (buffer.StreamProtocol, protocol.Protocol) :
+ RECV_COMMANDS = SERVER_COMMANDS
+ SEND_COMMANDS = CLIENT_COMMANDS
+
+ def connectionMade (self) :
+ log.msg("Connected to API server, sending module init message")
+
+ o = self.startCommand('module_init')
+ o.writeVarLen('B', secret)
+ o.writeVarLen('B', self.factory.name)
+ o.writeItem("H", self.factory.version)
+ buffer.writeStringStream(o, 'B', self.factory.event_types)
+
+ self.send(o)
+
+ def sendEvent (self, event) :
+ o = self.startCommand('module_event')
+ o.writeEnum(self.factory.event_types, event.type)
+ o.writeVarLen('B', event.msg)
+
+ self.send(o)
+
+ def on_module_ok (self, i) :
+ log.msg("Registration OK")
+
+ self.factory.connected(self)
+
+ def logPrefix (self) :
+ return "module %s:%d client" % (self.factory.name, self.factory.version)
+
+class Module (ModuleInfo, protocol.ClientFactory) :
+ protocol = ClientProtocol
+
+ def __init__ (self) :
+ log.msg("Connecting to %s:%d" % (SERVER_HOST, PORT))
+ reactor.connectTCP(SERVER_HOST, PORT, self)
+
+ self.connection = None
+
+ def run (self) :
+ log.startLogging(sys.stderr)
+
+ reactor.run()
+
+ def connected (self, connection) :
+ log.msg("Connected!")
+ self.connection = connection
+
+ self.handleConnect()
+
+ def disconnect (self) :
+ self.connection.transport.loseConnection()
+
+ def sendEvent (self, type, msg) :
+ self.connection.sendEvent(self.buildEvent(type, msg))
+
+ def buildEvent (self, type, msg) :
+ return Event(self, type, msg)
+
+ def handleConnect (self) :
+ """
+ Do something
+ """
+
+ pass
+
+class ServerFactory (protocol.ServerFactory) :
+ protocol = ServerProtocol
+
+ def __init__ (self, nexus) :
+ self.nexus = nexus
+