From 66dc1444a2dd6aafaca4717523848b01a482ea3f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 16 Mar 2022 13:36:18 +1030 Subject: [PATCH 1/2] commando: make custommsg hook async. Otherwise it blocks everything while it's working, which can be a while for a slow command. Fixes: #347 Signed-off-by: Rusty Russell --- commando/commando.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commando/commando.py b/commando/commando.py index c9a65dacb..659dfc415 100755 --- a/commando/commando.py +++ b/commando/commando.py @@ -161,8 +161,8 @@ def try_command(plugin, peer_id, idnum, method, params, runestr): send_result(plugin, peer_id, idnum, res) -@plugin.hook('custommsg') -def on_custommsg(peer_id, payload, plugin, **kwargs): +@plugin.async_hook('custommsg') +def on_custommsg(peer_id, payload, plugin, request, **kwargs): pbytes = bytes.fromhex(payload) mtype = int.from_bytes(pbytes[:2], "big") idnum = int.from_bytes(pbytes[2:10], "big") @@ -194,7 +194,7 @@ def on_custommsg(peer_id, payload, plugin, **kwargs): else: # Pass through result finished.req.set_result(ret['result']) - return {'result': 'continue'} + request.set_result({'result': 'continue'}) @plugin.async_method("commando") From 43f296c924511b697796c60548686e89bfa7259e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 17 Mar 2022 14:02:18 +1030 Subject: [PATCH 2/2] commando: actually do RPC dispatch async. We use multiprocessing for this, because the pyln-client RPC command api doesn't support async. Signed-off-by: Rusty Russell --- commando/commando.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/commando/commando.py b/commando/commando.py index 659dfc415..7358e8ded 100755 --- a/commando/commando.py +++ b/commando/commando.py @@ -26,6 +26,7 @@ import secrets import string import runes # type: ignore +import multiprocessing from typing import Dict, Tuple, Optional plugin = Plugin() @@ -132,6 +133,15 @@ def do_cacherune(plugin, peer_id, runestr): return {'result': {'rune': runestr}} +def command_run(plugin, peer_id, idnum, method, params): + """Function to run a command and write the result""" + try: + res = {'result': plugin.rpc.call(method, params)} + except RpcError as e: + res = {'error': e.error} + send_result(plugin, peer_id, idnum, res) + + def try_command(plugin, peer_id, idnum, method, params, runestr): """Run an arbitrary command and message back the result""" # You can always set your rune, even if *that rune* wouldn't @@ -153,10 +163,11 @@ def try_command(plugin, peer_id, idnum, method, params, runestr): else: res = {'error': 'FIXME: Refusing to call inside ourselves'} else: - try: - res = {'result': plugin.rpc.call(method, params)} - except RpcError as e: - res = {'error': e.error} + # The subprocess does send_result itself: pyln-client doesn't + # support async RPC yet. + multiprocessing.Process(target=command_run, + args=(plugin, peer_id, idnum, method, params)).start() + return send_result(plugin, peer_id, idnum, res)