diff --git a/contrib/pylightning/lightning/plugin.py b/contrib/pylightning/lightning/plugin.py index 44ec78840..f4e2d05fb 100644 --- a/contrib/pylightning/lightning/plugin.py +++ b/contrib/pylightning/lightning/plugin.py @@ -1,5 +1,6 @@ from collections import OrderedDict from lightning import LightningRpc +from enum import Enum import inspect import json @@ -9,6 +10,11 @@ import sys import traceback +class MethodType(Enum): + RPCMETHOD = 0 + HOOK = 1 + + class Plugin(object): """Controls interactions with lightningd, and bundles functionality. @@ -66,7 +72,7 @@ class Plugin(object): ) # Register the function with the name - self.methods[name] = func + self.methods[name] = (func, MethodType.RPCMETHOD) def add_subscription(self, topic, func): """Add a subscription to our list of subscriptions. @@ -133,6 +139,25 @@ class Plugin(object): return f return decorator + def add_hook(self, name, func): + """Register a hook that is called synchronously by lightningd on events + """ + if name in self.methods: + raise ValueError( + "Method {} was already registered".format(name, self.methods[name]) + ) + self.methods[name] = (func, MethodType.HOOK) + + def hook(self, method_name): + """Decorator to add a plugin hook to the dispatch table. + + Internally uses add_hook. + """ + def decorator(f): + self.add_hook(method_name, f) + return f + return decorator + def _exec_func(self, func, request): params = request['params'] sig = inspect.signature(func) @@ -173,7 +198,7 @@ class Plugin(object): if name not in self.methods: raise ValueError("No method {} found.".format(name)) - func = self.methods[name] + func, _ = self.methods[name] try: result = { @@ -244,7 +269,7 @@ class Plugin(object): # then unstash this and call it. if 'init' in self.methods: self.init = self.methods['init'] - self.methods['init'] = self._init + self.methods['init'] = (self._init, MethodType.RPCMETHOD) partial = "" for l in self.stdin: @@ -258,11 +283,17 @@ class Plugin(object): def _getmanifest(self): methods = [] - for name, func in self.methods.items(): + hooks = [] + for name, entry in self.methods.items(): + func, typ = entry # Skip the builtin ones, they don't get reported if name in ['getmanifest', 'init']: continue + if typ == MethodType.HOOK: + hooks.append(name) + continue + doc = inspect.getdoc(func) doc = re.sub('\n+', ' ', doc) if not doc: @@ -280,6 +311,7 @@ class Plugin(object): 'options': list(self.options.values()), 'rpcmethods': methods, 'subscriptions': list(self.subscriptions.keys()), + 'hooks': hooks, } def _init(self, options, configuration, request): @@ -293,7 +325,7 @@ class Plugin(object): # Swap the registered `init` method handler back in and # re-dispatch if self.init: - self.methods['init'] = self.init + self.methods['init'], _ = self.init self.init = None return self._exec_func(self.methods['init'], request) return None