aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authormartin f. krafft <madduck@madduck.net>2008-03-21 19:12:12 +0100
committerJoey Hess <joey@kodama.kitenet.net>2008-03-21 15:07:10 -0400
commite3624de63c799427fbd95fa5bbef9462f95912c6 (patch)
tree532425e6ec54e0d039091582f44782081353f8ef /plugins
parent99fce0af0d4e99bc81ef7847bfbe77662763e805 (diff)
downloadikiwiki-e3624de63c799427fbd95fa5bbef9462f95912c6.tar
ikiwiki-e3624de63c799427fbd95fa5bbef9462f95912c6.tar.gz
Allow external plugins to return no value
Instead of using the XML-RPC v2 extension <nil/>, which Perl's XML::RPC::Parser does not (yet) support (Joey's patch is pending), we agreed on a sentinel: {'null':''}, that is, a hash with a single key "null" pointing to the empty string. The Python proxy automatically converts None appropriately and raises an exception if a hook function should, by weird coincidence, attempt to return {'null':''}. Signed-off-by: martin f. krafft <madduck@madduck.net>
Diffstat (limited to 'plugins')
-rw-r--r--plugins/proxy.py58
-rwxr-xr-xplugins/pythondemo6
2 files changed, 45 insertions, 19 deletions
diff --git a/plugins/proxy.py b/plugins/proxy.py
index 6f9b1f852..9042f389d 100644
--- a/plugins/proxy.py
+++ b/plugins/proxy.py
@@ -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,9 +160,25 @@ 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):
+ if name is None:
+ name = function.__name__
+ self._hooks.append((type, name))
+
+ 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...')
@@ -161,7 +186,7 @@ class IkiWikiProcedureProxy(object):
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
+ return IkiWikiProcedureProxy._IKIWIKI_NIL_SENTINEL
def run(self):
try:
@@ -169,10 +194,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
diff --git a/plugins/pythondemo b/plugins/pythondemo
index 6d632d524..5038c603b 100755
--- a/plugins/pythondemo
+++ b/plugins/pythondemo
@@ -151,7 +151,7 @@ def htmlize_demo(*args):
kwargs = _arglist_to_dict(args)
debug("hook `htmlize' called with arguments %s" % kwargs)
return kwargs['content']
-proxy.hook('htmlize', htmlize_demo)
+#proxy.hook('htmlize', htmlize_demo)
def pagetemplate_demo(*args):
# Templates are filled out for many different things in ikiwiki, like
@@ -178,12 +178,10 @@ def templatefile_demo(*args):
# change the default ("page.tmpl"). Template files are looked for in
# /usr/share/ikiwiki/templates by default.
#
- # TODO: we cannot really pass undef/None via xml-rpc, so what to do?
kwargs = _arglist_to_dict(args)
debug("hook `templatefile' called with arguments %s" % kwargs)
- raise NotImplementedError
return None
-#proxy.hook('templatefile', templatefile_demo)
+proxy.hook('templatefile', templatefile_demo)
def sanitize_demo(*args):
# Use this to implement html sanitization or anything else that needs to