Allow dynamic option in python plugin

This commit is contained in:
Erik De Smedt 2023-12-14 11:22:44 +01:00 committed by Christian Decker
parent b6c486c2ba
commit 557b5fee46
3 changed files with 38 additions and 6 deletions

View file

@ -220,7 +220,8 @@ class Plugin(object):
invoice_features: Optional[Union[int, str, bytes]] = None,
custom_msgs: Optional[List[int]] = None):
self.methods = {
'init': Method('init', self._init, MethodType.RPCMETHOD)
'init': Method('init', self._init, MethodType.RPCMETHOD),
'setconfig': Method('setconfig', self._set_config, MethodType.RPCMETHOD)
}
self.options: Dict[str, Dict[str, Any]] = {}
@ -389,7 +390,8 @@ class Plugin(object):
def add_option(self, name: str, default: Optional[str],
description: Optional[str],
opt_type: str = "string", deprecated: bool = False,
multi: bool = False) -> None:
multi: bool = False,
dynamic=False) -> None:
"""Add an option that we'd like to register with lightningd.
Needs to be called before `Plugin.run`, otherwise we might not
@ -414,10 +416,11 @@ class Plugin(object):
'value': None,
'multi': multi,
'deprecated': deprecated,
"dynamic": dynamic
}
def add_flag_option(self, name: str, description: str,
deprecated: bool = False) -> None:
deprecated: bool = False, dynamic: bool = False) -> None:
"""Add a flag option that we'd like to register with lightningd.
Needs to be called before `Plugin.run`, otherwise we might not
@ -425,7 +428,7 @@ class Plugin(object):
"""
self.add_option(name, None, description, opt_type="flag",
deprecated=deprecated)
deprecated=deprecated, dynamic=dynamic)
def add_notification_topic(self, topic: str):
"""Announce that the plugin will emit notifications for the topic.
@ -784,7 +787,7 @@ class Plugin(object):
""")
for method in self.methods.values():
if method.name in ['init', 'getmanifest']:
if method.name in ['init', 'getmanifest', 'setconfig']:
# Skip internal methods provided by all plugins
continue
@ -864,7 +867,7 @@ class Plugin(object):
hooks = []
for method in self.methods.values():
# Skip the builtin ones, they don't get reported
if method.name in ['getmanifest', 'init']:
if method.name in ['getmanifest', 'init', 'setconfig']:
continue
if method.mtype == MethodType.HOOK:
@ -970,6 +973,12 @@ class Plugin(object):
return self._exec_func(self.child_init, request)
return None
def _set_config(self, **_) -> None:
"""Called when the value of a dynamic option is changed
For now we don't do anything.
"""
pass
class PluginStream(object):
"""Sink that turns everything that is written to it into a notification.

12
tests/plugins/dynamic_option.py Executable file
View file

@ -0,0 +1,12 @@
#!/usr/bin/env python3
from pyln.client import Plugin
plugin = Plugin()
plugin.add_option(
name="test-dynamic-config",
description="A config option which can be changed at run-time",
default="initial",
dynamic=True)
plugin.run()

View file

@ -4258,6 +4258,17 @@ def test_all_subscription(node_factory, directory):
assert not l2.daemon.is_in_log(f'.*test_libplugin: all: connect.*')
def test_dynamic_option_python_plugin(node_factory):
plugin = os.path.join(os.getcwd(), "tests/plugins/dynamic_option.py")
ln = node_factory.get_node(options={"plugin": plugin})
result = ln.rpc.listconfigs("test-dynamic-config")
assert result["configs"]["test-dynamic-config"]["value_str"] == "initial"
result = ln.rpc.setconfig("test-dynamic-config", "changed")
assert result["config"]["value_str"] == "changed"
def test_renepay_not_important(node_factory):
# I mean, it's *important*, it's just not "mission-critical" just yet!
l1 = node_factory.get_node(options={'allow-deprecated-apis': True})