#ifndef LIGHTNING_LIGHTNINGD_PLUGIN_HOOK_H #define LIGHTNING_LIGHTNINGD_PLUGIN_HOOK_H #include "config.h" #include #include #include #include #include #include /** * 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. */ enum plugin_hook_type { PLUGIN_HOOK_SINGLE, PLUGIN_HOOK_CHAIN, }; struct plugin_hook { const char *name; /* Which type of plugin is this? It'll determine how many plugins can * register this hook, and how the hooks are called. */ enum plugin_hook_type type; void (*response_cb)(void *arg, const char *buffer, const jsmntok_t *toks); void (*serialize_payload)(void *src, struct json_stream *dest); /* Which plugins have registered this hook? This is a `tal_arr` * initialized at creation. */ struct plugin **plugins; }; 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, type, response_cb, response_cb_arg_type, \ serialize_payload, payload_type) \ struct plugin_hook name##_hook_gen = { \ stringify(name), \ type, \ 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, /* .plugins */ \ }; \ 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. */ void plugin_hook_db_sync(struct db *db); #endif /* LIGHTNING_LIGHTNINGD_PLUGIN_HOOK_H */