From 7de4c40b77a0ce6de2e80be9c3871e992f45977f Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Mon, 19 Nov 2018 16:06:45 +0100 Subject: [PATCH] plugin: Add plugin rpcmethods to the JSON-RPC interface Signed-off-by: Christian Decker <@cdecker> --- lightningd/plugin.c | 106 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/lightningd/plugin.c b/lightningd/plugin.c index db37ad7ff..a1c3a144a 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -383,6 +384,107 @@ static bool plugin_opts_add(const struct plugin_request *req) return true; } +static void plugin_rpcmethod_destroy(struct json_command *cmd) +{ +} + +static void plugin_rpcmethod_dispatch(struct command *cmd, const char *buffer, + const jsmntok_t *params) +{ + // FIXME: We could avoid parsing the buffer again if we were + // to also pass in the method name. + cmd->usage = "[params]"; + command_still_pending(cmd); +} + +static bool plugin_rpcmethod_add(struct plugin *plugin, const char *buffer, + const jsmntok_t *meth) +{ + const jsmntok_t *nametok, *desctok, *longdesctok; + struct json_command *cmd; + + nametok = json_get_member(buffer, meth, "name"); + desctok = json_get_member(buffer, meth, "description"); + longdesctok = json_get_member(buffer, meth, "long_description"); + + if (!nametok || nametok->type != JSMN_STRING) { + plugin_kill( + plugin, + tal_fmt(plugin, + "rpcmethod does not have a string \"name\": %.*s", + meth->end - meth->start, buffer + meth->start)); + return false; + } + + if (!desctok || desctok->type != JSMN_STRING) { + plugin_kill(plugin, tal_fmt(plugin, + "rpcmethod does not have a string " + "\"description\": %.*s", + meth->end - meth->start, + buffer + meth->start)); + return false; + } + + if (longdesctok && longdesctok->type != JSMN_STRING) { + plugin_kill( + plugin, + tal_fmt(plugin, + "\"long_description\" is not a string: %.*s", + meth->end - meth->start, buffer + meth->start)); + return false; + } + + cmd = notleak(tal(plugin, struct json_command)); + cmd->name = tal_strndup(cmd, buffer + nametok->start, + nametok->end - nametok->start); + cmd->description = tal_strndup(cmd, buffer + desctok->start, + desctok->end - desctok->start); + if (longdesctok) + cmd->verbose = + tal_strndup(cmd, buffer + longdesctok->start, + longdesctok->end - longdesctok->start); + else + cmd->verbose = cmd->description; + + cmd->deprecated = false; + cmd->dispatch = plugin_rpcmethod_dispatch; + tal_add_destructor(cmd, plugin_rpcmethod_destroy); + if (!jsonrpc_command_add(plugin->plugins->rpc, cmd)) { + log_broken(plugin->log, + "Could not register method \"%s\", a method with " + "that name is already registered", + cmd->name); + return false; + } + return true; +} + +static bool plugin_rpcmethods_add(const struct plugin_request *req) +{ + const char *buffer = req->plugin->buffer; + const jsmntok_t *cur, *methods; + + /* This is the parent for all elements in the "options" array */ + int methpos; + + methods = + json_get_member(req->plugin->buffer, req->resulttok, "rpcmethods"); + if (!methods) + return false; + + methpos = methods - req->toks; + + if (methods->type != JSMN_ARRAY) { + plugin_kill(req->plugin, "\"result.rpcmethods\" is not an array"); + return false; + } + + for (cur = methods + 1; cur->parent == methpos; cur = json_next(cur)) + if (!plugin_rpcmethod_add(req->plugin, buffer, cur)) + return false; + return true; +} + /** * Callback for the plugin_manifest request. */ @@ -400,8 +502,8 @@ static void plugin_manifest_cb(const struct plugin_request *req, struct plugin * return; } - if (!plugin_opts_add(req)) - return; + if (!plugin_opts_add(req) || !plugin_rpcmethods_add(req)) + plugin_kill(plugin, "Failed to register options or methods"); } void plugins_init(struct plugins *plugins)