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.
This commit is contained in:
Christian Decker 2018-12-21 14:02:34 +01:00 committed by Rusty Russell
parent 1a952667ee
commit ff897f8788
3 changed files with 87 additions and 67 deletions

View File

@ -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)
{

View File

@ -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 */

View File

@ -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)