mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
jsonrpc: probe sites for usage information once, at start.
We store it in a strmap. This means we call the jsonrpc handler earlier, so all callers need to call param() before they do anything else; only json_listaddrs and json_help needed fixing. Plugins still use '[usage]' for now. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
e5c80f63d7
commit
5770e0c700
6 changed files with 85 additions and 23 deletions
|
@ -21,6 +21,7 @@
|
|||
#include <ccan/err/err.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <ccan/strmap/strmap.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/bech32.h>
|
||||
#include <common/json_command.h>
|
||||
|
@ -38,6 +39,7 @@
|
|||
#include <lightningd/json.h>
|
||||
#include <lightningd/jsonrpc.h>
|
||||
#include <lightningd/log.h>
|
||||
#include <lightningd/memdump.h>
|
||||
#include <lightningd/options.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -106,6 +108,10 @@ struct jsonrpc {
|
|||
struct io_listener *rpc_listener;
|
||||
struct json_command **commands;
|
||||
struct log *log;
|
||||
|
||||
/* Map from json command names to usage strings: we don't put this inside
|
||||
* struct json_command as it's good practice to have those const. */
|
||||
STRMAP(const char *) usagemap;
|
||||
};
|
||||
|
||||
/* The command itself usually owns the stream, because jcon may get closed.
|
||||
|
@ -304,10 +310,11 @@ static void json_add_help_command(struct command *cmd,
|
|||
struct json_command *json_command)
|
||||
{
|
||||
char *usage;
|
||||
cmd->mode = CMD_USAGE;
|
||||
json_command->dispatch(cmd, NULL, NULL, NULL);
|
||||
usage = tal_fmt(cmd, "%s %s", json_command->name, cmd->usage);
|
||||
|
||||
usage = tal_fmt(cmd, "%s %s",
|
||||
json_command->name,
|
||||
strmap_get(&cmd->ld->jsonrpc->usagemap,
|
||||
json_command->name));
|
||||
json_object_start(response, NULL);
|
||||
|
||||
json_add_string(response, "command", usage);
|
||||
|
@ -347,7 +354,7 @@ static struct command_result *json_help(struct command *cmd,
|
|||
{
|
||||
struct json_stream *response;
|
||||
const jsmntok_t *cmdtok;
|
||||
struct json_command **commands = cmd->ld->jsonrpc->commands;
|
||||
struct json_command **commands;
|
||||
const struct json_command *one_cmd;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
|
@ -355,6 +362,7 @@ static struct command_result *json_help(struct command *cmd,
|
|||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
commands = cmd->ld->jsonrpc->commands;
|
||||
if (cmdtok) {
|
||||
one_cmd = find_command(commands, buffer, cmdtok);
|
||||
if (!one_cmd)
|
||||
|
@ -771,6 +779,7 @@ static struct io_plan *incoming_jcon_connected(struct io_conn *conn,
|
|||
|
||||
static void destroy_json_command(struct json_command *command, struct jsonrpc *rpc)
|
||||
{
|
||||
strmap_del(&rpc->usagemap, command->name, NULL);
|
||||
for (size_t i = 0; i < tal_count(rpc->commands); i++) {
|
||||
if (rpc->commands[i] == command) {
|
||||
tal_arr_remove(&rpc->commands, i);
|
||||
|
@ -780,9 +789,7 @@ static void destroy_json_command(struct json_command *command, struct jsonrpc *r
|
|||
abort();
|
||||
}
|
||||
|
||||
/* For built-in ones, they're not tal objects, so no destructor */
|
||||
static bool jsonrpc_command_add_perm(struct jsonrpc *rpc,
|
||||
struct json_command *command)
|
||||
static bool command_add(struct jsonrpc *rpc, struct json_command *command)
|
||||
{
|
||||
size_t count = tal_count(rpc->commands);
|
||||
|
||||
|
@ -795,23 +802,54 @@ static bool jsonrpc_command_add_perm(struct jsonrpc *rpc,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command)
|
||||
/* Built-in commands get called to construct usage string via param() */
|
||||
static void setup_command_usage(struct lightningd *ld,
|
||||
struct json_command *command)
|
||||
{
|
||||
if (!jsonrpc_command_add_perm(rpc, command))
|
||||
const struct command_result *res;
|
||||
struct command *dummy;
|
||||
|
||||
/* Call it with minimal cmd, to fill out usagemap */
|
||||
dummy = tal(tmpctx, struct command);
|
||||
dummy->mode = CMD_USAGE;
|
||||
dummy->ld = ld;
|
||||
dummy->json_cmd = command;
|
||||
res = command->dispatch(dummy, NULL, NULL, NULL);
|
||||
assert(res == ¶m_failed);
|
||||
assert(strmap_get(&ld->jsonrpc->usagemap, command->name));
|
||||
}
|
||||
|
||||
bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command,
|
||||
const char *usage TAKES)
|
||||
{
|
||||
if (!command_add(rpc, command))
|
||||
return false;
|
||||
usage = tal_strdup(command, usage);
|
||||
strmap_add(&rpc->usagemap, command->name, usage);
|
||||
tal_add_destructor2(command, destroy_json_command, rpc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool jsonrpc_command_add_perm(struct lightningd *ld,
|
||||
struct jsonrpc *rpc,
|
||||
struct json_command *command)
|
||||
{
|
||||
if (!command_add(rpc, command))
|
||||
return false;
|
||||
setup_command_usage(ld, command);
|
||||
return true;
|
||||
}
|
||||
|
||||
void jsonrpc_setup(struct lightningd *ld)
|
||||
{
|
||||
struct json_command **commands = get_cmdlist();
|
||||
|
||||
ld->jsonrpc = tal(ld, struct jsonrpc);
|
||||
strmap_init(&ld->jsonrpc->usagemap);
|
||||
ld->jsonrpc->commands = tal_arr(ld->jsonrpc, struct json_command *, 0);
|
||||
ld->jsonrpc->log = new_log(ld->jsonrpc, ld->log_book, "jsonrpc");
|
||||
for (size_t i=0; i<num_cmdlist; i++) {
|
||||
if (!jsonrpc_command_add_perm(ld->jsonrpc, commands[i]))
|
||||
if (!jsonrpc_command_add_perm(ld, ld->jsonrpc, commands[i]))
|
||||
fatal("Cannot add duplicate command %s",
|
||||
commands[i]->name);
|
||||
}
|
||||
|
@ -823,9 +861,11 @@ bool command_usage_only(const struct command *cmd)
|
|||
return cmd->mode == CMD_USAGE;
|
||||
}
|
||||
|
||||
void command_set_usage(struct command *cmd, const char *usage)
|
||||
void command_set_usage(struct command *cmd, const char *usage TAKES)
|
||||
{
|
||||
cmd->usage = usage;
|
||||
usage = tal_strdup(cmd->ld, usage);
|
||||
if (!strmap_add(&cmd->ld->jsonrpc->usagemap, cmd->json_cmd->name, usage))
|
||||
fatal("Two usages for command %s?", cmd->json_cmd->name);
|
||||
}
|
||||
|
||||
bool command_check_only(const struct command *cmd)
|
||||
|
@ -1141,3 +1181,11 @@ static const struct json_command check_command = {
|
|||
};
|
||||
|
||||
AUTODATA(json_command, &check_command);
|
||||
|
||||
#if DEVELOPER
|
||||
void jsonrpc_remove_memleak(struct htable *memtable,
|
||||
const struct jsonrpc *jsonrpc)
|
||||
{
|
||||
memleak_remove_strmap(memtable, &jsonrpc->usagemap);
|
||||
}
|
||||
#endif /* DEVELOPER */
|
||||
|
|
|
@ -37,8 +37,6 @@ struct command {
|
|||
bool pending;
|
||||
/* Tell param() how to process the command */
|
||||
enum command_mode mode;
|
||||
/* This is created if mode is CMD_USAGE */
|
||||
const char *usage;
|
||||
/* Have we started a json stream already? For debugging. */
|
||||
bool have_json_stream;
|
||||
};
|
||||
|
@ -175,7 +173,8 @@ void jsonrpc_listen(struct jsonrpc *rpc, struct lightningd *ld);
|
|||
*
|
||||
* Free @command to remove it.
|
||||
*/
|
||||
bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command);
|
||||
bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command,
|
||||
const char *usage TAKES);
|
||||
|
||||
/**
|
||||
* Begin a JSON-RPC notification with the specified topic.
|
||||
|
@ -208,4 +207,13 @@ struct jsonrpc_request *jsonrpc_request_start_(
|
|||
void jsonrpc_request_end(struct jsonrpc_request *request);
|
||||
|
||||
AUTODATA_TYPE(json_command, struct json_command);
|
||||
|
||||
#if DEVELOPER
|
||||
struct htable;
|
||||
struct jsonrpc;
|
||||
|
||||
void jsonrpc_remove_memleak(struct htable *memtable,
|
||||
const struct jsonrpc *jsonrpc);
|
||||
#endif /* DEVELOPER */
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_JSONRPC_H */
|
||||
|
|
|
@ -154,6 +154,7 @@ static void scan_mem(struct command *cmd,
|
|||
memleak_remove_htable(memtable, &ld->topology->txowatches.raw);
|
||||
memleak_remove_htable(memtable, &ld->htlcs_in.raw);
|
||||
memleak_remove_htable(memtable, &ld->htlcs_out.raw);
|
||||
jsonrpc_remove_memleak(memtable, ld->jsonrpc);
|
||||
|
||||
/* Now delete ld and those which it has pointers to. */
|
||||
memleak_remove_referenced(memtable, ld);
|
||||
|
|
|
@ -610,11 +610,8 @@ static struct command_result *plugin_rpcmethod_dispatch(struct command *cmd,
|
|||
struct jsonrpc_request *req;
|
||||
char id[STR_MAX_CHARS(u64)];
|
||||
|
||||
if (cmd->mode == CMD_USAGE || cmd->mode == CMD_CHECK) {
|
||||
/* FIXME! */
|
||||
cmd->usage = "[params]";
|
||||
if (cmd->mode == CMD_CHECK)
|
||||
return command_param_failed();
|
||||
}
|
||||
|
||||
plugin = find_plugin_for_command(cmd);
|
||||
|
||||
|
@ -675,7 +672,9 @@ static bool plugin_rpcmethod_add(struct plugin *plugin,
|
|||
|
||||
cmd->deprecated = false;
|
||||
cmd->dispatch = plugin_rpcmethod_dispatch;
|
||||
if (!jsonrpc_command_add(plugin->plugins->ld->jsonrpc, cmd)) {
|
||||
if (!jsonrpc_command_add(plugin->plugins->ld->jsonrpc, cmd,
|
||||
/* FIXME */
|
||||
"[params]")) {
|
||||
log_broken(plugin->log,
|
||||
"Could not register method \"%s\", a method with "
|
||||
"that name is already registered",
|
||||
|
|
|
@ -40,6 +40,9 @@ void log_io(struct log *log UNNEEDED, enum log_level dir UNNEEDED, const char *c
|
|||
/* Generated stub for log_prefix */
|
||||
const char *log_prefix(const struct log *log UNNEEDED)
|
||||
{ fprintf(stderr, "log_prefix called!\n"); abort(); }
|
||||
/* Generated stub for memleak_remove_strmap_ */
|
||||
void memleak_remove_strmap_(struct htable *memtable UNNEEDED, const struct strmap *m UNNEEDED)
|
||||
{ fprintf(stderr, "memleak_remove_strmap_ called!\n"); abort(); }
|
||||
/* Generated stub for new_log */
|
||||
struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, const char *fmt UNNEEDED, ...)
|
||||
{ fprintf(stderr, "new_log called!\n"); abort(); }
|
||||
|
|
|
@ -332,12 +332,15 @@ static struct command_result *json_listaddrs(struct command *cmd,
|
|||
u64 *bip32_max_index;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_opt_def("bip32_max_index", param_u64, &bip32_max_index,
|
||||
db_get_intvar(cmd->ld->wallet->db,
|
||||
"bip32_max_index", 0)),
|
||||
p_opt("bip32_max_index", param_u64, &bip32_max_index),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
if (!bip32_max_index) {
|
||||
bip32_max_index = tal(cmd, u64);
|
||||
*bip32_max_index = db_get_intvar(cmd->ld->wallet->db,
|
||||
"bip32_max_index", 0);
|
||||
}
|
||||
response = json_stream_success(cmd);
|
||||
json_object_start(response, NULL);
|
||||
json_array_start(response, "addresses");
|
||||
|
|
Loading…
Add table
Reference in a new issue