diff --git a/plugins/libplugin.c b/plugins/libplugin.c index 50448e9f8..363b1ae94 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,10 @@ static UINTMAP(struct out_req *) out_reqs; static u64 next_outreq_id; +/* 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. */ +static STRMAP(const char *) usagemap; + struct plugin_conn { int fd; MEMBUF(char) mb; @@ -260,20 +265,23 @@ struct command_result *command_fail(struct command *cmd, return res; } -/* We never invoke param for usage. */ +/* We invoke param for usage at registration time. */ bool command_usage_only(const struct command *cmd) { - return false; + return cmd->rpc == NULL; } +/* FIXME: would be good to support this! */ bool command_check_only(const struct command *cmd) { return false; } -void command_set_usage(struct command *cmd, const char *usage) +void command_set_usage(struct command *cmd, const char *usage TAKES) { - abort(); + usage = tal_strdup(NULL, usage); + if (!strmap_add(&usagemap, cmd->methodname, usage)) + plugin_err("Two usages for command %s?", cmd->methodname); } /* Reads rpc reply and returns tokens, setting contents to 'error' or @@ -418,8 +426,10 @@ handle_getmanifest(struct command *getmanifest_cmd, "'rpcmethods': [ "); for (size_t i = 0; i < num_commands; i++) { tal_append_fmt(¶ms, "{ 'name': '%s'," + " 'usage': '%s'," " 'description': '%s'", commands[i].name, + strmap_get(&usagemap, commands[i].name), commands[i].description); if (commands[i].long_description) tal_append_fmt(¶ms, @@ -491,6 +501,23 @@ static void handle_new_command(const tal_t *ctx, plugin_err("Unknown command '%s'", cmd->methodname); } +static void setup_command_usage(const struct plugin_command *commands, + size_t num_commands) +{ + struct command *usage_cmd = tal(tmpctx, struct command); + + /* This is how common/param can tell it's just a usage request */ + usage_cmd->rpc = NULL; + for (size_t i = 0; i < num_commands; i++) { + struct command_result *res; + + usage_cmd->methodname = commands[i].name; + res = commands[i].handle(usage_cmd, NULL, NULL); + assert(res == NULL); + assert(strmap_get(&usagemap, commands[i].name)); + } +} + void plugin_main(char *argv[], void (*init)(struct plugin_conn *rpc), const struct plugin_command *commands, @@ -510,6 +537,8 @@ void plugin_main(char *argv[], /* Note this already prints to stderr, which is enough for now */ daemon_setup(argv[0], NULL, NULL); + setup_command_usage(commands, num_commands); + membuf_init(&rpc_conn.mb, tal_arr(ctx, char, READ_CHUNKSIZE), READ_CHUNKSIZE, membuf_tal_realloc);