add last parameter to plugin registration
[ikiwiki.git] / plugins / proxy.py
index 6f9b1f8525821645d1dee6580864ec3b9e320473..36facecc57e30266879ea3206ff23d459009f33c 100644 (file)
@@ -13,8 +13,6 @@ __author__ = 'martin f. krafft <madduck@madduck.net>'
 __copyright__ = 'Copyright © ' + __author__
 __licence__ = 'GPLv2'
 
-LOOP_DELAY = 0.1
-
 import sys
 import time
 import xmlrpclib
@@ -31,6 +29,9 @@ class _IkiWikiExtPluginXMLRPCDispatcher(SimpleXMLRPCDispatcher):
             # python2.4 and before only took one argument
             SimpleXMLRPCDispatcher.__init__(self)
 
+    def dispatch(self, method, params):
+        return self._dispatch(method, params)
+
 class _XMLStreamParser(object):
 
     def __init__(self):
@@ -77,8 +78,8 @@ class _XMLStreamParser(object):
 
 class _IkiWikiExtPluginXMLRPCHandler(object):
 
-    def __init__(self, debug_fn, allow_none=False, encoding=None):
-        self._dispatcher = _IkiWikiExtPluginXMLRPCDispatcher(allow_none, encoding)
+    def __init__(self, debug_fn):
+        self._dispatcher = _IkiWikiExtPluginXMLRPCDispatcher()
         self.register_function = self._dispatcher.register_function
         self._debug_fn = debug_fn
 
@@ -125,20 +126,28 @@ class _IkiWikiExtPluginXMLRPCHandler(object):
 
     def handle_rpc(self, in_fd, out_fd):
         self._debug_fn('waiting for procedure calls from ikiwiki...')
-        ret = _IkiWikiExtPluginXMLRPCHandler._read(in_fd)
-        if ret is None:
+        xml = _IkiWikiExtPluginXMLRPCHandler._read(in_fd)
+        if xml is None:
             # ikiwiki is going down
             self._debug_fn('ikiwiki is going down, and so are we...')
             return
 
-        self._debug_fn('received procedure call from ikiwiki: [%s]' % ret)
-        ret = self._dispatcher._marshaled_dispatch(ret)
-        self._debug_fn('sending procedure response to ikiwiki: [%s]' % ret)
-        _IkiWikiExtPluginXMLRPCHandler._write(out_fd, ret)
+        self._debug_fn('received procedure call from ikiwiki: [%s]' % xml)
+        params, method = xmlrpclib.loads(xml)
+        ret = self._dispatcher.dispatch(method, params)
+        xml = xmlrpclib.dumps((ret,), methodresponse=True)
+        self._debug_fn('sending procedure response to ikiwiki: [%s]' % xml)
+        _IkiWikiExtPluginXMLRPCHandler._write(out_fd, xml)
         return ret
 
 class IkiWikiProcedureProxy(object):
 
+    # how to communicate None to ikiwiki
+    _IKIWIKI_NIL_SENTINEL = {'null':''}
+
+    # sleep during each iteration
+    _LOOP_DELAY = 0.1
+
     def __init__(self, id, in_fd=sys.stdin, out_fd=sys.stdout, debug_fn=None):
         self._id = id
         self._in_fd = in_fd
@@ -151,17 +160,34 @@ class IkiWikiProcedureProxy(object):
         self._xmlrpc_handler = _IkiWikiExtPluginXMLRPCHandler(self._debug_fn)
         self._xmlrpc_handler.register_function(self._importme, name='import')
 
-    def hook(self, type, function):
-        self._hooks.append((type, function.__name__))
-        self._xmlrpc_handler.register_function(function)
+    def hook(self, type, function, name=None, last=False):
+        if name is None:
+            name = function.__name__
+        self._hooks.append((type, name, last))
+
+        def hook_proxy(*args):
+#            curpage = args[0]
+#            kwargs = dict([args[i:i+2] for i in xrange(1, len(args), 2)])
+            ret = function(*args)
+            self._debug_fn("%s hook `%s' returned: [%s]" % (type, name, ret))
+            if ret == IkiWikiProcedureProxy._IKIWIKI_NIL_SENTINEL:
+                raise IkiWikiProcedureProxy.InvalidReturnValue, \
+                        'hook functions are not allowed to return %s' \
+                        % IkiWikiProcedureProxy._IKIWIKI_NIL_SENTINEL
+            if ret is None:
+                ret = IkiWikiProcedureProxy._IKIWIKI_NIL_SENTINEL
+            return ret
+
+        self._xmlrpc_handler.register_function(hook_proxy, name=name)
 
     def _importme(self):
         self._debug_fn('importing...')
-        for type, function in self._hooks:
+        for type, function, last in self._hooks:
             self._debug_fn('hooking %s into %s chain...' % (function, type))
             self._xmlrpc_handler.send_rpc('hook', self._in_fd, self._out_fd,
-                                          id=self._id, type=type, call=function)
-        return 0
+                                          id=self._id, type=type, call=function,
+                                          last=last)
+        return IkiWikiProcedureProxy._IKIWIKI_NIL_SENTINEL
 
     def run(self):
         try:
@@ -169,10 +195,13 @@ class IkiWikiProcedureProxy(object):
                 ret = self._xmlrpc_handler.handle_rpc(self._in_fd, self._out_fd)
                 if ret is None:
                     return
-                time.sleep(LOOP_DELAY)
+                time.sleep(IkiWikiProcedureProxy._LOOP_DELAY)
         except Exception, e:
             print >>sys.stderr, 'uncaught exception: %s' % e
             import traceback
             print >>sys.stderr, traceback.format_exc(sys.exc_info()[2])
             import posix
             sys.exit(posix.EX_SOFTWARE)
+
+    class InvalidReturnValue(Exception):
+        pass