diff --git a/lightningd/Makefile b/lightningd/Makefile index d516b5e1d..e491e534e 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -73,6 +73,7 @@ LIGHTNINGD_SRC := \ lightningd/log.c \ lightningd/log_status.c \ lightningd/memdump.c \ + lightningd/notification.c \ lightningd/onchain_control.c \ lightningd/opening_control.c \ lightningd/options.c \ diff --git a/lightningd/notification.c b/lightningd/notification.c new file mode 100644 index 000000000..021c16ab5 --- /dev/null +++ b/lightningd/notification.c @@ -0,0 +1,13 @@ +#include "lightningd/notification.h" +#include + +const char *notification_topics[] = { +}; + +bool notifications_have_topic(const char *topic) +{ + for (size_t i=0; ARRAY_SIZE(notification_topics); i++) + if (streq(topic, notification_topics[i])) + return true; + return false; +} diff --git a/lightningd/notification.h b/lightningd/notification.h new file mode 100644 index 000000000..1cdc1712c --- /dev/null +++ b/lightningd/notification.h @@ -0,0 +1,9 @@ +#ifndef LIGHTNING_LIGHTNINGD_NOTIFICATION_H +#define LIGHTNING_LIGHTNINGD_NOTIFICATION_H +#include "config.h" +#include +#include + +bool notifications_have_topic(const char *topic); + +#endif /* LIGHTNING_LIGHTNINGD_NOTIFICATION_H */ diff --git a/lightningd/plugin.c b/lightningd/plugin.c index 8be9d263d..325269a5b 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,9 @@ struct plugin { /* Timer to add a timeout to some plugin RPC calls. Used to * guarantee that `getmanifest` doesn't block indefinitely. */ const struct oneshot *timeout_timer; + + /* An array of subscribed topics */ + char **subscriptions; }; struct plugin_request { @@ -765,6 +769,46 @@ static bool plugin_rpcmethods_add(struct plugin *plugin, return true; } +static bool plugin_subscriptions_add(struct plugin *plugin, const char *buffer, + const jsmntok_t *resulttok) +{ + const jsmntok_t *subscriptions = + json_get_member(buffer, resulttok, "subscriptions"); + + if (!subscriptions) { + plugin->subscriptions = NULL; + return true; + } + plugin->subscriptions = tal_arr(plugin, char *, 0); + if (subscriptions->type != JSMN_ARRAY) { + plugin_kill(plugin, "\"result.subscriptions\" is not an array"); + return false; + } + + for (int i = 0; i < subscriptions->size; i++) { + char *topic; + const jsmntok_t *s = json_get_arr(subscriptions, i); + if (s->type != JSMN_STRING) { + plugin_kill( + plugin, + "result.subscriptions[%d] is not a string: %s", i, + plugin->buffer); + return false; + } + topic = json_strdup(plugin, plugin->buffer, s); + + if (!notifications_have_topic(topic)) { + plugin_kill( + plugin, + "topic '%s' is not a known notification topic", topic); + return false; + } + + *tal_arr_expand(&plugin->subscriptions) = topic; + } + return true; +} + static void plugin_manifest_timeout(struct plugin *plugin) { log_broken(plugin->log, "The plugin failed to respond to \"getmanifest\" in time, terminating."); @@ -796,8 +840,11 @@ static void plugin_manifest_cb(const struct plugin_request *req, } if (!plugin_opts_add(plugin, buffer, resulttok) - || !plugin_rpcmethods_add(plugin, buffer, resulttok)) - plugin_kill(plugin, "Failed to register options or methods"); + || !plugin_rpcmethods_add(plugin, buffer, resulttok) + || !plugin_subscriptions_add(plugin, buffer, resulttok)) + plugin_kill( + plugin, + "Failed to register options, methods, or subscriptions."); /* Reset timer, it'd kill us otherwise. */ tal_free(plugin->timeout_timer); }