Plugin: support extra args to "start".

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: Plugins: `start` command can now take plugin-specific parameters.
This commit is contained in:
Rusty Russell
2020-12-14 15:28:35 +10:30
parent 8a9976c4c1
commit d971e3de98
8 changed files with 117 additions and 18 deletions

View File

@@ -348,7 +348,7 @@ static char *opt_add_plugin(const char *arg, struct lightningd *ld)
log_info(ld->log, "%s: disabled via disable-plugin", arg);
return NULL;
}
plugin_register(ld->plugins, arg, NULL, false);
plugin_register(ld->plugins, arg, NULL, false, NULL, NULL);
return NULL;
}
@@ -375,7 +375,7 @@ static char *opt_important_plugin(const char *arg, struct lightningd *ld)
log_info(ld->log, "%s: disabled via disable-plugin", arg);
return NULL;
}
plugin_register(ld->plugins, arg, NULL, true);
plugin_register(ld->plugins, arg, NULL, true, NULL, NULL);
return NULL;
}

View File

@@ -1,5 +1,6 @@
#include <ccan/array_size/array_size.h>
#include <ccan/list/list.h>
#include <ccan/mem/mem.h>
#include <ccan/opt/opt.h>
#include <ccan/tal/str/str.h>
#include <ccan/utf8/utf8.h>
@@ -174,7 +175,9 @@ static void destroy_plugin(struct plugin *p)
}
struct plugin *plugin_register(struct plugins *plugins, const char* path TAKES,
struct command *start_cmd, bool important)
struct command *start_cmd, bool important,
const char *parambuf STEALS,
const jsmntok_t *params STEALS)
{
struct plugin *p, *p_temp;
@@ -212,6 +215,8 @@ struct plugin *plugin_register(struct plugins *plugins, const char* path TAKES,
list_head_init(&p->pending_rpccalls);
p->important = important;
p->parambuf = tal_steal(p, parambuf);
p->params = tal_steal(p, params);
return p;
}
@@ -1154,6 +1159,48 @@ static const char *plugin_hooks_add(struct plugin *plugin, const char *buffer,
return NULL;
}
static struct plugin_opt *plugin_opt_find(struct plugin *plugin,
const char *name, size_t namelen)
{
struct plugin_opt *opt;
list_for_each(&plugin->plugin_opts, opt, list) {
/* Trim the `--` that we added before */
if (memeqstr(name, namelen, opt->name + 2))
return opt;
}
return NULL;
}
/* start command might have included plugin-specific parameters */
static const char *plugin_add_params(struct plugin *plugin)
{
size_t i;
const jsmntok_t *t;
if (!plugin->params)
return NULL;
json_for_each_obj(i, t, plugin->params) {
struct plugin_opt *popt;
char *err;
popt = plugin_opt_find(plugin,
plugin->parambuf + t->start,
t->end - t->start);
if (!popt) {
return tal_fmt(plugin, "unknown parameter %.*s",
json_tok_full_len(t),
json_tok_full(plugin->parambuf, t));
}
err = plugin_opt_set(json_strdup(tmpctx, plugin->parambuf,
t + 1), popt);
if (err)
return err;
}
return NULL;
}
static void plugin_manifest_timeout(struct plugin *plugin)
{
bool startup = plugin->plugins->startup;
@@ -1243,6 +1290,8 @@ static const char *plugin_parse_getmanifest_response(const char *buffer,
err = plugin_subscriptions_add(plugin, buffer, resulttok);
if (!err)
err = plugin_hooks_add(plugin, buffer, resulttok);
if (!err)
err = plugin_add_params(plugin);
plugin->plugin_state = NEEDS_INIT;
return err;
@@ -1360,7 +1409,8 @@ char *add_plugin_dir(struct plugins *plugins, const char *dir, bool error_ok)
log_info(plugins->log, "%s: disabled via disable-plugin",
fullpath);
} else {
p = plugin_register(plugins, fullpath, NULL, false);
p = plugin_register(plugins, fullpath, NULL, false,
NULL, NULL);
if (!p && !error_ok)
return tal_fmt(NULL, "Failed to register %s: %s",
fullpath, strerror(errno));
@@ -1807,7 +1857,8 @@ void plugins_set_builtin_plugins_dir(struct plugins *plugins,
take(path_join(NULL, dir,
list_of_builtin_plugins[i])),
NULL,
/* important = */ true);
/* important = */ true,
NULL, NULL);
}
struct plugin_destroyed {

View File

@@ -88,6 +88,10 @@ struct plugin {
/* If set, the plugin is so important that if it terminates early,
* C-lightning should terminate as well. */
bool important;
/* Parameters for dynamically-started plugins. */
const char *parambuf;
const jsmntok_t *params;
};
/**
@@ -200,6 +204,8 @@ void plugins_free(struct plugins *plugins);
* @param path: The path of the executable for this plugin
* @param start_cmd: The optional JSON command which caused this.
* @param important: The plugin is important.
* @param parambuf: NULL, or the JSON buffer for extra parameters.
* @param params: NULL, or the tokens for extra parameters.
*
* If @start_cmd, then plugin_cmd_killed or plugin_cmd_succeeded will be called
* on it eventually.
@@ -207,7 +213,10 @@ void plugins_free(struct plugins *plugins);
struct plugin *plugin_register(struct plugins *plugins,
const char* path TAKES,
struct command *start_cmd,
bool important);
bool important,
const char *parambuf STEALS,
const jsmntok_t *params STEALS);
/**
* Returns true if the provided name matches a plugin command

View File

@@ -56,9 +56,10 @@ struct command_result *plugin_cmd_all_complete(struct plugins *plugins,
* will give a result 60 seconds later at the most (once init completes).
*/
static struct command_result *
plugin_dynamic_start(struct command *cmd, const char *plugin_path)
plugin_dynamic_start(struct command *cmd, const char *plugin_path,
const char *buffer, const jsmntok_t *params)
{
struct plugin *p = plugin_register(cmd->ld->plugins, plugin_path, cmd, false);
struct plugin *p = plugin_register(cmd->ld->plugins, plugin_path, cmd, false, buffer, params);
const char *err;
if (!p)
@@ -173,15 +174,35 @@ static struct command_result *json_plugin_control(struct command *cmd,
return plugin_dynamic_stop(cmd, plugin_name);
} else if (streq(subcmd, "start")) {
const char *plugin_path;
jsmntok_t *mod_params;
if (!param(cmd, buffer, params,
p_req("subcommand", param_ignore, cmd),
p_req("plugin", param_string, &plugin_path),
p_opt_any(),
NULL))
return command_param_failed();
/* Manually parse any remaining options (only for objects,
* since plugin options must be explicitly named!). */
if (params->type == JSMN_ARRAY) {
if (params->size != 2)
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"Extra parameters must be in object");
mod_params = NULL;
} else {
mod_params = json_tok_copy(cmd, params);
json_tok_remove(&mod_params, mod_params,
json_get_member(buffer, mod_params,
"subcommand") - 1, 1);
json_tok_remove(&mod_params, mod_params,
json_get_member(buffer, mod_params,
"plugin") - 1, 1);
}
if (access(plugin_path, X_OK) == 0)
return plugin_dynamic_start(cmd, plugin_path);
return plugin_dynamic_start(cmd, plugin_path,
buffer, mod_params);
else
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"%s is not executable: %s",