mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-04 03:03:51 +01:00
common/json_filter: routines for json filtering.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
15112ae87b
commit
3c75770586
6 changed files with 242 additions and 0 deletions
|
@ -48,6 +48,7 @@ COMMON_SRC_NOGEN := \
|
||||||
common/initial_channel.c \
|
common/initial_channel.c \
|
||||||
common/initial_commit_tx.c \
|
common/initial_commit_tx.c \
|
||||||
common/iso4217.c \
|
common/iso4217.c \
|
||||||
|
common/json_filter.c \
|
||||||
common/json_param.c \
|
common/json_param.c \
|
||||||
common/json_parse.c \
|
common/json_parse.c \
|
||||||
common/json_parse_simple.c \
|
common/json_parse_simple.c \
|
||||||
|
|
192
common/json_filter.c
Normal file
192
common/json_filter.c
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ccan/strmap/strmap.h>
|
||||||
|
#include <ccan/tal/str/str.h>
|
||||||
|
#include <common/json_filter.h>
|
||||||
|
#include <common/utils.h>
|
||||||
|
|
||||||
|
/* If they set a filter, we keep it in a tree. */
|
||||||
|
struct json_filter {
|
||||||
|
/* We accumulate errors: if they treat an array as an object */
|
||||||
|
bool misused;
|
||||||
|
|
||||||
|
/* Pointer to parent, or NULL at top. */
|
||||||
|
struct json_filter *parent;
|
||||||
|
|
||||||
|
/* Tracks how far we are into filter, e.g.
|
||||||
|
* if they specify "peers.foo" and we're
|
||||||
|
* in "peer.foo.bar" depth will be 1. */
|
||||||
|
size_t depth;
|
||||||
|
/* If we're in "peer.bar", we're negative */
|
||||||
|
bool positive;
|
||||||
|
|
||||||
|
/* If this is an array */
|
||||||
|
struct json_filter *filter_array;
|
||||||
|
|
||||||
|
/* Otherwise, object: one per keyword */
|
||||||
|
STRMAP(struct json_filter *) filter_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Returns true if we should print this member: this is a shortcut for:
|
||||||
|
*
|
||||||
|
* json_filter_down(filter, member);
|
||||||
|
* ret = json_filter_ok(filter, NULL);
|
||||||
|
* json_filter_up(filter);
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool json_filter_ok(const struct json_filter *filter, const char *member)
|
||||||
|
{
|
||||||
|
if (!filter)
|
||||||
|
return true;
|
||||||
|
if (filter->depth > 0 || !member)
|
||||||
|
return filter->positive;
|
||||||
|
return strmap_get(&filter->filter_map, member) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if we should print this new obj/array */
|
||||||
|
bool json_filter_down(struct json_filter **filter, const char *member)
|
||||||
|
{
|
||||||
|
struct json_filter *child;
|
||||||
|
|
||||||
|
if (!*filter)
|
||||||
|
return true;
|
||||||
|
if ((*filter)->depth > 0) {
|
||||||
|
(*filter)->depth++;
|
||||||
|
return (*filter)->positive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're a leaf node: all true. */
|
||||||
|
if (!(*filter)->filter_array && strmap_empty(&(*filter)->filter_map)) {
|
||||||
|
assert((*filter)->positive);
|
||||||
|
(*filter)->depth = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Array? */
|
||||||
|
if (!member) {
|
||||||
|
if (!(*filter)->filter_array) {
|
||||||
|
(*filter)->misused = true;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
child = (*filter)->filter_array;
|
||||||
|
} else {
|
||||||
|
if ((*filter)->filter_array) {
|
||||||
|
(*filter)->misused = true;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
child = strmap_get(&(*filter)->filter_map, member);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child) {
|
||||||
|
/* Should have been cleaned up last time. */
|
||||||
|
assert(child->depth == 0);
|
||||||
|
/* We only have positive filters natively. */
|
||||||
|
assert(child->positive == true);
|
||||||
|
*filter = child;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OK, this path wasn't specified. */
|
||||||
|
fail:
|
||||||
|
(*filter)->positive = false;
|
||||||
|
(*filter)->depth = 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if we were printing (i.e. close object/arr) */
|
||||||
|
bool json_filter_up(struct json_filter **filter)
|
||||||
|
{
|
||||||
|
if (!*filter)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ((*filter)->depth == 0) {
|
||||||
|
assert((*filter)->parent);
|
||||||
|
assert((*filter)->parent->depth == 0);
|
||||||
|
/* Reset for next time */
|
||||||
|
(*filter)->positive = true;
|
||||||
|
*filter = (*filter)->parent;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*filter)->depth--;
|
||||||
|
return (*filter)->positive;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_json_filter(struct json_filter *filter)
|
||||||
|
{
|
||||||
|
strmap_clear(&filter->filter_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_filter *json_filter_new(const tal_t *ctx)
|
||||||
|
{
|
||||||
|
struct json_filter *filter = tal(ctx, struct json_filter);
|
||||||
|
filter->misused = false;
|
||||||
|
filter->parent = NULL;
|
||||||
|
filter->depth = 0;
|
||||||
|
filter->positive = true;
|
||||||
|
filter->filter_array = NULL;
|
||||||
|
strmap_init(&filter->filter_map);
|
||||||
|
tal_add_destructor(filter, destroy_json_filter);
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_filter *json_filter_subobj(struct json_filter *filter,
|
||||||
|
const char *fieldname,
|
||||||
|
size_t fieldnamelen)
|
||||||
|
{
|
||||||
|
struct json_filter *subfilter = json_filter_new(filter);
|
||||||
|
subfilter->parent = filter;
|
||||||
|
strmap_add(&filter->filter_map,
|
||||||
|
tal_strndup(filter, fieldname, fieldnamelen),
|
||||||
|
subfilter);
|
||||||
|
return subfilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_filter *json_filter_subarr(struct json_filter *filter)
|
||||||
|
{
|
||||||
|
struct json_filter *subfilter = json_filter_new(filter);
|
||||||
|
subfilter->parent = filter;
|
||||||
|
filter->filter_array = subfilter;
|
||||||
|
return subfilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool json_filter_finished(const struct json_filter *filter)
|
||||||
|
{
|
||||||
|
return !filter->parent && filter->depth == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool strmap_filter_misused(const char *member,
|
||||||
|
struct json_filter *filter,
|
||||||
|
const char **ret)
|
||||||
|
{
|
||||||
|
*ret = json_filter_misused(tmpctx, filter);
|
||||||
|
if (*ret == NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* If there was a problem, prepend member and stop iterating */
|
||||||
|
*ret = tal_fmt(tmpctx, ".%s%s", member, *ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *json_filter_misused(const tal_t *ctx, const struct json_filter *f)
|
||||||
|
{
|
||||||
|
const char *ret;
|
||||||
|
|
||||||
|
if (f->misused) {
|
||||||
|
if (f->filter_array)
|
||||||
|
return tal_fmt(ctx, " is an object");
|
||||||
|
else
|
||||||
|
return tal_fmt(ctx, " is an array");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->filter_array) {
|
||||||
|
ret = json_filter_misused(tmpctx, f->filter_array);
|
||||||
|
if (ret)
|
||||||
|
return tal_fmt(ctx, "[]%s", ret);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
ret = NULL;
|
||||||
|
strmap_iterate(&f->filter_map, strmap_filter_misused, &ret);
|
||||||
|
return tal_steal(ctx, ret);
|
||||||
|
}
|
||||||
|
}
|
34
common/json_filter.h
Normal file
34
common/json_filter.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Helpers for filtering JSON results while generating.
|
||||||
|
*/
|
||||||
|
#ifndef LIGHTNING_COMMON_JSON_FILTER_H
|
||||||
|
#define LIGHTNING_COMMON_JSON_FILTER_H
|
||||||
|
#include "config.h"
|
||||||
|
#include <ccan/tal/tal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct json_filter;
|
||||||
|
|
||||||
|
/* Print this? */
|
||||||
|
bool json_filter_ok(const struct json_filter *filter, const char *member);
|
||||||
|
|
||||||
|
/* Returns true if we should print this new obj/array */
|
||||||
|
bool json_filter_down(struct json_filter **filter, const char *member);
|
||||||
|
|
||||||
|
/* Returns true if we were printing (i.e. close object/arr) */
|
||||||
|
bool json_filter_up(struct json_filter **filter);
|
||||||
|
|
||||||
|
/* Is filter finished (i.e. balanced!) */
|
||||||
|
bool json_filter_finished(const struct json_filter *filter);
|
||||||
|
|
||||||
|
/* Has filter been misused? If so, returns explanatory string, otherwise NULL */
|
||||||
|
const char *json_filter_misused(const tal_t *ctx, const struct json_filter *f);
|
||||||
|
|
||||||
|
/* Filter allocation */
|
||||||
|
struct json_filter *json_filter_new(const tal_t *ctx);
|
||||||
|
struct json_filter *json_filter_subobj(struct json_filter *filter,
|
||||||
|
const char *fieldname,
|
||||||
|
size_t fieldnamelen);
|
||||||
|
struct json_filter *json_filter_subarr(struct json_filter *filter);
|
||||||
|
|
||||||
|
#endif /* LIGHTNING_COMMON_JSON_FILTER_H */
|
|
@ -4,6 +4,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <common/channel_type.h>
|
#include <common/channel_type.h>
|
||||||
|
#include <common/json_filter.h>
|
||||||
#include <common/setup.h>
|
#include <common/setup.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -17,6 +18,18 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
||||||
void *record UNNEEDED, struct tlv_field **fields UNNEEDED,
|
void *record UNNEEDED, struct tlv_field **fields UNNEEDED,
|
||||||
const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED)
|
const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED)
|
||||||
{ fprintf(stderr, "fromwire_tlv called!\n"); abort(); }
|
{ fprintf(stderr, "fromwire_tlv called!\n"); abort(); }
|
||||||
|
/* Generated stub for json_filter_down */
|
||||||
|
bool json_filter_down(struct json_filter **filter UNNEEDED, const char *member UNNEEDED)
|
||||||
|
{ fprintf(stderr, "json_filter_down called!\n"); abort(); }
|
||||||
|
/* Generated stub for json_filter_finished */
|
||||||
|
bool json_filter_finished(const struct json_filter *filter UNNEEDED)
|
||||||
|
{ fprintf(stderr, "json_filter_finished called!\n"); abort(); }
|
||||||
|
/* Generated stub for json_filter_ok */
|
||||||
|
bool json_filter_ok(const struct json_filter *filter UNNEEDED, const char *member UNNEEDED)
|
||||||
|
{ fprintf(stderr, "json_filter_ok called!\n"); abort(); }
|
||||||
|
/* Generated stub for json_filter_up */
|
||||||
|
bool json_filter_up(struct json_filter **filter UNNEEDED)
|
||||||
|
{ fprintf(stderr, "json_filter_up called!\n"); abort(); }
|
||||||
/* Generated stub for towire_tlv */
|
/* Generated stub for towire_tlv */
|
||||||
void towire_tlv(u8 **pptr UNNEEDED,
|
void towire_tlv(u8 **pptr UNNEEDED,
|
||||||
const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED,
|
const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "../../common/json_filter.c"
|
||||||
#include "../../common/json_stream.c"
|
#include "../../common/json_stream.c"
|
||||||
#include "../jsonrpc.c"
|
#include "../jsonrpc.c"
|
||||||
#include "../feerate.c"
|
#include "../feerate.c"
|
||||||
|
|
|
@ -140,6 +140,7 @@ PLUGIN_COMMON_OBJS := \
|
||||||
common/json_param.o \
|
common/json_param.o \
|
||||||
common/json_parse.o \
|
common/json_parse.o \
|
||||||
common/json_parse_simple.o \
|
common/json_parse_simple.o \
|
||||||
|
common/json_filter.o \
|
||||||
common/json_stream.o \
|
common/json_stream.o \
|
||||||
common/lease_rates.o \
|
common/lease_rates.o \
|
||||||
common/memleak.o \
|
common/memleak.o \
|
||||||
|
|
Loading…
Add table
Reference in a new issue