Skip to content

Commit 88d73d4

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 a17eb06 commit 88d73d4

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 {
@@ -1262,6 +1264,7 @@ handle_getmanifest(struct command *getmanifest_cmd,
12621264
json_add_string(params, "description", p->opts[i].description);
12631265
json_add_deprecated(params, "deprecated", p->opts[i].depr_start, p->opts[i].depr_end);
12641266
json_add_bool(params, "dynamic", p->opts[i].dynamic);
1267+
json_add_bool(params, "multi", p->opts[i].multi);
12651268
if (p->opts[i].jsonfmt)
12661269
p->opts[i].jsonfmt(p, params, "default", p->opts[i].arg);
12671270
json_object_end(params);
@@ -1598,9 +1601,19 @@ static struct command_result *handle_init(struct command *cmd,
15981601
if (!popt)
15991602
plugin_err(p, "lightningd specified unknown option '%s'?", name);
16001603

1601-
problem = popt->handle(p, json_strdup(tmpctx, buf, t+1), false, popt->arg);
1602-
if (problem)
1603-
plugin_err(p, "option '%s': %s", popt->name, problem);
1604+
if (popt->multi) {
1605+
size_t j;
1606+
const jsmntok_t *opt;
1607+
json_for_each_arr(j, opt, t+1) {
1608+
problem = popt->handle(p, json_strdup(tmpctx, buf, opt), false, popt->arg);
1609+
if (problem)
1610+
plugin_err(p, "option '%s': %s", popt->name, problem);
1611+
}
1612+
} else {
1613+
problem = popt->handle(p, json_strdup(tmpctx, buf, t+1), false, popt->arg);
1614+
if (problem)
1615+
plugin_err(p, "option '%s': %s", popt->name, problem);
1616+
}
16041617
}
16051618

16061619
if (p->init) {
@@ -2449,6 +2462,7 @@ static struct plugin *new_plugin(const tal_t *ctx,
24492462
o.depr_start = va_arg(ap, const char *);
24502463
o.depr_end = va_arg(ap, const char *);
24512464
o.dynamic = va_arg(ap, int); /* bool gets promoted! */
2465+
o.multi = va_arg(ap, int); /* bool gets promoted! */
24522466
tal_arr_expand(&p->opts, o);
24532467
}
24542468

plugins/libplugin.h

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

579579
/* Macro to define arguments */
580-
#define plugin_option_(name, type, description, set, jsonfmt, arg, dev_only, depr_start, depr_end, dynamic) \
580+
#define plugin_option_(name, type, description, set, jsonfmt, arg, dev_only, depr_start, depr_end, dynamic, multi) \
581581
(name), \
582582
(type), \
583583
(description), \
@@ -594,23 +594,27 @@ void *plugin_get_data_(struct plugin *plugin);
594594
(dev_only), \
595595
(depr_start), \
596596
(depr_end), \
597-
(dynamic)
597+
(dynamic), \
598+
(multi)
598599

599600
/* jsonfmt can be NULL, but then default won't be printed */
600601
#define plugin_option(name, type, description, set, jsonfmt, arg) \
601-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, false)
602+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, false, false)
602603

603604
#define plugin_option_dev(name, type, description, set, jsonfmt, arg) \
604-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, false)
605+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, false, false)
605606

606607
#define plugin_option_dev_dynamic(name, type, description, set, jsonfmt, arg) \
607-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, true)
608+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, true, false)
608609

609610
#define plugin_option_dynamic(name, type, description, set, jsonfmt, arg) \
610-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, true)
611+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, true, false)
611612

612613
#define plugin_option_deprecated(name, type, description, depr_start, depr_end, set, jsonfmt, arg) \
613-
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, (depr_start), (depr_end), false)
614+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, (depr_start), (depr_end), false, false)
615+
616+
#define plugin_option_multi(name, type, description, set, jsonfmt, arg) \
617+
plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, false, true)
614618

615619
/* Standard helpers */
616620
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)
@@ -221,6 +222,13 @@ static const char *init(struct command *init_cmd,
221222
plugin_log(p, LOG_DBG, "somearg = %s", tlp->somearg);
222223
tlp->somearg = tal_free(tlp->somearg);
223224

225+
for (size_t i = 0; i < tal_count(tlp->strarr); i++) {
226+
plugin_log(p, LOG_DBG, "multiopt#%zu = %s",
227+
i, tlp->strarr[i]);
228+
}
229+
if (tlp->somearg)
230+
plugin_log(p, LOG_DBG, "somearg = %s", tlp->somearg);
231+
224232
if (tlp->self_disable)
225233
return "Disabled via selfdisable option";
226234

@@ -287,6 +295,25 @@ static const struct plugin_notification notifs[] = { {
287295
}
288296
};
289297

298+
static char *set_multi_string_option(struct plugin *plugin,
299+
const char *arg,
300+
bool check_only,
301+
const char ***arr)
302+
{
303+
if (!check_only)
304+
tal_arr_expand(arr, tal_strdup(*arr, arg));
305+
return NULL;
306+
}
307+
308+
static bool multi_string_jsonfmt(struct plugin *plugin, struct json_stream *js, const char *fieldname, const char ***arr)
309+
{
310+
json_array_start(js, fieldname);
311+
for (size_t i = 0; i < tal_count(*arr); i++)
312+
json_add_string(js, NULL, (*arr)[i]);
313+
json_array_end(js);
314+
return true;
315+
}
316+
290317
int main(int argc, char *argv[])
291318
{
292319
setup_locale();
@@ -298,6 +325,7 @@ int main(int argc, char *argv[])
298325
tlp->self_disable = false;
299326
tlp->dont_shutdown = false;
300327
tlp->dynamic_opt = 7;
328+
tlp->strarr = tal_arr(tlp, const char *, 0);
301329

302330
plugin_main(argv, init, take(tlp), PLUGIN_RESTARTABLE, true, NULL,
303331
commands, ARRAY_SIZE(commands),
@@ -328,5 +356,11 @@ int main(int argc, char *argv[])
328356
"Set me!",
329357
set_dynamic, u32_jsonfmt,
330358
&tlp->dynamic_opt),
359+
plugin_option_multi("multiopt",
360+
"string",
361+
"Set me multiple times!",
362+
set_multi_string_option,
363+
multi_string_jsonfmt,
364+
&tlp->strarr),
331365
NULL);
332366
}

tests/test_plugin.py

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

16841684
del l1.daemon.opts["somearg-deprecated"]
1685+
l1.daemon.opts["multiopt"] = ['hello', 'world']
16851686
l1.start()
16861687

16871688
# Test that check works as expected.
@@ -1695,6 +1696,9 @@ def test_libplugin(node_factory):
16951696
# This works
16961697
assert l1.rpc.check('checkthis', key=["test_libplugin", "name"]) == {'command_to_check': 'checkthis'}
16971698

1699+
assert l1.daemon.is_in_log('plugin-test_libplugin: multiopt#0 = hello')
1700+
assert l1.daemon.is_in_log('plugin-test_libplugin: multiopt#1 = world')
1701+
16981702

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

0 commit comments

Comments
 (0)