diff --git a/lightningd/plugin.c b/lightningd/plugin.c index 55fc5f538f17..217a570dd8fb 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -1086,9 +1087,53 @@ void json_add_opt_plugins(struct json_stream *response, const struct plugins *plugins) { struct plugin *p; + struct plugin_opt *opt; + const char *opt_name; + const char *plugin_name; + char *plugin_ext; + + /* DEPRECATED: duplicated JSON "plugin" entries */ + if (deprecated_apis) { + list_for_each(&plugins->plugins, p, list) { + json_add_string(response, "plugin", p->cmd); + } + } + + /* we output 'plugins' and their options as an array of substructures */ + json_array_start(response, "plugins"); list_for_each(&plugins->plugins, p, list) { - json_add_string(response, "plugin", p->cmd); + json_object_start(response, NULL); + + /* guess a suitable plugin name: basename without extension */ + plugin_name = tal_strdup(p, basename(p->cmd)); + plugin_ext = strrchr(plugin_name, '.'); + if (plugin_ext != NULL) + plugin_ext[0] = 0; + json_add_string(response, "name", plugin_name); + tal_free(plugin_name); + + json_add_string(response, "path", p->cmd); + if (!list_empty(&p->plugin_opts)) { + json_object_start(response, "options"); + list_for_each(&p->plugin_opts, opt, list) + { + /* Trim the `--` that we added before */ + opt_name = opt->name + 2; + if (opt->value->as_str) { + json_add_string(response, opt_name, opt->value->as_str); + } else if (opt->value->as_bool) { + json_add_bool(response, opt_name, opt->value->as_bool); + } else if (opt->value->as_int) { + json_add_bool(response, opt_name, opt->value->as_int); + } else { + json_add_null(response, opt_name); + } + } + json_object_end(response); + } + json_object_end(response); } + json_array_end(response); } /** diff --git a/tests/test_misc.py b/tests/test_misc.py index e1f01d4794c3..142341b3e58c 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -742,12 +742,25 @@ def test_listconfigs(node_factory, bitcoind, chainparams): # Test one at a time. for c in configs.keys(): - if c.startswith('#'): + if c.startswith('#') or c.startswith('plugins'): continue oneconfig = l1.rpc.listconfigs(config=c) assert(oneconfig[c] == configs[c]) +def test_listconfigs_plugins(node_factory, bitcoind, chainparams): + l1 = node_factory.get_node() + + # assert that we have pay plugin and that plugins have a name and path + configs = l1.rpc.listconfigs() + assert configs['plugins'] + assert len([p for p in configs['plugins'] if p['name'] == "pay"]) == 1 + for p in configs['plugins']: + assert p['name'] and len(p['name']) > 0 + assert p['path'] and len(p['path']) > 0 + assert os.path.isfile(p['path']) and os.access(p['path'], os.X_OK) + + def test_multirpc(node_factory): """Test that we can do multiple RPC without waiting for response""" l1 = node_factory.get_node()