mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
plugins: get usage from plugins (required unless deprecated_apis == True).
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
a8d1588154
commit
53c0a21d2c
3 changed files with 34 additions and 6 deletions
|
@ -70,10 +70,12 @@ this example:
|
||||||
"rpcmethods": [
|
"rpcmethods": [
|
||||||
{
|
{
|
||||||
"name": "hello",
|
"name": "hello",
|
||||||
|
"usage": "[name]",
|
||||||
"description": "Returns a personalized greeting for {greeting} (set via options)."
|
"description": "Returns a personalized greeting for {greeting} (set via options)."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "gettime",
|
"name": "gettime",
|
||||||
|
"usage": "",
|
||||||
"description": "Returns the current time in {timezone}",
|
"description": "Returns the current time in {timezone}",
|
||||||
"long_description": "Returns the current time in the timezone that is given as the only parameter.\nThis description may be quite long and is allowed to span multiple lines."
|
"long_description": "Returns the current time in the timezone that is given as the only parameter.\nThis description may be quite long and is allowed to span multiple lines."
|
||||||
}
|
}
|
||||||
|
@ -93,9 +95,10 @@ currently only string options are supported.*
|
||||||
The `rpcmethods` are methods that will be exposed via `lightningd`'s
|
The `rpcmethods` are methods that will be exposed via `lightningd`'s
|
||||||
JSON-RPC over Unix-Socket interface, just like the builtin
|
JSON-RPC over Unix-Socket interface, just like the builtin
|
||||||
commands. Any parameters given to the JSON-RPC calls will be passed
|
commands. Any parameters given to the JSON-RPC calls will be passed
|
||||||
through verbatim. Notice that the `name` and the `description` fields
|
through verbatim. Notice that the `name`, `description` and `usage` fields
|
||||||
are mandatory, while the `long_description` can be omitted (it'll be
|
are mandatory, while the `long_description` can be omitted (it'll be
|
||||||
set to `description` if it was not provided).
|
set to `description` if it was not provided). `usage` should surround optional
|
||||||
|
parameter names in `[]`.
|
||||||
|
|
||||||
Plugins are free to register any `name` for their `rpcmethod` as long
|
Plugins are free to register any `name` for their `rpcmethod` as long
|
||||||
as the name was not previously registered. This includes both built-in
|
as the name was not previously registered. This includes both built-in
|
||||||
|
@ -149,11 +152,13 @@ called `hello` and `gettime`:
|
||||||
"rpcmethods": [
|
"rpcmethods": [
|
||||||
{
|
{
|
||||||
"name": "hello",
|
"name": "hello",
|
||||||
|
"usage": "[name]",
|
||||||
"description": "Returns a personalized greeting for {greeting} (set via options)."
|
"description": "Returns a personalized greeting for {greeting} (set via options)."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "gettime",
|
"name": "gettime",
|
||||||
"description": "Returns the current time in {timezone}",
|
"description": "Returns the current time in {timezone}",
|
||||||
|
"usage": "",
|
||||||
"long_description": "Returns the current time in the timezone that is given as the only parameter.\nThis description may be quite long and is allowed to span multiple lines."
|
"long_description": "Returns the current time in the timezone that is given as the only parameter.\nThis description may be quite long and is allowed to span multiple lines."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <lightningd/json.h>
|
#include <lightningd/json.h>
|
||||||
#include <lightningd/lightningd.h>
|
#include <lightningd/lightningd.h>
|
||||||
#include <lightningd/notification.h>
|
#include <lightningd/notification.h>
|
||||||
|
#include <lightningd/options.h>
|
||||||
#include <lightningd/plugin_hook.h>
|
#include <lightningd/plugin_hook.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -633,12 +634,14 @@ static bool plugin_rpcmethod_add(struct plugin *plugin,
|
||||||
const char *buffer,
|
const char *buffer,
|
||||||
const jsmntok_t *meth)
|
const jsmntok_t *meth)
|
||||||
{
|
{
|
||||||
const jsmntok_t *nametok, *desctok, *longdesctok;
|
const jsmntok_t *nametok, *desctok, *longdesctok, *usagetok;
|
||||||
struct json_command *cmd;
|
struct json_command *cmd;
|
||||||
|
const char *usage;
|
||||||
|
|
||||||
nametok = json_get_member(buffer, meth, "name");
|
nametok = json_get_member(buffer, meth, "name");
|
||||||
desctok = json_get_member(buffer, meth, "description");
|
desctok = json_get_member(buffer, meth, "description");
|
||||||
longdesctok = json_get_member(buffer, meth, "long_description");
|
longdesctok = json_get_member(buffer, meth, "long_description");
|
||||||
|
usagetok = json_get_member(buffer, meth, "usage");
|
||||||
|
|
||||||
if (!nametok || nametok->type != JSMN_STRING) {
|
if (!nametok || nametok->type != JSMN_STRING) {
|
||||||
plugin_kill(plugin,
|
plugin_kill(plugin,
|
||||||
|
@ -662,6 +665,13 @@ static bool plugin_rpcmethod_add(struct plugin *plugin,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (usagetok && usagetok->type != JSMN_STRING) {
|
||||||
|
plugin_kill(plugin,
|
||||||
|
"\"usage\" is not a string: %.*s",
|
||||||
|
meth->end - meth->start, buffer + meth->start);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cmd = notleak(tal(plugin, struct json_command));
|
cmd = notleak(tal(plugin, struct json_command));
|
||||||
cmd->name = json_strdup(cmd, buffer, nametok);
|
cmd->name = json_strdup(cmd, buffer, nametok);
|
||||||
cmd->description = json_strdup(cmd, buffer, desctok);
|
cmd->description = json_strdup(cmd, buffer, desctok);
|
||||||
|
@ -669,12 +679,18 @@ static bool plugin_rpcmethod_add(struct plugin *plugin,
|
||||||
cmd->verbose = json_strdup(cmd, buffer, longdesctok);
|
cmd->verbose = json_strdup(cmd, buffer, longdesctok);
|
||||||
else
|
else
|
||||||
cmd->verbose = cmd->description;
|
cmd->verbose = cmd->description;
|
||||||
|
if (usagetok)
|
||||||
|
usage = json_strdup(tmpctx, buffer, usagetok);
|
||||||
|
else if (!deprecated_apis) {
|
||||||
|
plugin_kill(plugin,
|
||||||
|
"\"usage\" not provided by plugin");
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
usage = "[params]";
|
||||||
|
|
||||||
cmd->deprecated = false;
|
cmd->deprecated = false;
|
||||||
cmd->dispatch = plugin_rpcmethod_dispatch;
|
cmd->dispatch = plugin_rpcmethod_dispatch;
|
||||||
if (!jsonrpc_command_add(plugin->plugins->ld->jsonrpc, cmd,
|
if (!jsonrpc_command_add(plugin->plugins->ld->jsonrpc, cmd, usage)) {
|
||||||
/* FIXME */
|
|
||||||
"[params]")) {
|
|
||||||
log_broken(plugin->log,
|
log_broken(plugin->log,
|
||||||
"Could not register method \"%s\", a method with "
|
"Could not register method \"%s\", a method with "
|
||||||
"that name is already registered",
|
"that name is already registered",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from fixtures import * # noqa: F401,F403
|
from fixtures import * # noqa: F401,F403
|
||||||
from lightning import RpcError
|
from lightning import RpcError
|
||||||
|
from utils import only_one
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -47,6 +48,8 @@ def test_rpc_passthrough(node_factory):
|
||||||
cmd = [hlp for hlp in n.rpc.help()['help'] if 'hello' in hlp['command']]
|
cmd = [hlp for hlp in n.rpc.help()['help'] if 'hello' in hlp['command']]
|
||||||
assert(len(cmd) == 1)
|
assert(len(cmd) == 1)
|
||||||
|
|
||||||
|
# Make sure usage message is present.
|
||||||
|
assert only_one(n.rpc.help('hello')['help'])['command'] == 'hello [name]'
|
||||||
# While we're at it, let's check that helloworld.py is logging
|
# While we're at it, let's check that helloworld.py is logging
|
||||||
# correctly via the notifications plugin->lightningd
|
# correctly via the notifications plugin->lightningd
|
||||||
assert n.daemon.is_in_log('Plugin helloworld.py initialized')
|
assert n.daemon.is_in_log('Plugin helloworld.py initialized')
|
||||||
|
@ -119,3 +122,7 @@ def test_pay_plugin(node_factory):
|
||||||
|
|
||||||
with pytest.raises(RpcError, match=r'missing required parameter'):
|
with pytest.raises(RpcError, match=r'missing required parameter'):
|
||||||
l1.rpc.call('pay')
|
l1.rpc.call('pay')
|
||||||
|
|
||||||
|
# Make sure usage messages are present.
|
||||||
|
assert only_one(l1.rpc.help('pay')['help'])['command'] == 'pay bolt11 [msatoshi] [description] [riskfactor] [maxfeepercent] [retry_for] [maxdelay] [exemptfee]'
|
||||||
|
assert only_one(l1.rpc.help('paystatus')['help'])['command'] == 'paystatus [bolt11]'
|
||||||
|
|
Loading…
Add table
Reference in a new issue