#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`. ` * * - `deserialize_response` takes a `json_stream` and parses it into a * new struct of type `response_type`, * * - `response_cb` is called once the plugin has responded and the * response has been parsed by `deserialize_response`. 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, void *response); void (*serialize_payload)(void *src, struct json_stream *dest); void *(*deserialize_response)(const tal_t *, const char *buffer, const jsmntok_t *toks); /* 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, \ deserialize_response, response_type) \ struct plugin_hook name##_hook_gen = { \ stringify(name), \ typesafe_cb_cast(void (*)(void *, void *), \ void (*)(response_cb_arg_type, response_type), \ response_cb), \ typesafe_cb_cast(void (*)(void *, struct json_stream *), \ void (*)(payload_type, struct json_stream *), \ serialize_payload), \ typesafe_cb_cast( \ void *(*)(const tal_t *, const char *, const jsmntok_t *), \ response_type (*)(const tal_t *, const char *, \ const jsmntok_t *), \ deserialize_response), \ 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); /* 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 */