core-lightning/lightningd/plugin_hook.h
darosior d299420fbe lightningd/plugin_hook: make it possible to unregister a hook
This adds 'plugin_unregister_hook' and 'plugin_unregister_hook_all'
functions to unregister a given hook a plugin registered, or all hooks a
plugin registered for. Since hooks can only be registered once, it's
useful in the case a new plugin is added which would be prefered for
hook registration over an already loaded plugin.
2019-07-28 07:24:04 +00:00

116 lines
5.3 KiB
C

#ifndef LIGHTNING_LIGHTNINGD_PLUGIN_HOOK_H
#define LIGHTNING_LIGHTNINGD_PLUGIN_HOOK_H
#include "config.h"
#include <ccan/autodata/autodata.h>
#include <ccan/tal/tal.h>
#include <ccan/typesafe_cb/typesafe_cb.h>
#include <lightningd/json_stream.h>
#include <lightningd/lightningd.h>
#include <lightningd/plugin.h>
/**
* Plugin hooks are a way for plugins to implement custom behavior and
* reactions to certain things in `lightningd`. `lightningd` will ask
* plugins that have registered a hook for a given event how it'd like
* to proceed. This allows plugins to deviate from the default
* behavior that `lightningd` otherwise implements.
*
* Examples include storing an additional backup of important
* information belonging to the wallet before committing to it, or
* holding an incoming payment that is guaranteed to succeed for some
* time in order to check that the delivery of goods works correctly,
* giving the option of instantly refunding should something go wrong.
*
* Hooks are commonly structured into a number of converter functions
* and a callback. The converter functions convert from an internal
* struct representation of the method arguments to a JSON-object for
* delivery to the plugin, and from a JSON-object to the internal
* representation:
*
* - `serialize_payload` which takes a payload of type `payload_type`
* and serializes it into the given `json_stream`. `
*
* - `response_cb` is called once the plugin has responded (or with
* buffer == NULL if there's no plugin). In addition an arbitrary
* additional argument of type `cb_arg_type` can be passed along
* that may contain any additional context necessary.
*
*
* To make hook invocations easier, each hook registered with
* `REGISTER_PLUGIN_HOOK` provides a `plugin_hook_call_hookname`
* function that performs typechecking at compile time, and makes sure
* that all the provided functions for serialization, deserialization
* and callback have the correct type.
*/
struct plugin_hook {
const char *name;
void (*response_cb)(void *arg, const char *buffer, const jsmntok_t *toks);
void (*serialize_payload)(void *src, struct json_stream *dest);
/* Which plugin has registered this hook? */
struct plugin *plugin;
};
AUTODATA_TYPE(hooks, struct plugin_hook);
/* Do not call this directly, rather use the `plugin_hook_call_name`
* wrappers generated by the `PLUGIN_HOOK_REGISTER` macro.
*/
void plugin_hook_call_(struct lightningd *ld, const struct plugin_hook *hook,
void *payload, void *cb_arg);
/* Create a small facade in from of `plugin_hook_call_` to make sure
* arguments are of the correct type before downcasting them to `void
* *`. Not really necessary, but nice since it also makes sure that
* the method-name is correct for the call.
*/
/* FIXME: Find a way to avoid back-to-back declaration and definition */
#define PLUGIN_HOOK_CALL_DEF(name, payload_type, response_cb_arg_type) \
UNNEEDED static inline void plugin_hook_call_##name( \
struct lightningd *ld, payload_type payload, \
response_cb_arg_type cb_arg) \
{ \
plugin_hook_call_(ld, &name##_hook_gen, (void *)payload, \
(void *)cb_arg); \
}
/* Typechecked registration of a plugin hook. We check that the
* serialize_payload function converts an object of type payload_type
* to a json_stream (.params object in the JSON-RPC request), that the
* deserialize_response function converts from the JSON-RPC response
* json_stream to an object of type response_type and that the
* response_cb function accepts the deserialized response format and
* an arbitrary extra argument used to maintain context.
*/
#define REGISTER_PLUGIN_HOOK(name, response_cb, response_cb_arg_type, \
serialize_payload, payload_type) \
struct plugin_hook name##_hook_gen = { \
stringify(name), \
typesafe_cb_cast(void (*)(void *, const char *, const jsmntok_t *),\
void (*)(response_cb_arg_type, \
const char *, const jsmntok_t *), \
response_cb), \
typesafe_cb_cast(void (*)(void *, struct json_stream *), \
void (*)(payload_type, struct json_stream *), \
serialize_payload), \
NULL, /* .plugin */ \
}; \
AUTODATA(hooks, &name##_hook_gen); \
PLUGIN_HOOK_CALL_DEF(name, payload_type, response_cb_arg_type);
bool plugin_hook_register(struct plugin *plugin, const char *method);
/* Unregister a hook a plugin has registered for */
bool plugin_hook_unregister(struct plugin *plugin, const char *method);
/* Unregister all hooks a plugin has registered for */
void plugin_hook_unregister_all(struct plugin *plugin);
/* Special sync plugin hook for db: changes[] are SQL statements, with optional
* final command appended. */
void plugin_hook_db_sync(struct db *db, const char **changes, const char *final);
#endif /* LIGHTNING_LIGHTNINGD_PLUGIN_HOOK_H */