From ff897f87880dc186321fb092e6603da6990cce44 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Fri, 21 Dec 2018 14:02:34 +0100 Subject: [PATCH] jsonrpc: Generalize plugin_request to jsonrpc_request There is very little that is plugin specific in the jsonrpc_request so this just extracts the common parts so we can reuse them outside of the plugin compilation unit as well. --- lightningd/jsonrpc.c | 36 +++++++++++++++++ lightningd/jsonrpc.h | 26 +++++++++++++ lightningd/plugin.c | 92 ++++++++++++-------------------------------- 3 files changed, 87 insertions(+), 67 deletions(-) diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c index 927bbb5d4..7e8e8b3fa 100644 --- a/lightningd/jsonrpc.c +++ b/lightningd/jsonrpc.c @@ -1027,6 +1027,42 @@ void jsonrpc_notification_end(struct jsonrpc_notification *n) json_stream_append(n->stream, "\n\n"); } +struct jsonrpc_request *jsonrpc_request_start_( + const tal_t *ctx, const char *method, + void (*response_cb)(const char *buffer, const jsmntok_t *toks, + const jsmntok_t *idtok, void *), + void *response_cb_arg) +{ + struct jsonrpc_request *r = tal(ctx, struct jsonrpc_request); + static u64 next_request_id = 0; + r->id = next_request_id++; + r->response_cb = response_cb; + r->response_cb_arg = response_cb_arg; + r->method = NULL; + r->stream = new_json_stream(r, NULL); + + /* If no method is specified we don't prefill the JSON-RPC + * request with the header. This serves as an escape hatch to + * get a raw request, but get a valid request-id assigned. */ + if (method != NULL) { + r->method = tal_strdup(r, method); + json_object_start(r->stream, NULL); + json_add_string(r->stream, "jsonrpc", "2.0"); + json_add_u64(r->stream, "id", r->id); + json_add_string(r->stream, "method", method); + json_object_start(r->stream, "params"); + } + + return r; +} + +void jsonrpc_request_end(struct jsonrpc_request *r) +{ + json_object_end(r->stream); /* closes '.params' */ + json_object_end(r->stream); /* closes '.' */ + json_stream_append(r->stream, "\n\n"); +} + /* We add this destructor as a canary to detect cmd failing. */ static void destroy_command_canary(struct command *cmd, bool *failed) { diff --git a/lightningd/jsonrpc.h b/lightningd/jsonrpc.h index f923a1add..b248d54bb 100644 --- a/lightningd/jsonrpc.h +++ b/lightningd/jsonrpc.h @@ -66,6 +66,15 @@ struct jsonrpc_notification { struct json_stream *stream; }; +struct jsonrpc_request { + u64 id; + const char *method; + struct json_stream *stream; + void (*response_cb)(const char *buffer, const jsmntok_t *toks, + const jsmntok_t *idtok, void *); + void *response_cb_arg; +}; + /** * json_stream_success - start streaming a successful json result. * @cmd: the command we're running. @@ -183,5 +192,22 @@ struct jsonrpc_notification *jsonrpc_notification_start(const tal_t *ctx, const */ void jsonrpc_notification_end(struct jsonrpc_notification *n); +#define jsonrpc_request_start(ctx, method, response_cb, response_cb_arg) \ + jsonrpc_request_start_( \ + (ctx), (method), \ + typesafe_cb_preargs(void, void *, (response_cb), (response_cb_arg), \ + const char *buffer, \ + const jsmntok_t *toks, \ + const jsmntok_t *idtok), \ + (response_cb_arg)) + +struct jsonrpc_request *jsonrpc_request_start_( + const tal_t *ctx, const char *method, + void (*response_cb)(const char *buffer, const jsmntok_t *toks, + const jsmntok_t *idtok, void *), + void *response_cb_arg); + +void jsonrpc_request_end(struct jsonrpc_request *request); + AUTODATA_TYPE(json_command, struct json_command); #endif /* LIGHTNING_LIGHTNINGD_JSONRPC_H */ diff --git a/lightningd/plugin.c b/lightningd/plugin.c index dc371fe83..ce792d5de 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -66,24 +66,12 @@ struct plugin { char **subscriptions; }; -struct plugin_request { - u64 id; - struct json_stream *stream; - - /* The response handler to be called when plugin gives us an object. */ - void (*cb)(const char *buffer, - const jsmntok_t *toks, - const jsmntok_t *idtok, - void *); - void *arg; -}; - struct plugins { struct list_head plugins; size_t pending_manifests; /* Currently pending requests by their request ID */ - UINTMAP(struct plugin_request *) pending_requests; + UINTMAP(struct jsonrpc_request *) pending_requests; struct log *log; struct log_book *log_book; @@ -192,39 +180,29 @@ static void PRINTF_FMT(2,3) plugin_kill(struct plugin *plugin, char *fmt, ...) * * The caller needs to add the request to req->stream. */ -static struct plugin_request * +static struct jsonrpc_request * plugin_request_new_(struct plugin *plugin, + const char *method, void (*cb)(const char *buffer, const jsmntok_t *toks, const jsmntok_t *idtok, void *), void *arg) { - static u64 next_request_id = 0; - struct plugin_request *req = tal(plugin, struct plugin_request); - - req->id = next_request_id++; - req->cb = cb; - req->arg = arg; - - /* We will not concurrently drain, if we do we must set the - * writer to non-NULL */ - req->stream = new_json_stream(req, NULL); + struct jsonrpc_request *req = jsonrpc_request_start(plugin, method, cb, arg); /* Add to map so we can find it later when routing the response */ uintmap_add(&plugin->plugins->pending_requests, req->id, req); return req; } - -#define plugin_request_new(plugin, cb, arg) \ - plugin_request_new_( \ - (plugin), \ - typesafe_cb_preargs(void, void *, (cb), (arg), \ - const char *buffer, \ - const jsmntok_t *toks, \ - const jsmntok_t *idtok), \ - (arg)) - +#define plugin_request_new(plugin, method, response_cb, response_cb_arg) \ + plugin_request_new_((plugin), (method), \ + typesafe_cb_preargs(void, void *, (response_cb), \ + (response_cb_arg), \ + const char *buffer, \ + const jsmntok_t *toks, \ + const jsmntok_t *idtok), \ + (response_cb_arg)) /** * Send a JSON-RPC message (request or notification) to the plugin. */ @@ -303,7 +281,7 @@ static void plugin_response_handle(struct plugin *plugin, const jsmntok_t *toks, const jsmntok_t *idtok) { - struct plugin_request *request; + struct jsonrpc_request *request; u64 id; /* We only send u64 ids, so if this fails it's a critical error (note * that this also works if id is inside a JSON string!). */ @@ -323,7 +301,7 @@ static void plugin_response_handle(struct plugin *plugin, } /* We expect the request->cb to copy if needed */ - request->cb(plugin->buffer, toks, idtok, request->arg); + request->response_cb(plugin->buffer, toks, idtok, request->response_cb_arg); uintmap_del(&plugin->plugins->pending_requests, id); tal_free(request); @@ -666,7 +644,7 @@ static struct command_result *plugin_rpcmethod_dispatch(struct command *cmd, { const jsmntok_t *idtok; struct plugin *plugin; - struct plugin_request *req; + struct jsonrpc_request *req; char id[STR_MAX_CHARS(u64)]; if (cmd->mode == CMD_USAGE || cmd->mode == CMD_CHECK) { @@ -681,7 +659,7 @@ static struct command_result *plugin_rpcmethod_dispatch(struct command *cmd, idtok = json_get_member(buffer, toks, "id"); assert(idtok != NULL); - req = plugin_request_new(plugin, plugin_rpcmethod_cb, cmd); + req = plugin_request_new(plugin, NULL, plugin_rpcmethod_cb, cmd); snprintf(id, ARRAY_SIZE(id), "%"PRIu64, req->id); json_stream_forward_change_id(req->stream, buffer, toks, idtok, id); @@ -920,30 +898,13 @@ void clear_plugins(struct plugins *plugins) tal_free(p); } -/* For our own "getmanifest" and "init" requests: starts params[] */ -static void start_simple_request(struct plugin_request *req, const char *reqname) -{ - json_object_start(req->stream, NULL); - json_add_string(req->stream, "jsonrpc", "2.0"); - json_add_string(req->stream, "method", reqname); - json_add_u64(req->stream, "id", req->id); -} - -static void end_simple_request(struct plugin *plugin, struct plugin_request *req) -{ - json_object_end(req->stream); - json_stream_append(req->stream, "\n\n"); - plugin_send(plugin, req->stream); - req->stream = NULL; -} - void plugins_init(struct plugins *plugins, const char *dev_plugin_debug) { struct plugin *p; char **cmd; int stdin, stdout; struct timer *expired; - struct plugin_request *req; + struct jsonrpc_request *req; plugins->pending_manifests = 0; uintmap_init(&plugins->pending_requests); @@ -969,11 +930,10 @@ void plugins_init(struct plugins *plugins, const char *dev_plugin_debug) * write-only on p->stdout */ io_new_conn(p, stdout, plugin_stdout_conn_init, p); io_new_conn(p, stdin, plugin_stdin_conn_init, p); - req = plugin_request_new(p, plugin_manifest_cb, p); - start_simple_request(req, "getmanifest"); - json_array_start(req->stream, "params"); - json_array_end(req->stream); - end_simple_request(p, req); + req = plugin_request_new(p, "getmanifest", plugin_manifest_cb, p); + jsonrpc_request_end(req); + plugin_send(p, req->stream); + plugins->pending_manifests++; /* Don't timeout if they're running a debugger. */ if (debug) @@ -1011,13 +971,11 @@ static void plugin_config(struct plugin *plugin) { struct plugin_opt *opt; const char *name; - struct plugin_request *req; + struct jsonrpc_request *req; struct lightningd *ld = plugin->plugins->ld; /* No writer since we don't flush concurrently. */ - req = plugin_request_new(plugin, plugin_config_cb, plugin); - start_simple_request(req, "init"); - json_object_start(req->stream, "params"); /* start of .params */ + req = plugin_request_new(plugin, "init", plugin_config_cb, plugin); /* Add .params.options */ json_object_start(req->stream, "options"); @@ -1034,8 +992,8 @@ static void plugin_config(struct plugin *plugin) json_add_string(req->stream, "rpc-file", ld->rpc_filename); json_object_end(req->stream); - json_object_end(req->stream); /* end of .params */ - end_simple_request(plugin, req); + jsonrpc_request_end(req); + plugin_send(plugin, req->stream); } void plugins_config(struct plugins *plugins)