Browse Source

plugins: get usage from plugins (required unless deprecated_apis == True).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
fix-test_pay_direct-flake
Rusty Russell 6 years ago
parent
commit
53c0a21d2c
  1. 9
      doc/PLUGINS.md
  2. 24
      lightningd/plugin.c
  3. 7
      tests/test_plugin.py

9
doc/PLUGINS.md

@ -70,10 +70,12 @@ this example:
"rpcmethods": [
{
"name": "hello",
"usage": "[name]",
"description": "Returns a personalized greeting for {greeting} (set via options)."
},
{
"name": "gettime",
"usage": "",
"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."
}
@ -93,9 +95,10 @@ currently only string options are supported.*
The `rpcmethods` are methods that will be exposed via `lightningd`'s
JSON-RPC over Unix-Socket interface, just like the builtin
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
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
as the name was not previously registered. This includes both built-in
@ -149,11 +152,13 @@ called `hello` and `gettime`:
"rpcmethods": [
{
"name": "hello",
"usage": "[name]",
"description": "Returns a personalized greeting for {greeting} (set via options)."
},
{
"name": "gettime",
"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."
}
],

24
lightningd/plugin.c

@ -19,6 +19,7 @@
#include <lightningd/json.h>
#include <lightningd/lightningd.h>
#include <lightningd/notification.h>
#include <lightningd/options.h>
#include <lightningd/plugin_hook.h>
#include <signal.h>
#include <sys/stat.h>
@ -633,12 +634,14 @@ static bool plugin_rpcmethod_add(struct plugin *plugin,
const char *buffer,
const jsmntok_t *meth)
{
const jsmntok_t *nametok, *desctok, *longdesctok;
const jsmntok_t *nametok, *desctok, *longdesctok, *usagetok;
struct json_command *cmd;
const char *usage;
nametok = json_get_member(buffer, meth, "name");
desctok = json_get_member(buffer, meth, "description");
longdesctok = json_get_member(buffer, meth, "long_description");
usagetok = json_get_member(buffer, meth, "usage");
if (!nametok || nametok->type != JSMN_STRING) {
plugin_kill(plugin,
@ -662,6 +665,13 @@ static bool plugin_rpcmethod_add(struct plugin *plugin,
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->name = json_strdup(cmd, buffer, nametok);
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);
else
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->dispatch = plugin_rpcmethod_dispatch;
if (!jsonrpc_command_add(plugin->plugins->ld->jsonrpc, cmd,
/* FIXME */
"[params]")) {
if (!jsonrpc_command_add(plugin->plugins->ld->jsonrpc, cmd, usage)) {
log_broken(plugin->log,
"Could not register method \"%s\", a method with "
"that name is already registered",

7
tests/test_plugin.py

@ -1,6 +1,7 @@
from collections import OrderedDict
from fixtures import * # noqa: F401,F403
from lightning import RpcError
from utils import only_one
import pytest
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']]
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
# correctly via the notifications plugin->lightningd
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'):
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…
Cancel
Save