#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 `cb_arg_type` * and serializes it into the given `json_stream`. ` * - `deserialize_cb` is called for each plugin, if it returns true the * next one is called, otherwise the cb_arg_type argument is free. * - If all `deserialize_cb` return true, `final_cb` is called. It must free * or otherwise take ownership of the cb_arg_type argument. * * To make hook invocations easier, each 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; /* Returns false if we should stop iterating (and free arg). */ bool (*deserialize_cb)(void *arg, const char *buffer, const jsmntok_t *toks); void (*final_cb)(void *arg); /* To send the payload to the plugin */ void (*serialize_payload)(void *src, struct json_stream *dest, struct plugin *plugin); /* Which plugins have registered this hook? This is a `tal_arr` * initialized at creation. */ struct hook_instance **hooks; }; 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. * * Returns true if callback called immediately, otherwise false if it's * still waiting on a plugin response. */ bool plugin_hook_call_(struct lightningd *ld, const struct plugin_hook *hook, tal_t *cb_arg STEALS); /* Generic deserialize_cb: returns true iff 'result': 'continue' */ bool plugin_hook_continue(void *arg, const char *buffer, const jsmntok_t *toks); /* 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, cb_arg_type) \ UNNEEDED static inline bool plugin_hook_call_##name( \ struct lightningd *ld, cb_arg_type cb_arg STEALS) \ { \ return plugin_hook_call_(ld, &name##_hook_gen, 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, deserialize_cb, final_cb, \ serialize_payload, cb_arg_type) \ struct plugin_hook name##_hook_gen = { \ stringify(name), \ typesafe_cb_cast( \ bool (*)(void *, const char *, const jsmntok_t *), \ bool (*)(cb_arg_type, const char *, const jsmntok_t *), \ deserialize_cb), \ typesafe_cb_cast(void (*)(void *STEALS), \ void (*)(cb_arg_type STEALS), final_cb), \ typesafe_cb_cast( \ void (*)(void *, struct json_stream *, struct plugin *), \ void (*)(cb_arg_type, struct json_stream *, struct plugin *), \ serialize_payload), \ NULL, /* .plugins */ \ }; \ AUTODATA(hooks, &name##_hook_gen); \ PLUGIN_HOOK_CALL_DEF(name, cb_arg_type) struct plugin_hook *plugin_hook_register(struct plugin *plugin, const char *method); /* Special sync plugin hook for db. */ void plugin_hook_db_sync(struct db *db); /* Add dependencies for this hook. */ void plugin_hook_add_deps(struct plugin_hook *hook, struct plugin *plugin, const char *buffer, const jsmntok_t *before, const jsmntok_t *after); /* Returns array of plugins which cannot be ordered (empty on success) */ struct plugin **plugin_hooks_make_ordered(const tal_t *ctx); #endif /* LIGHTNING_LIGHTNINGD_PLUGIN_HOOK_H */