blind error handling tweaks
authorTero Marttila <terom@fixme.fi>
Sat, 20 Feb 2010 23:06:43 +0200
changeset 64 8574aeff9b36
parent 63 a849c00b63f8
child 67 00907acd732a
blind error handling tweaks
fixbot/api/amp.py
fixbot/irc.py
fixbot/logwatch/sources.py
fixbot/module.py
--- a/fixbot/api/amp.py	Sat Feb 20 22:32:18 2010 +0200
+++ b/fixbot/api/amp.py	Sat Feb 20 23:06:43 2010 +0200
@@ -1,4 +1,5 @@
 from twisted.protocols import amp
+from twisted.python import log
 
 from fixbot.module import ModuleInfo, Event
 
@@ -21,6 +22,17 @@
         ('msg',     amp.String()),
     ]
 
+class CmdModuleAbort (amp.Command) :
+    """
+        Module has failed and will now disconnect
+    """
+
+    arguments = [
+        ('msg',     amp.String())   # string describing the error occuring
+    ]
+
+    requiresAnswer = False
+
 class ServerProtocol (amp.AMP) :
     """
         Nexus-side command handler
@@ -29,11 +41,25 @@
     # the registered ModuleInfo
     module = None
     
+    def connectionMade (self) :
+        log.msg("Module connecting from: %s" % (self.transport.getPeer()))
+
+
+    def connectionLost (self, reason) :
+        log.err(reason, "Module lost")
+        
+        if self.module :
+            # drop it
+            self.factory.nexus.unregisterModule(self.module, reason.getErrorMessage())
+
+
     @CmdModuleRegister.responder
     def on_ModuleRegister (self, name) :
         # construct the ModuleInfo
         mi = ModuleInfo()
         mi.name = name
+
+        log.msg("Module registered: %s" % (mi))
         
         # register
         self.factory.nexus.registerModule(mi, self)
@@ -52,7 +78,17 @@
 
         # ok
         return {}
+    
+    @CmdModuleAbort.responder
+    def on_ModuleAbort (self, msg) :
+        # unhook
+        module = self.module
+        self.module = None
 
+        # report
+        self.factory.nexus.unregisterModule(self.module, msg)
+        
+        # XXX: stop accepting commands etc?
 
 class ClientProtocol (amp.AMP) :
     """
@@ -68,6 +104,14 @@
         # register
         self.sendModuleRegister(self.factory.name).addCallback(self._ModuleRegisterOK)
     
+    def connectionLost (self, reason) :
+        """
+            Disconnected from nexus, for whatever reason...
+        """
+        
+        log.err(reason, "API connection lost")
+
+        # XXX: was this expected? Reconnect?
 
     def sendModuleRegister (self, name) :
         """
@@ -92,4 +136,20 @@
         
         self.callRemote(CmdModuleEvent, type=event.type, msg=event.msg)
 
+    def sendModuleAbort (self, msg) :
+        """
+            Send CmdModuleAbort - no response is expected
+        """
 
+        self.callRemote(CmdModuleAbort, msg=msg)
+
+
+    def abort (self, msg) :
+        """
+            Send abort message and drop connection
+        """
+
+        # disconnect. This should leave the transport to flush buffers, and then call connectionLost
+        # should also stop us from sending any more commands
+        self.transport.loseConnection()
+
--- a/fixbot/irc.py	Sat Feb 20 22:32:18 2010 +0200
+++ b/fixbot/irc.py	Sat Feb 20 23:06:43 2010 +0200
@@ -3,8 +3,6 @@
 from twisted.python import log
 import traceback
 
-import buffer
-
 class ReplyException (Exception) :
     def __init__ (self, reply) :
         self.reply = reply
--- a/fixbot/logwatch/sources.py	Sat Feb 20 22:32:18 2010 +0200
+++ b/fixbot/logwatch/sources.py	Sat Feb 20 23:06:43 2010 +0200
@@ -37,6 +37,13 @@
         log.err(msg)
         self.module.error(msg)
 
+    def connectionLost (self, reason) :
+        """
+            The transport we were connected to has dropped, possibly as a result of our handlers raising an error?
+        """
+
+        self.handleError("lost LogSource for %s: %s" % (self.name, reason.getErrorMessage()))
+
     def handleData (self, data) :
         """
             Feed binary data into the buffer, processing all lines via handleLine()
@@ -109,6 +116,9 @@
             else :
                 raise ValueError(out)
 
+    def logPrefix (self) :
+        return "LogSource(%s)" % (self.name, )
+
 class File (LogSource, protocol.ProcessProtocol) :
     """
         Stream lines from a regular file using /usr/bin/tail -f
@@ -149,11 +159,7 @@
 
     def handleEOF (self) :
         self.handleError("!!! EOF on fifo %s, re-opening" % self.name)
-        self.reopen()
-    
-    def connectionLost (self, reason) :
-        super(Fifo, self).connectionLost(reason)
-        self.handleError("lost fifo for %s: %s" % (self.name, reason.getErrorMessage()))
+        self.reopen()    
 
 class UnixDatagramSocket (LogSource, protocol.DatagramProtocol) :
     """
@@ -180,6 +186,4 @@
         # handle it as a line of data
         self.handleLine(data)
 
-    def logPrefix (self) :
-        return "LogSource(%s)" % (self.name, )
 
--- a/fixbot/module.py	Sat Feb 20 22:32:18 2010 +0200
+++ b/fixbot/module.py	Sat Feb 20 23:06:43 2010 +0200
@@ -13,7 +13,7 @@
     name = None
 
     def __str__ (self) :
-        return "Module %s:" % (self.name)
+        return "%s" % (self.name)
     
     def __repr__ (self) :
         return "<module %s>" % (self.name, )
@@ -70,6 +70,7 @@
 
         # XXX: legacy: self.secret = config['api-secret']
 
+
     def _onRegistered (self, connection) :
         """
             Connected to nexus and registered
@@ -78,16 +79,20 @@
         log.msg("Connected and registered")
 
         self.connection = connection
-
+        
+        # XXX: abort on errors?
         self.handleConnect()
 
+    
+    # XXX: unused, bad interface
     def disconnect (self) :
         """
             Disconnect from Nexus
         """
 
         self.connection.transport.loseConnection()
-    
+
+
     def sendEvent (self, type, msg) :
         """
             Send event to nexus
@@ -95,6 +100,7 @@
 
         self.connection.sendEvent(Event(self, type, msg))
 
+
     def handleConnect (self) :
         """
             Do something once we are connected to nexus and registered
@@ -102,6 +108,13 @@
 
         pass
 
+    def abort (self, err) :
+        """
+            Abort this module, disconnecting with the given error
+        """
+
+        self.connection.abort(str(err))
+
 def makeService (module_class, config, protocol) :
     s = service.MultiService()