mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 18:11:28 +01:00
plugin: Register plugin cli options
We also make `--help` a non-early arg so it allows for the plugins to register their options before printing the help message. The options themselves are stored in a separate struct inbetween them being registered and them being forwarded to the plugin. Currently only supports string options. Signed-off-by: Christian Decker <@cdecker>
This commit is contained in:
parent
10338983a6
commit
55d6d6b0e7
@ -19,7 +19,10 @@ def json_hello(request):
|
|||||||
def json_init(request):
|
def json_init(request):
|
||||||
return {
|
return {
|
||||||
"options": [
|
"options": [
|
||||||
{"name": "greeting", "type": "string", "default": "World"},
|
{"name": "greeting",
|
||||||
|
"type": "string",
|
||||||
|
"default": "World",
|
||||||
|
"description": "What name should I call you?"},
|
||||||
],
|
],
|
||||||
"rpcmethods": [
|
"rpcmethods": [
|
||||||
{
|
{
|
||||||
|
@ -724,7 +724,7 @@ void register_opts(struct lightningd *ld)
|
|||||||
{
|
{
|
||||||
opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
|
opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
|
||||||
|
|
||||||
opt_register_early_noarg("--help|-h", opt_lightningd_usage, ld,
|
opt_register_noarg("--help|-h", opt_lightningd_usage, ld,
|
||||||
"Print this message.");
|
"Print this message.");
|
||||||
opt_register_early_noarg("--test-daemons-only",
|
opt_register_early_noarg("--test-daemons-only",
|
||||||
test_subdaemons_and_exit,
|
test_subdaemons_and_exit,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <ccan/intmap/intmap.h>
|
#include <ccan/intmap/intmap.h>
|
||||||
#include <ccan/io/io.h>
|
#include <ccan/io/io.h>
|
||||||
#include <ccan/list/list.h>
|
#include <ccan/list/list.h>
|
||||||
|
#include <ccan/opt/opt.h>
|
||||||
#include <ccan/pipecmd/pipecmd.h>
|
#include <ccan/pipecmd/pipecmd.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <lightningd/json.h>
|
#include <lightningd/json.h>
|
||||||
@ -25,17 +26,22 @@ struct plugin {
|
|||||||
const char *outbuf;
|
const char *outbuf;
|
||||||
|
|
||||||
struct log *log;
|
struct log *log;
|
||||||
|
|
||||||
|
/* List of options that this plugin registered */
|
||||||
|
struct list_head plugin_opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct plugin_request {
|
struct plugin_request {
|
||||||
u64 id;
|
u64 id;
|
||||||
|
struct plugin *plugin;
|
||||||
|
|
||||||
/* Method to be called */
|
/* Method to be called */
|
||||||
const char *method;
|
const char *method;
|
||||||
|
|
||||||
/* JSON encoded params, either a dict or an array */
|
/* JSON encoded params, either a dict or an array */
|
||||||
const char *json_params;
|
const char *json_params;
|
||||||
const char *response;
|
const char *response;
|
||||||
const jsmntok_t *resulttok, *errortok;
|
const jsmntok_t *resulttok, *errortok, *toks;
|
||||||
|
|
||||||
/* The response handler to be called on success or error */
|
/* The response handler to be called on success or error */
|
||||||
void (*cb)(const struct plugin_request *, void *);
|
void (*cb)(const struct plugin_request *, void *);
|
||||||
@ -56,6 +62,15 @@ struct json_output {
|
|||||||
const char *json;
|
const char *json;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Simple storage for plugin options inbetween registering them on the
|
||||||
|
* command line and passing them off to the plugin */
|
||||||
|
struct plugin_opt {
|
||||||
|
struct list_node list;
|
||||||
|
const char *name;
|
||||||
|
const char *description;
|
||||||
|
char *value;
|
||||||
|
};
|
||||||
|
|
||||||
struct plugins *plugins_new(const tal_t *ctx, struct log *log){
|
struct plugins *plugins_new(const tal_t *ctx, struct log *log){
|
||||||
struct plugins *p;
|
struct plugins *p;
|
||||||
p = tal(ctx, struct plugins);
|
p = tal(ctx, struct plugins);
|
||||||
@ -74,6 +89,7 @@ void plugin_register(struct plugins *plugins, const char* path TAKES)
|
|||||||
p->plugins = plugins;
|
p->plugins = plugins;
|
||||||
p->cmd = tal_strdup(p, path);
|
p->cmd = tal_strdup(p, path);
|
||||||
p->log = plugins->log;
|
p->log = plugins->log;
|
||||||
|
list_head_init(&p->plugin_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,6 +165,7 @@ static bool plugin_read_json_one(struct plugin *plugin)
|
|||||||
request->response = plugin->buffer;
|
request->response = plugin->buffer;
|
||||||
request->errortok = errortok;
|
request->errortok = errortok;
|
||||||
request->resulttok = resulttok;
|
request->resulttok = resulttok;
|
||||||
|
request->toks = toks;
|
||||||
request->cb(request, request->arg);
|
request->cb(request, request->arg);
|
||||||
|
|
||||||
/* Move this object out of the buffer */
|
/* Move this object out of the buffer */
|
||||||
@ -217,6 +234,7 @@ static void plugin_request_send_(
|
|||||||
req->json_params = tal_strdup(req, params);
|
req->json_params = tal_strdup(req, params);
|
||||||
req->cb = cb;
|
req->cb = cb;
|
||||||
req->arg = arg;
|
req->arg = arg;
|
||||||
|
req->plugin = plugin;
|
||||||
|
|
||||||
/* Add to map so we can find it later when routing the response */
|
/* Add to map so we can find it later when routing the response */
|
||||||
uintmap_add(&plugin->plugins->pending_requests, req->id, req);
|
uintmap_add(&plugin->plugins->pending_requests, req->id, req);
|
||||||
@ -261,6 +279,90 @@ static struct io_plan *plugin_conn_init(struct io_conn *conn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback called when parsing options. It just stores the value in
|
||||||
|
* the plugin_opt */
|
||||||
|
static char *plugin_opt_set(const char *arg, struct plugin_opt *popt)
|
||||||
|
{
|
||||||
|
popt->value = tal_strdup(popt, arg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a single plugin option to the plugin as well as registering it with the
|
||||||
|
* command line options. */
|
||||||
|
static bool plugin_opt_add(struct plugin *plugin, const char *buffer,
|
||||||
|
const jsmntok_t *opt)
|
||||||
|
{
|
||||||
|
const jsmntok_t *nametok, *typetok, *defaulttok, *desctok;
|
||||||
|
struct plugin_opt *popt;
|
||||||
|
nametok = json_get_member(buffer, opt, "name");
|
||||||
|
typetok = json_get_member(buffer, opt, "type");
|
||||||
|
desctok = json_get_member(buffer, opt, "description");
|
||||||
|
defaulttok = json_get_member(buffer, opt, "default");
|
||||||
|
|
||||||
|
if (!typetok || !nametok || !desctok) {
|
||||||
|
plugin_kill(plugin,
|
||||||
|
"An option is missing either \"name\", \"description\" or \"type\"");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME(cdecker) Support numeric and boolean options as well */
|
||||||
|
if (!json_tok_streq(buffer, typetok, "string")) {
|
||||||
|
plugin_kill(plugin,
|
||||||
|
"Only \"string\" options currently supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
popt = tal(plugin, struct plugin_opt);
|
||||||
|
|
||||||
|
popt->name = tal_fmt(plugin, "--%.*s", nametok->end - nametok->start,
|
||||||
|
buffer + nametok->start);
|
||||||
|
popt->value = NULL;
|
||||||
|
if (defaulttok) {
|
||||||
|
popt->value = tal_strndup(plugin, buffer + defaulttok->start,
|
||||||
|
defaulttok->end - defaulttok->start);
|
||||||
|
popt->description = tal_fmt(
|
||||||
|
plugin, "%.*s (default: %s)", desctok->end - desctok->start,
|
||||||
|
buffer + desctok->start, popt->value);
|
||||||
|
} else {
|
||||||
|
popt->description = tal_strndup(plugin, buffer + desctok->start,
|
||||||
|
desctok->end - desctok->start);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&plugin->plugin_opts, &popt->list);
|
||||||
|
|
||||||
|
opt_register_arg(popt->name, plugin_opt_set, NULL, popt,
|
||||||
|
popt->description);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iterate through the options in the init response, and add them to
|
||||||
|
* the plugin and the command line options */
|
||||||
|
static bool plugin_opts_add(const struct plugin_request *req)
|
||||||
|
{
|
||||||
|
const char *buffer = req->plugin->buffer;
|
||||||
|
const jsmntok_t *cur, *options;
|
||||||
|
|
||||||
|
/* This is the parent for all elements in the "options" array */
|
||||||
|
int optpos;
|
||||||
|
options =
|
||||||
|
json_get_member(req->plugin->buffer, req->resulttok, "options");
|
||||||
|
if (!options)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
optpos = options - req->toks;
|
||||||
|
|
||||||
|
if (options->type != JSMN_ARRAY) {
|
||||||
|
plugin_kill(req->plugin, "\"result.options\" is not an array");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cur = options + 1; cur->parent == optpos; cur = json_next(cur))
|
||||||
|
if (!plugin_opt_add(req->plugin, buffer, cur))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for the plugin_init request.
|
* Callback for the plugin_init request.
|
||||||
*/
|
*/
|
||||||
@ -270,6 +372,14 @@ static void plugin_init_cb(const struct plugin_request *req, struct plugin *plug
|
|||||||
plugin->plugins->pending_init--;
|
plugin->plugins->pending_init--;
|
||||||
if (plugin->plugins->pending_init == 0)
|
if (plugin->plugins->pending_init == 0)
|
||||||
io_break(plugin->plugins);
|
io_break(plugin->plugins);
|
||||||
|
|
||||||
|
if (req->resulttok->type != JSMN_OBJECT) {
|
||||||
|
plugin_kill(plugin, "\"init\" response is not an object");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!plugin_opts_add(req))
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugins_init(struct plugins *plugins)
|
void plugins_init(struct plugins *plugins)
|
||||||
|
Loading…
Reference in New Issue
Block a user