mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
plugin: Split the parsing from the request handling in the plugin
This is a preparatory step for the next commit which adds notification parsing as well. Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
committed by
Rusty Russell
parent
9b9f9e4837
commit
dc25c43945
@@ -234,6 +234,66 @@ static void plugin_request_queue(struct plugin *plugin,
|
|||||||
io_wake(plugin);
|
io_wake(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void plugin_notification_handle(struct plugin *plugin,
|
||||||
|
const jsmntok_t *toks)
|
||||||
|
{
|
||||||
|
const jsmntok_t *methtok, *paramstok;
|
||||||
|
|
||||||
|
methtok = json_get_member(plugin->buffer, toks, "method");
|
||||||
|
paramstok = json_get_member(plugin->buffer, toks, "params");
|
||||||
|
|
||||||
|
if (!methtok || !paramstok) {
|
||||||
|
plugin_kill(plugin,
|
||||||
|
"Malformed JSON-RPC notification missing "
|
||||||
|
"\"method\" or \"params\": %.*s",
|
||||||
|
toks->end - toks->start,
|
||||||
|
plugin->buffer + toks->start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dispatch incoming notifications. This is currently limited
|
||||||
|
* to just a few method types, should this ever become
|
||||||
|
* unwieldy we can switch to the AUTODATA construction to
|
||||||
|
* register notification handlers in a variety of places. */
|
||||||
|
if (json_tok_streq(plugin->buffer, methtok, "log")) {
|
||||||
|
plugin_log_handle(plugin, paramstok);
|
||||||
|
} else {
|
||||||
|
plugin_kill(plugin, "Unknown notification method %.*s",
|
||||||
|
json_tok_len(methtok),
|
||||||
|
json_tok_contents(plugin->buffer, methtok));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void plugin_response_handle(struct plugin *plugin,
|
||||||
|
const jsmntok_t *toks,
|
||||||
|
const jsmntok_t *idtok)
|
||||||
|
{
|
||||||
|
struct plugin_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!). */
|
||||||
|
if (!json_to_u64(plugin->buffer, idtok, &id)) {
|
||||||
|
plugin_kill(plugin,
|
||||||
|
"JSON-RPC response \"id\"-field is not a u64");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
request = uintmap_get(&plugin->plugins->pending_requests, id);
|
||||||
|
|
||||||
|
if (!request) {
|
||||||
|
plugin_kill(
|
||||||
|
plugin,
|
||||||
|
"Received a JSON-RPC response for non-existent request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We expect the request->cb to copy if needed */
|
||||||
|
request->cb(request, plugin->buffer, toks, idtok, request->arg);
|
||||||
|
|
||||||
|
uintmap_del(&plugin->plugins->pending_requests, id);
|
||||||
|
tal_free(request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to parse a complete message from the plugin's buffer.
|
* Try to parse a complete message from the plugin's buffer.
|
||||||
*
|
*
|
||||||
@@ -242,11 +302,8 @@ static void plugin_request_queue(struct plugin *plugin,
|
|||||||
*/
|
*/
|
||||||
static bool plugin_read_json_one(struct plugin *plugin)
|
static bool plugin_read_json_one(struct plugin *plugin)
|
||||||
{
|
{
|
||||||
jsmntok_t *toks;
|
|
||||||
bool valid;
|
bool valid;
|
||||||
u64 id;
|
const jsmntok_t *toks, *jrtok, *idtok;
|
||||||
const jsmntok_t *idtok;
|
|
||||||
struct plugin_request *request;
|
|
||||||
|
|
||||||
/* FIXME: This could be done more efficiently by storing the
|
/* FIXME: This could be done more efficiently by storing the
|
||||||
* toks and doing an incremental parse, like lightning-cli
|
* toks and doing an incremental parse, like lightning-cli
|
||||||
@@ -269,32 +326,61 @@ static bool plugin_read_json_one(struct plugin *plugin)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jrtok = json_get_member(plugin->buffer, toks, "jsonrpc");
|
||||||
idtok = json_get_member(plugin->buffer, toks, "id");
|
idtok = json_get_member(plugin->buffer, toks, "id");
|
||||||
|
|
||||||
|
if (!jrtok) {
|
||||||
|
plugin_kill(
|
||||||
|
plugin,
|
||||||
|
"JSON-RPC message does not contain \"jsonrpc\" field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!idtok) {
|
if (!idtok) {
|
||||||
plugin_kill(plugin, "JSON-RPC response does not contain an \"id\"-field");
|
/* A Notification is a Request object without an "id"
|
||||||
return false;
|
* member. A Request object that is a Notification
|
||||||
|
* signifies the Client's lack of interest in the
|
||||||
|
* corresponding Response object, and as such no
|
||||||
|
* Response object needs to be returned to the
|
||||||
|
* client. The Server MUST NOT reply to a
|
||||||
|
* Notification, including those that are within a
|
||||||
|
* batch request.
|
||||||
|
*
|
||||||
|
* https://www.jsonrpc.org/specification#notification
|
||||||
|
*/
|
||||||
|
plugin_notification_handle(plugin, toks);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* When a rpc call is made, the Server MUST reply with
|
||||||
|
* a Response, except for in the case of
|
||||||
|
* Notifications. The Response is expressed as a
|
||||||
|
* single JSON Object, with the following members:
|
||||||
|
*
|
||||||
|
* - jsonrpc: A String specifying the version of the
|
||||||
|
* JSON-RPC protocol. MUST be exactly "2.0".
|
||||||
|
*
|
||||||
|
* - result: This member is REQUIRED on success. This
|
||||||
|
* member MUST NOT exist if there was an error
|
||||||
|
* invoking the method. The value of this member is
|
||||||
|
* determined by the method invoked on the Server.
|
||||||
|
*
|
||||||
|
* - error: This member is REQUIRED on error. This
|
||||||
|
* member MUST NOT exist if there was no error
|
||||||
|
* triggered during invocation.
|
||||||
|
*
|
||||||
|
* - id: This member is REQUIRED. It MUST be the same
|
||||||
|
* as the value of the id member in the Request
|
||||||
|
* Object. If there was an error in detecting the id
|
||||||
|
* in the Request object (e.g. Parse error/Invalid
|
||||||
|
* Request), it MUST be Null. Either the result
|
||||||
|
* member or error member MUST be included, but both
|
||||||
|
* members MUST NOT be included.
|
||||||
|
*
|
||||||
|
* https://www.jsonrpc.org/specification#response_object
|
||||||
|
*/
|
||||||
|
plugin_response_handle(plugin, toks, idtok);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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!). */
|
|
||||||
if (!json_to_u64(plugin->buffer, idtok, &id)) {
|
|
||||||
plugin_kill(plugin, "JSON-RPC response \"id\"-field is not a u64");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
request = uintmap_get(&plugin->plugins->pending_requests, id);
|
|
||||||
|
|
||||||
if (!request) {
|
|
||||||
plugin_kill(plugin, "Received a JSON-RPC response for non-existent request");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We expect the request->cb to copy if needed */
|
|
||||||
request->cb(request, plugin->buffer, toks, idtok, request->arg);
|
|
||||||
tal_free(request);
|
|
||||||
uintmap_del(&plugin->plugins->pending_requests, id);
|
|
||||||
|
|
||||||
/* Move this object out of the buffer */
|
/* Move this object out of the buffer */
|
||||||
memmove(plugin->buffer, plugin->buffer + toks[0].end,
|
memmove(plugin->buffer, plugin->buffer + toks[0].end,
|
||||||
tal_count(plugin->buffer) - toks[0].end);
|
tal_count(plugin->buffer) - toks[0].end);
|
||||||
@@ -314,10 +400,12 @@ static struct io_plan *plugin_read_json(struct io_conn *conn UNUSED,
|
|||||||
/* Read and process all messages from the connection */
|
/* Read and process all messages from the connection */
|
||||||
do {
|
do {
|
||||||
success = plugin_read_json_one(plugin);
|
success = plugin_read_json_one(plugin);
|
||||||
} while (success);
|
|
||||||
|
|
||||||
if (plugin->stop)
|
/* Processing the message from the plugin might have
|
||||||
return io_close(plugin->stdout_conn);
|
* resulted in it stopping, so let's check. */
|
||||||
|
if (plugin->stop)
|
||||||
|
return io_close(plugin->stdout_conn);
|
||||||
|
} while (success);
|
||||||
|
|
||||||
/* Now read more from the connection */
|
/* Now read more from the connection */
|
||||||
return io_read_partial(plugin->stdout_conn,
|
return io_read_partial(plugin->stdout_conn,
|
||||||
|
|||||||
Reference in New Issue
Block a user