@ -21,6 +21,7 @@
# include <ccan/err/err.h>
# include <ccan/err/err.h>
# include <ccan/io/io.h>
# include <ccan/io/io.h>
# include <ccan/str/hex/hex.h>
# include <ccan/str/hex/hex.h>
# include <ccan/strmap/strmap.h>
# include <ccan/tal/str/str.h>
# include <ccan/tal/str/str.h>
# include <common/bech32.h>
# include <common/bech32.h>
# include <common/json_command.h>
# include <common/json_command.h>
@ -38,6 +39,7 @@
# include <lightningd/json.h>
# include <lightningd/json.h>
# include <lightningd/jsonrpc.h>
# include <lightningd/jsonrpc.h>
# include <lightningd/log.h>
# include <lightningd/log.h>
# include <lightningd/memdump.h>
# include <lightningd/options.h>
# include <lightningd/options.h>
# include <stdio.h>
# include <stdio.h>
# include <sys/socket.h>
# include <sys/socket.h>
@ -106,6 +108,10 @@ struct jsonrpc {
struct io_listener * rpc_listener ;
struct io_listener * rpc_listener ;
struct json_command * * commands ;
struct json_command * * commands ;
struct log * log ;
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.
/* 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 )
struct json_command * json_command )
{
{
char * usage ;
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_object_start ( response , NULL ) ;
json_add_string ( response , " command " , usage ) ;
json_add_string ( response , " command " , usage ) ;
@ -347,7 +354,7 @@ static struct command_result *json_help(struct command *cmd,
{
{
struct json_stream * response ;
struct json_stream * response ;
const jsmntok_t * cmdtok ;
const jsmntok_t * cmdtok ;
struct json_command * * commands = cmd - > ld - > jsonrpc - > commands ;
struct json_command * * commands ;
const struct json_command * one_cmd ;
const struct json_command * one_cmd ;
if ( ! param ( cmd , buffer , params ,
if ( ! param ( cmd , buffer , params ,
@ -355,6 +362,7 @@ static struct command_result *json_help(struct command *cmd,
NULL ) )
NULL ) )
return command_param_failed ( ) ;
return command_param_failed ( ) ;
commands = cmd - > ld - > jsonrpc - > commands ;
if ( cmdtok ) {
if ( cmdtok ) {
one_cmd = find_command ( commands , buffer , cmdtok ) ;
one_cmd = find_command ( commands , buffer , cmdtok ) ;
if ( ! one_cmd )
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 )
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 + + ) {
for ( size_t i = 0 ; i < tal_count ( rpc - > commands ) ; i + + ) {
if ( rpc - > commands [ i ] = = command ) {
if ( rpc - > commands [ i ] = = command ) {
tal_arr_remove ( & rpc - > commands , i ) ;
tal_arr_remove ( & rpc - > commands , i ) ;
@ -780,9 +789,7 @@ static void destroy_json_command(struct json_command *command, struct jsonrpc *r
abort ( ) ;
abort ( ) ;
}
}
/* For built-in ones, they're not tal objects, so no destructor */
static bool command_add ( struct jsonrpc * rpc , struct json_command * command )
static bool jsonrpc_command_add_perm ( struct jsonrpc * rpc ,
struct json_command * command )
{
{
size_t count = tal_count ( rpc - > commands ) ;
size_t count = tal_count ( rpc - > commands ) ;
@ -795,23 +802,54 @@ static bool jsonrpc_command_add_perm(struct jsonrpc *rpc,
return true ;
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 = = & param_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 ;
return false ;
usage = tal_strdup ( command , usage ) ;
strmap_add ( & rpc - > usagemap , command - > name , usage ) ;
tal_add_destructor2 ( command , destroy_json_command , rpc ) ;
tal_add_destructor2 ( command , destroy_json_command , rpc ) ;
return true ;
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 )
void jsonrpc_setup ( struct lightningd * ld )
{
{
struct json_command * * commands = get_cmdlist ( ) ;
struct json_command * * commands = get_cmdlist ( ) ;
ld - > jsonrpc = tal ( ld , struct jsonrpc ) ;
ld - > jsonrpc = tal ( ld , struct jsonrpc ) ;
strmap_init ( & ld - > jsonrpc - > usagemap ) ;
ld - > jsonrpc - > commands = tal_arr ( ld - > jsonrpc , struct json_command * , 0 ) ;
ld - > jsonrpc - > commands = tal_arr ( ld - > jsonrpc , struct json_command * , 0 ) ;
ld - > jsonrpc - > log = new_log ( ld - > jsonrpc , ld - > log_book , " jsonrpc " ) ;
ld - > jsonrpc - > log = new_log ( ld - > jsonrpc , ld - > log_book , " jsonrpc " ) ;
for ( size_t i = 0 ; i < num_cmdlist ; i + + ) {
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 " ,
fatal ( " Cannot add duplicate command %s " ,
commands [ i ] - > name ) ;
commands [ i ] - > name ) ;
}
}
@ -823,9 +861,11 @@ bool command_usage_only(const struct command *cmd)
return cmd - > mode = = CMD_USAGE ;
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 )
bool command_check_only ( const struct command * cmd )
@ -1141,3 +1181,11 @@ static const struct json_command check_command = {
} ;
} ;
AUTODATA ( 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 */