From cb1156cd328f31e068e09afe0667784ec21a1077 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 9 Nov 2022 14:10:57 +1030 Subject: [PATCH] libplugin: support filters. Signed-off-by: Rusty Russell --- plugins/libplugin.c | 26 +++++++++++++++++++++++--- plugins/libplugin.h | 2 ++ tests/test_misc.py | 4 ++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/plugins/libplugin.c b/plugins/libplugin.c index 8f2f0b4b0..a5527448c 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -132,10 +133,9 @@ struct command_result *command_done(void) return &complete; } -/* Don't ask for _filter, we will crash! */ struct json_filter **command_filter_ptr(struct command *cmd) { - return NULL; + return &cmd->filter; } static void ld_send(struct plugin *plugin, struct json_stream *stream) @@ -261,6 +261,8 @@ struct json_stream *jsonrpc_stream_success(struct command *cmd) struct json_stream *js = jsonrpc_stream_start(cmd); json_object_start(js, "result"); + if (cmd->filter) + json_stream_attach_filter(js, cmd->filter); return js; } @@ -273,6 +275,7 @@ struct json_stream *jsonrpc_stream_fail(struct command *cmd, json_object_start(js, "error"); json_add_primitive_fmt(js, "code", "%d", code); json_add_string(js, "message", err); + cmd->filter = tal_free(cmd->filter); return js; } @@ -302,6 +305,14 @@ static struct command_result *command_complete(struct command *cmd, struct command_result *command_finished(struct command *cmd, struct json_stream *response) { + /* Detach filter before it complains about closing object it never saw */ + if (cmd->filter) { + const char *err = json_stream_detach_filter(tmpctx, response); + if (err) + json_add_string(response, "warning_parameter_filter", + err); + } + /* "result" or "error" object */ json_object_end(response); @@ -1435,11 +1446,12 @@ void plugin_set_memleak_handler(struct plugin *plugin, static void ld_command_handle(struct plugin *plugin, const jsmntok_t *toks) { - const jsmntok_t *methtok, *paramstok; + const jsmntok_t *methtok, *paramstok, *filtertok; struct command *cmd; methtok = json_get_member(plugin->buffer, toks, "method"); paramstok = json_get_member(plugin->buffer, toks, "params"); + filtertok = json_get_member(plugin->buffer, toks, "filter"); if (!methtok || !paramstok) plugin_err(plugin, "Malformed JSON-RPC notification missing " @@ -1450,6 +1462,7 @@ static void ld_command_handle(struct plugin *plugin, cmd = tal(plugin, struct command); cmd->plugin = plugin; cmd->usage_only = false; + cmd->filter = NULL; cmd->methodname = json_strdup(cmd, plugin->buffer, methtok); cmd->id = json_get_id(cmd, plugin->buffer, toks); @@ -1510,6 +1523,13 @@ static void ld_command_handle(struct plugin *plugin, } } + if (filtertok) { + /* On error, this fails cmd */ + if (parse_filter(cmd, "filter", plugin->buffer, filtertok) + != NULL) + return; + } + for (size_t i = 0; i < plugin->num_commands; i++) { if (streq(cmd->methodname, plugin->commands[i].name)) { plugin->commands[i].handle(cmd, diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 3e9b0f295..1db991c28 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -55,6 +55,8 @@ struct command { const char *methodname; bool usage_only; struct plugin *plugin; + /* Optional output field filter. */ + struct json_filter *filter; }; /* Create an array of these, one for each command you support. */ diff --git a/tests/test_misc.py b/tests/test_misc.py index 062a6280f..e28a62379 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -2854,10 +2854,10 @@ def test_field_filter(node_factory, chainparams): "fallbacks": {'type': True}}) assert dec['warning_parameter_filter'] == '.fallbacks is an array' - # Plugins ignore filters! + # C plugins implement filters! res = l1.rpc.call('decode', {'string': inv['bolt11']}, filter={"currency": True}) - assert 'type' in res + assert res == {"currency": chainparams['bip173_prefix']} def test_checkmessage_pubkey_not_found(node_factory):