diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c index 558e581bd..06f6e4a86 100644 --- a/lightningd/jsonrpc.c +++ b/lightningd/jsonrpc.c @@ -442,6 +442,7 @@ static void parse_request(struct json_connection *jcon, const jsmntok_t tok[]) c->id = tal_strndup(c, json_tok_contents(jcon->buffer, id), json_tok_len(id)); + c->mode = CMD_NORMAL; list_add(&jcon->commands, &c->list); tal_add_destructor(c, destroy_cmd); diff --git a/lightningd/jsonrpc.h b/lightningd/jsonrpc.h index 9f36b8010..e155258a2 100644 --- a/lightningd/jsonrpc.h +++ b/lightningd/jsonrpc.h @@ -10,6 +10,14 @@ struct bitcoin_txid; struct wireaddr; struct wallet_tx; +/* The command mode tells param() how to process. */ +enum command_mode { + /* Normal command processing */ + CMD_NORMAL, + /* Create command usage string, nothing else. */ + CMD_USAGE +}; + /* Context for a command (from JSON, but might outlive the connection!) * You can allocate off this for temporary objects. */ struct command { @@ -25,6 +33,10 @@ struct command { struct json_connection *jcon; /* Have we been marked by command_still_pending? For debugging... */ bool pending; + /* Tell param() how to process the command */ + enum command_mode mode; + /* This is created if mode is CMD_USAGE */ + const char *usage; }; struct json_connection { diff --git a/lightningd/param.c b/lightningd/param.c index a20c00938..c1480d7a5 100644 --- a/lightningd/param.c +++ b/lightningd/param.c @@ -223,6 +223,21 @@ static bool check_params(struct param *params) } #endif +static char *param_usage(const tal_t *ctx, + const struct param *params) +{ + char *usage = tal_strdup(ctx, ""); + for (size_t i = 0; i < tal_count(params); i++) { + if (i != 0) + tal_append_fmt(&usage, " "); + if (params[i].required) + tal_append_fmt(&usage, "%s", params[i].name); + else + tal_append_fmt(&usage, "[%s]", params[i].name); + } + return usage; +} + static bool param_arr(struct command *cmd, const char *buffer, const jsmntok_t tokens[], struct param *params) @@ -263,5 +278,10 @@ bool param(struct command *cmd, const char *buffer, } va_end(ap); + if (cmd->mode == CMD_USAGE) { + cmd->usage = param_usage(cmd, params); + return false; + } + return param_arr(cmd, buffer, tokens, params); } diff --git a/lightningd/test/run-param.c b/lightningd/test/run-param.c index 033ec56dd..7b069deb0 100644 --- a/lightningd/test/run-param.c +++ b/lightningd/test/run-param.c @@ -431,7 +431,7 @@ static void advanced(void) p_opt("msat_opt2", json_tok_msat, &msat_opt2), NULL)); assert(label != NULL); - assert(!strcmp(label->s, "lightning")); + assert(streq(label->s, "lightning")); assert(*msat == 24); assert(tok); assert(msat_opt1); @@ -445,8 +445,8 @@ static void advanced(void) p_req("label", json_tok_label, &label), p_opt("foo", json_tok_label, &foo), NULL)); - assert(!strcmp(label->s, "3")); - assert(!strcmp(foo->s, "foo")); + assert(streq(label->s, "3")); + assert(streq(foo->s, "foo")); } { u64 *msat; @@ -507,6 +507,54 @@ static void json_tok_tests(void) test_cb(json_tok_percent, double, "[ 'wow' ]", 0, false); } +static void test_invoice(struct command *cmd, const char *buffer, + const jsmntok_t *params) +{ + u64 *msatoshi_val; + struct json_escaped *label_val; + const char *desc_val; + u64 *expiry; + const jsmntok_t *fallbacks; + const jsmntok_t *preimagetok; + + assert(cmd->mode == CMD_USAGE); + if(!param(cmd, buffer, params, + p_req("msatoshi", json_tok_msat, &msatoshi_val), + p_req("label", json_tok_label, &label_val), + p_req("description", json_tok_escaped_string, &desc_val), + p_opt("expiry", json_tok_u64, &expiry), + p_opt("fallbacks", json_tok_array, &fallbacks), + p_opt("preimage", json_tok_tok, &preimagetok), NULL)) + return; + + /* should not be here since we are in the mode of CMD_USAGE + * and it always returns false. */ + abort(); +} + +static void usage(void) +{ + /* Do this to simulate a call to our pretend handler (test_invoice) */ + struct json_command invoice_command = { + "invoice", + test_invoice, + "", + false, + "" + }; + + cmd->mode = CMD_USAGE; + cmd->json_cmd = &invoice_command; + + cmd->json_cmd->dispatch(cmd, NULL, NULL); + + assert(streq(cmd->usage, + "msatoshi label description " + "[expiry] [fallbacks] [preimage]")); + + cmd->mode = CMD_NORMAL; +} + int main(void) { setup_locale(); @@ -528,6 +576,8 @@ int main(void) advanced(); advanced_fail(); json_tok_tests(); + usage(); + tal_free(tmpctx); printf("run-params ok\n"); }