Skip to content

Commit f69c4d6

Browse files
endothermicdevShahanaFarooqui
authored andcommitted
reckless-rpc: initial boilerplate
Trying a single command first - reckless-search to test launching a reckless process and processing the result.
1 parent 5073942 commit f69c4d6

File tree

2 files changed

+198
-1
lines changed

2 files changed

+198
-1
lines changed

plugins/Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ PLUGIN_FUNDER_HEADER := \
6363
plugins/funder_policy.h
6464
PLUGIN_FUNDER_OBJS := $(PLUGIN_FUNDER_SRC:.c=.o)
6565

66+
PLUGIN_RECKLESSRPC_SRC := plugins/recklessrpc.c
67+
PLUGIN_RECKLESSRPC_OBJS := $(PLUGIN_RECKLESSRPC_SRC:.c=.o)
68+
6669
PLUGIN_ALL_SRC := \
6770
$(PLUGIN_AUTOCLEAN_SRC) \
6871
$(PLUGIN_chanbackup_SRC) \
@@ -77,7 +80,8 @@ PLUGIN_ALL_SRC := \
7780
$(PLUGIN_PAY_LIB_SRC) \
7881
$(PLUGIN_PAY_SRC) \
7982
$(PLUGIN_SPENDER_SRC) \
80-
$(PLUGIN_RECOVER_SRC)
83+
$(PLUGIN_RECOVER_SRC) \
84+
$(PLUGIN_RECKLESSRPC_SRC)
8185

8286
PLUGIN_ALL_HEADER := \
8387
$(PLUGIN_PAY_HEADER) \
@@ -97,6 +101,7 @@ C_PLUGINS := \
97101
plugins/keysend \
98102
plugins/offers \
99103
plugins/pay \
104+
plugins/recklessrpc \
100105
plugins/recover \
101106
plugins/txprepare \
102107
plugins/cln-renepay \
@@ -216,6 +221,8 @@ plugins/funder: bitcoin/psbt.o common/psbt_open.o $(PLUGIN_FUNDER_OBJS) $(PLUGIN
216221

217222
plugins/recover: common/gossmap.o common/sciddir_or_pubkey.o common/fp16.o $(PLUGIN_RECOVER_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)
218223

224+
plugins/recklessrpc: $(PLUGIN_RECKLESSRPC_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)
225+
219226
# This covers all the low-level list RPCs which return simple arrays
220227
SQL_LISTRPCS := listchannels listforwards listhtlcs listinvoices listnodes listoffers listpeers listpeerchannels listclosedchannels listtransactions listsendpays bkpr-listaccountevents bkpr-listincome
221228
SQL_LISTRPCS_SCHEMAS := $(foreach l,$(SQL_LISTRPCS),doc/schemas/lightning-$l.json)

plugins/recklessrpc.c

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/* This plugin provides RPC access to the reckless standalone utility.
2+
*/
3+
4+
#include "config.h"
5+
#include <ccan/array_size/array_size.h>
6+
#include <ccan/io/io.h>
7+
#include <ccan/pipecmd/pipecmd.h>
8+
#include <ccan/tal/str/str.h>
9+
#include <common/json_param.h>
10+
#include <common/json_parse_simple.h>
11+
#include <common/json_stream.h>
12+
#include <errno.h>
13+
#include <plugins/libplugin.h>
14+
#include <signal.h>
15+
16+
static struct plugin *plugin;
17+
18+
struct reckless {
19+
struct command *cmd;
20+
int stdinfd;
21+
int stdoutfd;
22+
int stderrfd;
23+
char *stdoutbuf;
24+
char *stderrbuf;
25+
size_t stdout_read; /* running total */
26+
size_t stdout_new; /* new since last read */
27+
pid_t pid;
28+
};
29+
30+
static struct io_plan *read_more(struct io_conn *conn, struct reckless *rkls)
31+
{
32+
rkls->stdout_read += rkls->stdout_new;
33+
if (rkls->stdout_read == tal_count(rkls->stdoutbuf))
34+
tal_resize(&rkls->stdoutbuf, rkls->stdout_read * 2);
35+
return io_read_partial(conn, rkls->stdoutbuf + rkls->stdout_read,
36+
tal_count(rkls->stdoutbuf) - rkls->stdout_read,
37+
&rkls->stdout_new, read_more, rkls);
38+
}
39+
40+
static struct command_result *reckless_result(struct io_conn *conn,
41+
struct reckless *reckless)
42+
{
43+
struct json_stream *response;
44+
response = jsonrpc_stream_success(reckless->cmd);
45+
json_array_start(response, "result");
46+
const jsmntok_t *results, *result, *logs, *log;
47+
size_t i;
48+
jsmn_parser parser;
49+
jsmntok_t *toks;
50+
toks = tal_arr(reckless, jsmntok_t, 500);
51+
jsmn_init(&parser);
52+
if (jsmn_parse(&parser, reckless->stdoutbuf,
53+
strlen(reckless->stdoutbuf), toks, tal_count(toks)) <= 0) {
54+
plugin_log(plugin, LOG_DBG, "need more json tokens");
55+
assert(false);
56+
}
57+
58+
results = json_get_member(reckless->stdoutbuf, toks, "result");
59+
json_for_each_arr(i, result, results) {
60+
json_add_string(response,
61+
NULL,
62+
json_strdup(reckless, reckless->stdoutbuf,
63+
result));
64+
}
65+
json_array_end(response);
66+
json_array_start(response, "log");
67+
logs = json_get_member(reckless->stdoutbuf, toks, "log");
68+
json_for_each_arr(i, log, logs) {
69+
json_add_string(response,
70+
NULL,
71+
json_strdup(reckless, reckless->stdoutbuf,
72+
log));
73+
}
74+
json_array_end(response);
75+
76+
return command_finished(reckless->cmd, response);
77+
}
78+
79+
static void reckless_conn_finish(struct io_conn *conn,
80+
struct reckless *reckless)
81+
{
82+
/* FIXME: avoid EBADFD - leave stdin fd open? */
83+
if (errno && errno != 9)
84+
plugin_log(plugin, LOG_DBG, "err: %s", strerror(errno));
85+
reckless_result(conn, reckless);
86+
if (reckless->pid > 0) {
87+
int status;
88+
pid_t p;
89+
p = waitpid(reckless->pid, &status, WNOHANG);
90+
/* Did the reckless process exit? */
91+
if (p != reckless->pid && reckless->pid) {
92+
plugin_log(plugin, LOG_DBG, "reckless failed to exit "
93+
"(%i), killing now.", status);
94+
kill(reckless->pid, SIGKILL);
95+
}
96+
}
97+
plugin_log(plugin, LOG_DBG, "Reckless subprocess complete.");
98+
plugin_log(plugin, LOG_DBG, "output: %s", reckless->stdoutbuf);
99+
io_close(conn);
100+
tal_free(reckless);
101+
}
102+
103+
static struct io_plan *conn_init(struct io_conn *conn, struct reckless *rkls)
104+
{
105+
io_set_finish(conn, reckless_conn_finish, rkls);
106+
return read_more(conn, rkls);
107+
}
108+
109+
static struct command_result *reckless_call(struct command *cmd,
110+
const char *call)
111+
{
112+
if (!call)
113+
return command_fail(cmd, PLUGIN_ERROR, "invalid reckless call");
114+
char **my_call;
115+
my_call = tal_arrz(tmpctx, char *, 0);
116+
tal_arr_expand(&my_call, "reckless");
117+
tal_arr_expand(&my_call, "-v");
118+
tal_arr_expand(&my_call, "--json");
119+
tal_arr_expand(&my_call, "search");
120+
tal_arr_expand(&my_call, (char *) call);
121+
tal_arr_expand(&my_call, NULL);
122+
struct reckless *reckless;
123+
reckless = tal(NULL, struct reckless);
124+
reckless->cmd = cmd;
125+
reckless->stdoutbuf = tal_arrz(reckless, char, 1024);
126+
reckless->stderrbuf = tal_arrz(reckless, char, 1024);
127+
reckless->stdout_read = 0;
128+
reckless->stdout_new = 0;
129+
char * full_cmd;
130+
full_cmd = tal_fmt(tmpctx, "calling:");
131+
for (int i=0; i<tal_count(my_call); i++)
132+
tal_append_fmt(&full_cmd, " %s", my_call[i]);
133+
plugin_log(plugin, LOG_DBG, "%s", full_cmd);
134+
tal_free(full_cmd);
135+
136+
reckless->pid = pipecmdarr(&reckless->stdinfd, &reckless->stdoutfd,
137+
&reckless->stderrfd, my_call);
138+
139+
/* FIXME: fail if invalid pid*/
140+
io_new_conn(reckless, reckless->stdoutfd, conn_init, reckless);
141+
tal_free(my_call);
142+
return command_still_pending(cmd);
143+
}
144+
145+
static struct command_result *json_search(struct command *cmd,
146+
const char *buf,
147+
const jsmntok_t *params)
148+
{
149+
const char *search_target;
150+
/* Allow check command to evaluate. */
151+
if (!param(cmd, buf, params,
152+
p_req("plugin", param_string, &search_target),
153+
NULL))
154+
return command_param_failed();
155+
return reckless_call(cmd, search_target);
156+
}
157+
158+
static const char *init(struct plugin *p,
159+
const char *buf UNUSED,
160+
const jsmntok_t *config UNUSED)
161+
{
162+
plugin = p;
163+
plugin_log(p, LOG_DBG, "plugin initialized!");
164+
/* FIXME: TODO: scan for reckless config info */
165+
/* FIXME: TODO: assume default reckless config using ld config dets */
166+
return NULL;
167+
}
168+
169+
static const struct plugin_command commands[] = {
170+
{
171+
"reckless-search",
172+
json_search,
173+
},
174+
};
175+
176+
int main(int argc, char **argv)
177+
{
178+
setup_locale();
179+
180+
plugin_main(argv, init, NULL, PLUGIN_RESTARTABLE, true,
181+
NULL,
182+
commands, ARRAY_SIZE(commands),
183+
NULL, 0, /* Notifications */
184+
NULL, 0, /* Hooks */
185+
NULL, 0, /* Notification topics */
186+
NULL); /* plugin options */
187+
188+
return 0;
189+
}
190+

0 commit comments

Comments
 (0)