common/json_filter: routine to turn "filter" JSON into a filter.

Since the "struct command" is different from plugins and lightningd, we
need an accessor for this to work (the plugin one is a dummy for now!).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2022-11-04 14:00:48 +10:30
parent 3c75770586
commit 508a170598
6 changed files with 84 additions and 0 deletions

View File

@ -15,6 +15,9 @@ struct command_result *command_fail(struct command *cmd, enum jsonrpc_errcode co
const char *fmt, ...)
PRINTF_FMT(3, 4) WARN_UNUSED_RESULT RETURNS_NONNULL;
/* Caller supplies this too: must provide this to reach into cmd */
struct json_filter **command_filter_ptr(struct command *cmd);
/* Convenient wrapper for "paramname: msg: invalid token '.*%s'" */
static inline struct command_result *
command_fail_badparam(struct command *cmd,

View File

@ -2,6 +2,7 @@
#include <assert.h>
#include <ccan/strmap/strmap.h>
#include <ccan/tal/str/str.h>
#include <common/json_command.h>
#include <common/json_filter.h>
#include <common/utils.h>
@ -190,3 +191,61 @@ const char *json_filter_misused(const tal_t *ctx, const struct json_filter *f)
return tal_steal(ctx, ret);
}
}
/* Recursively populate filter. NULL on success.
*
* Example for listtransactions to include output type, amount_msat,
* {"transactions": [{"outputs": [{"amount_msat": true, "type": true}]}]}
*/
static struct command_result *
build_filter(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
struct json_filter *filter)
{
struct command_result *ret;
size_t i;
const jsmntok_t *t;
struct json_filter *subf;
if (tok->type == JSMN_ARRAY) {
if (tok->size != 1)
return command_fail_badparam(cmd, name, buffer, tok,
"Arrays can only have one element");
subf = json_filter_subarr(filter);
return build_filter(cmd, name, buffer, tok + 1, subf);
}
json_for_each_obj(i, t, tok) {
bool is_true;
const jsmntok_t *val = t + 1;
if (t->type != JSMN_STRING)
return command_fail_badparam(cmd, name, buffer, t,
"expected string key");
subf = json_filter_subobj(filter, buffer + t->start, t->end - t->start);
if (val->type == JSMN_OBJECT || val->type == JSMN_ARRAY) {
ret = build_filter(cmd, name, buffer, val, subf);
if (ret)
return ret;
} else if (!json_to_bool(buffer, val, &is_true) || !is_true)
return command_fail_badparam(cmd, name, buffer, val, "value must be true");
}
return NULL;
}
struct command_result *parse_filter(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok)
{
struct json_filter **filter = command_filter_ptr(cmd);
if (tok->type != JSMN_OBJECT)
return command_fail_badparam(cmd, name, buffer, tok,
"Expected object");
*filter = json_filter_new(cmd);
return build_filter(cmd, name, buffer, tok, *filter);
}

View File

@ -5,8 +5,10 @@
#define LIGHTNING_COMMON_JSON_FILTER_H
#include "config.h"
#include <ccan/tal/tal.h>
#include <common/json_parse_simple.h>
#include <stdbool.h>
struct command;
struct json_filter;
/* Print this? */
@ -31,4 +33,9 @@ struct json_filter *json_filter_subobj(struct json_filter *filter,
size_t fieldnamelen);
struct json_filter *json_filter_subarr(struct json_filter *filter);
/* Turn this "filter" field into cmd->filter and return NULL, or fail command */
struct command_result *parse_filter(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok);
#endif /* LIGHTNING_COMMON_JSON_FILTER_H */

View File

@ -22,6 +22,7 @@
#include <ccan/tal/str/str.h>
#include <common/configdir.h>
#include <common/json_command.h>
#include <common/json_filter.h>
#include <common/json_param.h>
#include <common/memleak.h>
#include <common/timeout.h>
@ -493,6 +494,11 @@ struct command_result *command_fail(struct command *cmd, enum jsonrpc_errcode co
return command_failed(cmd, r);
}
struct json_filter **command_filter_ptr(struct command *cmd)
{
return &cmd->filter;
}
struct command_result *command_still_pending(struct command *cmd)
{
notleak_with_children(cmd);
@ -909,6 +915,7 @@ parse_request(struct json_connection *jcon, const jsmntok_t tok[])
c->id_is_string = (id->type == JSMN_STRING);
c->id = json_strdup(c, jcon->buffer, id);
c->mode = CMD_NORMAL;
c->filter = NULL;
list_add_tail(&jcon->commands, &c->list);
tal_add_destructor(c, destroy_command);

View File

@ -41,6 +41,8 @@ struct command {
enum command_mode mode;
/* Have we started a json stream already? For debugging. */
struct json_stream *json_stream;
/* Optional output field filter. */
struct json_filter *filter;
};
/**

View File

@ -132,6 +132,12 @@ 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;
}
static void ld_send(struct plugin *plugin, struct json_stream *stream)
{
struct jstream *jstr = tal(plugin, struct jstream);