reckless-rpc: initial boilerplate

Trying a single command first - reckless-search to test
launching a reckless process and processing the result.
This commit is contained in:
Alex Myers
2024-07-08 14:43:07 -05:00
committed by ShahanaFarooqui
parent 5073942eef
commit f69c4d6385
2 changed files with 198 additions and 1 deletions

View File

@@ -63,6 +63,9 @@ PLUGIN_FUNDER_HEADER := \
plugins/funder_policy.h
PLUGIN_FUNDER_OBJS := $(PLUGIN_FUNDER_SRC:.c=.o)
PLUGIN_RECKLESSRPC_SRC := plugins/recklessrpc.c
PLUGIN_RECKLESSRPC_OBJS := $(PLUGIN_RECKLESSRPC_SRC:.c=.o)
PLUGIN_ALL_SRC := \
$(PLUGIN_AUTOCLEAN_SRC) \
$(PLUGIN_chanbackup_SRC) \
@@ -77,7 +80,8 @@ PLUGIN_ALL_SRC := \
$(PLUGIN_PAY_LIB_SRC) \
$(PLUGIN_PAY_SRC) \
$(PLUGIN_SPENDER_SRC) \
$(PLUGIN_RECOVER_SRC)
$(PLUGIN_RECOVER_SRC) \
$(PLUGIN_RECKLESSRPC_SRC)
PLUGIN_ALL_HEADER := \
$(PLUGIN_PAY_HEADER) \
@@ -97,6 +101,7 @@ C_PLUGINS := \
plugins/keysend \
plugins/offers \
plugins/pay \
plugins/recklessrpc \
plugins/recover \
plugins/txprepare \
plugins/cln-renepay \
@@ -216,6 +221,8 @@ plugins/funder: bitcoin/psbt.o common/psbt_open.o $(PLUGIN_FUNDER_OBJS) $(PLUGIN
plugins/recover: common/gossmap.o common/sciddir_or_pubkey.o common/fp16.o $(PLUGIN_RECOVER_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)
plugins/recklessrpc: $(PLUGIN_RECKLESSRPC_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)
# This covers all the low-level list RPCs which return simple arrays
SQL_LISTRPCS := listchannels listforwards listhtlcs listinvoices listnodes listoffers listpeers listpeerchannels listclosedchannels listtransactions listsendpays bkpr-listaccountevents bkpr-listincome
SQL_LISTRPCS_SCHEMAS := $(foreach l,$(SQL_LISTRPCS),doc/schemas/lightning-$l.json)

190
plugins/recklessrpc.c Normal file
View File

@@ -0,0 +1,190 @@
/* This plugin provides RPC access to the reckless standalone utility.
*/
#include "config.h"
#include <ccan/array_size/array_size.h>
#include <ccan/io/io.h>
#include <ccan/pipecmd/pipecmd.h>
#include <ccan/tal/str/str.h>
#include <common/json_param.h>
#include <common/json_parse_simple.h>
#include <common/json_stream.h>
#include <errno.h>
#include <plugins/libplugin.h>
#include <signal.h>
static struct plugin *plugin;
struct reckless {
struct command *cmd;
int stdinfd;
int stdoutfd;
int stderrfd;
char *stdoutbuf;
char *stderrbuf;
size_t stdout_read; /* running total */
size_t stdout_new; /* new since last read */
pid_t pid;
};
static struct io_plan *read_more(struct io_conn *conn, struct reckless *rkls)
{
rkls->stdout_read += rkls->stdout_new;
if (rkls->stdout_read == tal_count(rkls->stdoutbuf))
tal_resize(&rkls->stdoutbuf, rkls->stdout_read * 2);
return io_read_partial(conn, rkls->stdoutbuf + rkls->stdout_read,
tal_count(rkls->stdoutbuf) - rkls->stdout_read,
&rkls->stdout_new, read_more, rkls);
}
static struct command_result *reckless_result(struct io_conn *conn,
struct reckless *reckless)
{
struct json_stream *response;
response = jsonrpc_stream_success(reckless->cmd);
json_array_start(response, "result");
const jsmntok_t *results, *result, *logs, *log;
size_t i;
jsmn_parser parser;
jsmntok_t *toks;
toks = tal_arr(reckless, jsmntok_t, 500);
jsmn_init(&parser);
if (jsmn_parse(&parser, reckless->stdoutbuf,
strlen(reckless->stdoutbuf), toks, tal_count(toks)) <= 0) {
plugin_log(plugin, LOG_DBG, "need more json tokens");
assert(false);
}
results = json_get_member(reckless->stdoutbuf, toks, "result");
json_for_each_arr(i, result, results) {
json_add_string(response,
NULL,
json_strdup(reckless, reckless->stdoutbuf,
result));
}
json_array_end(response);
json_array_start(response, "log");
logs = json_get_member(reckless->stdoutbuf, toks, "log");
json_for_each_arr(i, log, logs) {
json_add_string(response,
NULL,
json_strdup(reckless, reckless->stdoutbuf,
log));
}
json_array_end(response);
return command_finished(reckless->cmd, response);
}
static void reckless_conn_finish(struct io_conn *conn,
struct reckless *reckless)
{
/* FIXME: avoid EBADFD - leave stdin fd open? */
if (errno && errno != 9)
plugin_log(plugin, LOG_DBG, "err: %s", strerror(errno));
reckless_result(conn, reckless);
if (reckless->pid > 0) {
int status;
pid_t p;
p = waitpid(reckless->pid, &status, WNOHANG);
/* Did the reckless process exit? */
if (p != reckless->pid && reckless->pid) {
plugin_log(plugin, LOG_DBG, "reckless failed to exit "
"(%i), killing now.", status);
kill(reckless->pid, SIGKILL);
}
}
plugin_log(plugin, LOG_DBG, "Reckless subprocess complete.");
plugin_log(plugin, LOG_DBG, "output: %s", reckless->stdoutbuf);
io_close(conn);
tal_free(reckless);
}
static struct io_plan *conn_init(struct io_conn *conn, struct reckless *rkls)
{
io_set_finish(conn, reckless_conn_finish, rkls);
return read_more(conn, rkls);
}
static struct command_result *reckless_call(struct command *cmd,
const char *call)
{
if (!call)
return command_fail(cmd, PLUGIN_ERROR, "invalid reckless call");
char **my_call;
my_call = tal_arrz(tmpctx, char *, 0);
tal_arr_expand(&my_call, "reckless");
tal_arr_expand(&my_call, "-v");
tal_arr_expand(&my_call, "--json");
tal_arr_expand(&my_call, "search");
tal_arr_expand(&my_call, (char *) call);
tal_arr_expand(&my_call, NULL);
struct reckless *reckless;
reckless = tal(NULL, struct reckless);
reckless->cmd = cmd;
reckless->stdoutbuf = tal_arrz(reckless, char, 1024);
reckless->stderrbuf = tal_arrz(reckless, char, 1024);
reckless->stdout_read = 0;
reckless->stdout_new = 0;
char * full_cmd;
full_cmd = tal_fmt(tmpctx, "calling:");
for (int i=0; i<tal_count(my_call); i++)
tal_append_fmt(&full_cmd, " %s", my_call[i]);
plugin_log(plugin, LOG_DBG, "%s", full_cmd);
tal_free(full_cmd);
reckless->pid = pipecmdarr(&reckless->stdinfd, &reckless->stdoutfd,
&reckless->stderrfd, my_call);
/* FIXME: fail if invalid pid*/
io_new_conn(reckless, reckless->stdoutfd, conn_init, reckless);
tal_free(my_call);
return command_still_pending(cmd);
}
static struct command_result *json_search(struct command *cmd,
const char *buf,
const jsmntok_t *params)
{
const char *search_target;
/* Allow check command to evaluate. */
if (!param(cmd, buf, params,
p_req("plugin", param_string, &search_target),
NULL))
return command_param_failed();
return reckless_call(cmd, search_target);
}
static const char *init(struct plugin *p,
const char *buf UNUSED,
const jsmntok_t *config UNUSED)
{
plugin = p;
plugin_log(p, LOG_DBG, "plugin initialized!");
/* FIXME: TODO: scan for reckless config info */
/* FIXME: TODO: assume default reckless config using ld config dets */
return NULL;
}
static const struct plugin_command commands[] = {
{
"reckless-search",
json_search,
},
};
int main(int argc, char **argv)
{
setup_locale();
plugin_main(argv, init, NULL, PLUGIN_RESTARTABLE, true,
NULL,
commands, ARRAY_SIZE(commands),
NULL, 0, /* Notifications */
NULL, 0, /* Hooks */
NULL, 0, /* Notification topics */
NULL); /* plugin options */
return 0;
}