Skip to content

Commit 7fdccca

Browse files
committed
libplugin: support multi options.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Added: libplugin: support for options which accumulate if specified more than once ("multi": true).
1 parent 70ea324 commit 7fdccca

File tree

5 files changed

+67
-11
lines changed

5 files changed

+67
-11
lines changed

plugins/libplugin.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ struct plugin_option {
6262
const char *depr_start, *depr_end;
6363
/* If true, allow setting after plugin has initialized */
6464
bool dynamic;
65+
/* If true, allow multiple settings. */
66+
bool multi;
6567
};
6668

6769
struct plugin {
@@ -1313,6 +1315,7 @@ handle_getmanifest(struct command *getmanifest_cmd,
13131315
json_add_string(params, "description", p->opts[i].description);
13141316
json_add_deprecated(params, "deprecated", p->opts[i].depr_start, p->opts[i].depr_end);
13151317
json_add_bool(params, "dynamic", p->opts[i].dynamic);
1318+
json_add_bool(params, "multi", p->opts[i].multi);
13161319
if (p->opts[i].jsonfmt)
13171320
p->opts[i].jsonfmt(p, params, "default", p->opts[i].arg);
13181321
json_object_end(params);
@@ -1637,9 +1640,19 @@ static struct command_result *handle_init(struct command *cmd,
16371640
if (!popt)
16381641
plugin_err(p, "lightningd specified unknown option '%s'?", name);
16391642

1640-
problem = popt->handle(p, json_strdup(tmpctx, buf, t+1), false, popt->arg);
1641-
if (problem)
1642-
plugin_err(p, "option '%s': %s", popt->name, problem);
1643+
if (popt->multi) {
1644+
size_t j;
1645+
const jsmntok_t *opt;
1646+
json_for_each_arr(j, opt, t+1) {
1647+
problem = popt->handle(p, json_strdup(tmpctx, buf, opt), false, popt->arg);
1648+
if (problem)
1649+
plugin_err(p, "option '%s': %s", popt->name, problem);
1650+
}
1651+
} else {
1652+
problem = popt->handle(p, json_strdup(tmpctx, buf, t+1), false, popt->arg);
1653+
if (problem)
1654+
plugin_err(p, "option '%s': %s", popt->name, problem);
1655+
}
16431656
}
16441657

16451658
if (p->init) {
@@ -2506,6 +2519,7 @@ static struct plugin *new_plugin(const tal_t *ctx,
25062519
o.depr_start = va_arg(ap, const char *);
25072520
o.depr_end = va_arg(ap, const char *);
25082521
o.dynamic = va_arg(ap, int); /* bool gets promoted! */
2522+
o.multi = va_arg(ap, int); /* bool gets promoted! */
25092523
tal_arr_expand(&p->opts, o);
25102524
}
25112525

plugins/libplugin.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ void *plugin_get_data_(struct plugin *plugin);
590590
#define plugin_get_data(plugin, type) ((type *)(plugin_get_data_(plugin)))
591591

592592
/* Macro to define arguments */
593-
#define plugin_option_(name, type, description, set, jsonfmt, arg, dev_only, depr_start, depr_end, dynamic) \
593+
#define plugin_option_(name, type, description, set, jsonfmt, arg, dev_only, depr_start, depr_end, dynamic, multi) \
594594
(name), \
595595
(type), \
596596
(description), \
@@ -607,23 +607,27 @@ void *plugin_get_data_(struct plugin *plugin);
607607
(dev_only), \
608608
(depr_start), \
609609
(depr_end), \
610-
(dynamic)
610+
(dynamic), \
611+
(multi)
611612

612613
/* jsonfmt can be NULL, but then default won't be printed */
613614
#define plugin_option(name, type, description, set, jsonfmt, arg) \
614-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, false)
615+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, false, false)
615616

616617
#define plugin_option_dev(name, type, description, set, jsonfmt, arg) \
617-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, false)
618+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, false, false)
618619

619620
#define plugin_option_dev_dynamic(name, type, description, set, jsonfmt, arg) \
620-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, true)
621+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, true, false)
621622

622623
#define plugin_option_dynamic(name, type, description, set, jsonfmt, arg) \
623-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, true)
624+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, true, false)
624625

625626
#define plugin_option_deprecated(name, type, description, depr_start, depr_end, set, jsonfmt, arg) \
626-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, (depr_start), (depr_end), false)
627+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, (depr_start), (depr_end), false, false)
628+
629+
#define plugin_option_multi(name, type, description, set, jsonfmt, arg) \
630+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, false, true)
627631

628632
/* Standard helpers */
629633
char *u64_option(struct plugin *plugin, const char *arg, bool check_only, u64 *i);

plugins/xpay/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ ALL_C_SOURCES += $(PLUGIN_XPAY_SRC)
1010
ALL_C_HEADERS += $(PLUGIN_XPAY_HDRS)
1111

1212
# Make all plugins depend on all plugin headers, for simplicity.
13-
$(PLUGIN_XPAY_OBJS): $(PLUGIN_XPAY_HDRS)
13+
$(PLUGIN_XPAY_OBJS): $(PLUGIN_XPAY_HDRS) $(PLUGIN_LIB_HEADER)
1414

1515
plugins/cln-xpay: $(PLUGIN_XPAY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) bitcoin/chainparams.o common/gossmap.o common/gossmods_listpeerchannels.o common/fp16.o common/dijkstra.o common/bolt12.o common/bolt12_merkle.o common/sciddir_or_pubkey.o wire/bolt12_wiregen.o wire/onion_wiregen.o common/onionreply.o common/onion_encode.o common/sphinx.o common/hmac.o

tests/plugins/test_libplugin.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct test_libplugin {
1212
bool self_disable;
1313
bool dont_shutdown;
1414
u32 dynamic_opt;
15+
const char **strarr;
1516
};
1617

1718
static struct test_libplugin *get_test_libplugin(struct plugin *plugin)
@@ -229,6 +230,13 @@ static const char *init(struct command *init_cmd,
229230
plugin_log(p, LOG_DBG, "somearg = %s", tlp->somearg);
230231
tlp->somearg = tal_free(tlp->somearg);
231232

233+
for (size_t i = 0; i < tal_count(tlp->strarr); i++) {
234+
plugin_log(p, LOG_DBG, "multiopt#%zu = %s",
235+
i, tlp->strarr[i]);
236+
}
237+
if (tlp->somearg)
238+
plugin_log(p, LOG_DBG, "somearg = %s", tlp->somearg);
239+
232240
if (tlp->self_disable)
233241
return "Disabled via selfdisable option";
234242

@@ -295,6 +303,25 @@ static const struct plugin_notification notifs[] = { {
295303
}
296304
};
297305

306+
static char *set_multi_string_option(struct plugin *plugin,
307+
const char *arg,
308+
bool check_only,
309+
const char ***arr)
310+
{
311+
if (!check_only)
312+
tal_arr_expand(arr, tal_strdup(*arr, arg));
313+
return NULL;
314+
}
315+
316+
static bool multi_string_jsonfmt(struct plugin *plugin, struct json_stream *js, const char *fieldname, const char ***arr)
317+
{
318+
json_array_start(js, fieldname);
319+
for (size_t i = 0; i < tal_count(*arr); i++)
320+
json_add_string(js, NULL, (*arr)[i]);
321+
json_array_end(js);
322+
return true;
323+
}
324+
298325
int main(int argc, char *argv[])
299326
{
300327
setup_locale();
@@ -306,6 +333,7 @@ int main(int argc, char *argv[])
306333
tlp->self_disable = false;
307334
tlp->dont_shutdown = false;
308335
tlp->dynamic_opt = 7;
336+
tlp->strarr = tal_arr(tlp, const char *, 0);
309337

310338
plugin_main(argv, init, take(tlp), PLUGIN_RESTARTABLE, true, NULL,
311339
commands, ARRAY_SIZE(commands),
@@ -336,5 +364,11 @@ int main(int argc, char *argv[])
336364
"Set me!",
337365
set_dynamic, u32_jsonfmt,
338366
&tlp->dynamic_opt),
367+
plugin_option_multi("multiopt",
368+
"string",
369+
"Set me multiple times!",
370+
set_multi_string_option,
371+
multi_string_jsonfmt,
372+
&tlp->strarr),
339373
NULL);
340374
}

tests/test_plugin.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,7 @@ def test_libplugin(node_factory):
16841684
assert l1.daemon.is_in_stderr(r"somearg-deprecated=test_opt: deprecated option")
16851685

16861686
del l1.daemon.opts["somearg-deprecated"]
1687+
l1.daemon.opts["multiopt"] = ['hello', 'world']
16871688
l1.start()
16881689

16891690
# Test that check works as expected.
@@ -1697,6 +1698,9 @@ def test_libplugin(node_factory):
16971698
# This works
16981699
assert l1.rpc.check('checkthis', key=["test_libplugin", "name"]) == {'command_to_check': 'checkthis'}
16991700

1701+
assert l1.daemon.is_in_log('plugin-test_libplugin: multiopt#0 = hello')
1702+
assert l1.daemon.is_in_log('plugin-test_libplugin: multiopt#1 = world')
1703+
17001704

17011705
def test_libplugin_deprecated(node_factory):
17021706
"""Sanity checks for plugins made with libplugin using deprecated args"""

0 commit comments

Comments
 (0)