core-lightning/lightningd/plugin_hook.h
Rusty Russell a314bc62fc lightningd: remove deserialize step for plugin hooks.
This seems like overkill, at least for now.  Handling the JSON
inline is clearer, for the existing examples at least.

We also remove the dummy hook, rather than fix it.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2019-04-23 15:26:42 +02:00

110 lines
5.0 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);
/* 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 */