Skip to content

Commit 557b5fe

Browse files
ErikDeSmedtcdecker
authored andcommitted
Allow dynamic option in python plugin
1 parent b6c486c commit 557b5fe

File tree

3 files changed

+38
-6
lines changed

3 files changed

+38
-6
lines changed

contrib/pyln-client/pyln/client/plugin.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ def __init__(self, stdout: Optional[io.TextIOBase] = None,
220220
invoice_features: Optional[Union[int, str, bytes]] = None,
221221
custom_msgs: Optional[List[int]] = None):
222222
self.methods = {
223-
'init': Method('init', self._init, MethodType.RPCMETHOD)
223+
'init': Method('init', self._init, MethodType.RPCMETHOD),
224+
'setconfig': Method('setconfig', self._set_config, MethodType.RPCMETHOD)
224225
}
225226

226227
self.options: Dict[str, Dict[str, Any]] = {}
@@ -389,7 +390,8 @@ def decorator(f: Callable[..., None]) -> Callable[..., None]:
389390
def add_option(self, name: str, default: Optional[str],
390391
description: Optional[str],
391392
opt_type: str = "string", deprecated: bool = False,
392-
multi: bool = False) -> None:
393+
multi: bool = False,
394+
dynamic=False) -> None:
393395
"""Add an option that we'd like to register with lightningd.
394396
395397
Needs to be called before `Plugin.run`, otherwise we might not
@@ -414,18 +416,19 @@ def add_option(self, name: str, default: Optional[str],
414416
'value': None,
415417
'multi': multi,
416418
'deprecated': deprecated,
419+
"dynamic": dynamic
417420
}
418421

419422
def add_flag_option(self, name: str, description: str,
420-
deprecated: bool = False) -> None:
423+
deprecated: bool = False, dynamic: bool = False) -> None:
421424
"""Add a flag option that we'd like to register with lightningd.
422425
423426
Needs to be called before `Plugin.run`, otherwise we might not
424427
end up getting it set.
425428
426429
"""
427430
self.add_option(name, None, description, opt_type="flag",
428-
deprecated=deprecated)
431+
deprecated=deprecated, dynamic=dynamic)
429432

430433
def add_notification_topic(self, topic: str):
431434
"""Announce that the plugin will emit notifications for the topic.
@@ -784,7 +787,7 @@ def print_usage(self):
784787
""")
785788

786789
for method in self.methods.values():
787-
if method.name in ['init', 'getmanifest']:
790+
if method.name in ['init', 'getmanifest', 'setconfig']:
788791
# Skip internal methods provided by all plugins
789792
continue
790793

@@ -864,7 +867,7 @@ def _getmanifest(self, **kwargs) -> JSONType:
864867
hooks = []
865868
for method in self.methods.values():
866869
# Skip the builtin ones, they don't get reported
867-
if method.name in ['getmanifest', 'init']:
870+
if method.name in ['getmanifest', 'init', 'setconfig']:
868871
continue
869872

870873
if method.mtype == MethodType.HOOK:
@@ -970,6 +973,12 @@ def verify_bool(d: Dict[str, JSONType], key: str) -> bool:
970973
return self._exec_func(self.child_init, request)
971974
return None
972975

976+
def _set_config(self, **_) -> None:
977+
"""Called when the value of a dynamic option is changed
978+
For now we don't do anything.
979+
"""
980+
pass
981+
973982

974983
class PluginStream(object):
975984
"""Sink that turns everything that is written to it into a notification.

tests/plugins/dynamic_option.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env python3
2+
from pyln.client import Plugin
3+
4+
plugin = Plugin()
5+
6+
plugin.add_option(
7+
name="test-dynamic-config",
8+
description="A config option which can be changed at run-time",
9+
default="initial",
10+
dynamic=True)
11+
12+
plugin.run()

tests/test_plugin.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4258,6 +4258,17 @@ def test_all_subscription(node_factory, directory):
42584258
assert not l2.daemon.is_in_log(f'.*test_libplugin: all: connect.*')
42594259

42604260

4261+
def test_dynamic_option_python_plugin(node_factory):
4262+
plugin = os.path.join(os.getcwd(), "tests/plugins/dynamic_option.py")
4263+
ln = node_factory.get_node(options={"plugin": plugin})
4264+
result = ln.rpc.listconfigs("test-dynamic-config")
4265+
4266+
assert result["configs"]["test-dynamic-config"]["value_str"] == "initial"
4267+
4268+
result = ln.rpc.setconfig("test-dynamic-config", "changed")
4269+
assert result["config"]["value_str"] == "changed"
4270+
4271+
42614272
def test_renepay_not_important(node_factory):
42624273
# I mean, it's *important*, it's just not "mission-critical" just yet!
42634274
l1 = node_factory.get_node(options={'allow-deprecated-apis': True})

0 commit comments

Comments
 (0)