|
@ -37,6 +37,17 @@ bool deprecated_apis; |
|
|
|
|
|
|
|
|
extern const struct chainparams *chainparams; |
|
|
extern const struct chainparams *chainparams; |
|
|
|
|
|
|
|
|
|
|
|
struct plugin { |
|
|
|
|
|
enum plugin_restartability restartability; |
|
|
|
|
|
const struct plugin_command *commands; |
|
|
|
|
|
size_t num_commands; |
|
|
|
|
|
const struct plugin_notification *notif_subs; |
|
|
|
|
|
size_t num_notif_subs; |
|
|
|
|
|
const struct plugin_hook *hook_subs; |
|
|
|
|
|
size_t num_hook_subs; |
|
|
|
|
|
struct plugin_option *opts; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
struct plugin_timer { |
|
|
struct plugin_timer { |
|
|
struct timer timer; |
|
|
struct timer timer; |
|
|
struct command_result *(*cb)(void); |
|
|
struct command_result *(*cb)(void); |
|
@ -484,53 +495,47 @@ send_outreq_(struct command *cmd, |
|
|
|
|
|
|
|
|
static struct command_result * |
|
|
static struct command_result * |
|
|
handle_getmanifest(struct command *getmanifest_cmd, |
|
|
handle_getmanifest(struct command *getmanifest_cmd, |
|
|
const struct plugin_command *commands, |
|
|
struct plugin *p) |
|
|
size_t num_commands, |
|
|
|
|
|
const struct plugin_notification *notif_subs, |
|
|
|
|
|
size_t num_notif_subs, |
|
|
|
|
|
const struct plugin_hook *hook_subs, |
|
|
|
|
|
size_t num_hook_subs, |
|
|
|
|
|
const struct plugin_option *opts, |
|
|
|
|
|
const enum plugin_restartability restartability) |
|
|
|
|
|
{ |
|
|
{ |
|
|
struct json_out *params = json_out_new(tmpctx); |
|
|
struct json_out *params = json_out_new(tmpctx); |
|
|
|
|
|
|
|
|
json_out_start(params, NULL, '{'); |
|
|
json_out_start(params, NULL, '{'); |
|
|
json_out_start(params, "options", '['); |
|
|
json_out_start(params, "options", '['); |
|
|
for (size_t i = 0; i < tal_count(opts); i++) { |
|
|
for (size_t i = 0; i < tal_count(p->opts); i++) { |
|
|
json_out_start(params, NULL, '{'); |
|
|
json_out_start(params, NULL, '{'); |
|
|
json_out_addstr(params, "name", opts[i].name); |
|
|
json_out_addstr(params, "name", p->opts[i].name); |
|
|
json_out_addstr(params, "type", opts[i].type); |
|
|
json_out_addstr(params, "type", p->opts[i].type); |
|
|
json_out_addstr(params, "description", opts[i].description); |
|
|
json_out_addstr(params, "description", p->opts[i].description); |
|
|
json_out_end(params, '}'); |
|
|
json_out_end(params, '}'); |
|
|
} |
|
|
} |
|
|
json_out_end(params, ']'); |
|
|
json_out_end(params, ']'); |
|
|
|
|
|
|
|
|
json_out_start(params, "rpcmethods", '['); |
|
|
json_out_start(params, "rpcmethods", '['); |
|
|
for (size_t i = 0; i < num_commands; i++) { |
|
|
for (size_t i = 0; i < p->num_commands; i++) { |
|
|
json_out_start(params, NULL, '{'); |
|
|
json_out_start(params, NULL, '{'); |
|
|
json_out_addstr(params, "name", commands[i].name); |
|
|
json_out_addstr(params, "name", p->commands[i].name); |
|
|
json_out_addstr(params, "usage", |
|
|
json_out_addstr(params, "usage", |
|
|
strmap_get(&usagemap, commands[i].name)); |
|
|
strmap_get(&usagemap, p->commands[i].name)); |
|
|
json_out_addstr(params, "description", commands[i].description); |
|
|
json_out_addstr(params, "description", p->commands[i].description); |
|
|
if (commands[i].long_description) |
|
|
if (p->commands[i].long_description) |
|
|
json_out_addstr(params, "long_description", |
|
|
json_out_addstr(params, "long_description", |
|
|
commands[i].long_description); |
|
|
p->commands[i].long_description); |
|
|
json_out_end(params, '}'); |
|
|
json_out_end(params, '}'); |
|
|
} |
|
|
} |
|
|
json_out_end(params, ']'); |
|
|
json_out_end(params, ']'); |
|
|
|
|
|
|
|
|
json_out_start(params, "subscriptions", '['); |
|
|
json_out_start(params, "subscriptions", '['); |
|
|
for (size_t i = 0; i < num_notif_subs; i++) |
|
|
for (size_t i = 0; i < p->num_notif_subs; i++) |
|
|
json_out_addstr(params, NULL, notif_subs[i].name); |
|
|
json_out_addstr(params, NULL, p->notif_subs[i].name); |
|
|
json_out_end(params, ']'); |
|
|
json_out_end(params, ']'); |
|
|
|
|
|
|
|
|
json_out_start(params, "hooks", '['); |
|
|
json_out_start(params, "hooks", '['); |
|
|
for (size_t i = 0; i < num_hook_subs; i++) |
|
|
for (size_t i = 0; i < p->num_hook_subs; i++) |
|
|
json_out_addstr(params, NULL, hook_subs[i].name); |
|
|
json_out_addstr(params, NULL, p->hook_subs[i].name); |
|
|
json_out_end(params, ']'); |
|
|
json_out_end(params, ']'); |
|
|
|
|
|
|
|
|
json_out_addstr(params, "dynamic", restartability == PLUGIN_RESTARTABLE ? "true" : "false"); |
|
|
json_out_addstr(params, "dynamic", |
|
|
|
|
|
p->restartability == PLUGIN_RESTARTABLE ? "true" : "false"); |
|
|
json_out_end(params, '}'); |
|
|
json_out_end(params, '}'); |
|
|
json_out_finished(params); |
|
|
json_out_finished(params); |
|
|
|
|
|
|
|
@ -629,12 +634,7 @@ char *charp_option(const char *arg, char **p) |
|
|
static void handle_new_command(const tal_t *ctx, |
|
|
static void handle_new_command(const tal_t *ctx, |
|
|
struct plugin_conn *request_conn, |
|
|
struct plugin_conn *request_conn, |
|
|
struct plugin_conn *rpc_conn, |
|
|
struct plugin_conn *rpc_conn, |
|
|
const struct plugin_command *commands, |
|
|
struct plugin *p) |
|
|
size_t num_commands, |
|
|
|
|
|
const struct plugin_notification *notif_subs, |
|
|
|
|
|
size_t num_notif_subs, |
|
|
|
|
|
const struct plugin_hook *hook_subs, |
|
|
|
|
|
size_t num_hook_subs) |
|
|
|
|
|
{ |
|
|
{ |
|
|
struct command *cmd; |
|
|
struct command *cmd; |
|
|
const jsmntok_t *params; |
|
|
const jsmntok_t *params; |
|
@ -643,27 +643,27 @@ static void handle_new_command(const tal_t *ctx, |
|
|
cmd = read_json_request(ctx, request_conn, rpc_conn, ¶ms, &reqlen); |
|
|
cmd = read_json_request(ctx, request_conn, rpc_conn, ¶ms, &reqlen); |
|
|
/* If this is a notification. */ |
|
|
/* If this is a notification. */ |
|
|
if (!cmd->id) { |
|
|
if (!cmd->id) { |
|
|
for (size_t i = 0; i < num_notif_subs; i++) { |
|
|
for (size_t i = 0; i < p->num_notif_subs; i++) { |
|
|
if (streq(cmd->methodname, notif_subs[i].name)) { |
|
|
if (streq(cmd->methodname, p->notif_subs[i].name)) { |
|
|
notif_subs[i].handle(cmd, membuf_elems(&request_conn->mb), |
|
|
p->notif_subs[i].handle(cmd, membuf_elems(&request_conn->mb), |
|
|
params); |
|
|
params); |
|
|
membuf_consume(&request_conn->mb, reqlen); |
|
|
membuf_consume(&request_conn->mb, reqlen); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
for (size_t i = 0; i < num_hook_subs; i++) { |
|
|
for (size_t i = 0; i < p->num_hook_subs; i++) { |
|
|
if (streq(cmd->methodname, hook_subs[i].name)) { |
|
|
if (streq(cmd->methodname, p->hook_subs[i].name)) { |
|
|
hook_subs[i].handle(cmd, membuf_elems(&request_conn->mb), |
|
|
p->hook_subs[i].handle(cmd, membuf_elems(&request_conn->mb), |
|
|
params); |
|
|
params); |
|
|
membuf_consume(&request_conn->mb, reqlen); |
|
|
membuf_consume(&request_conn->mb, reqlen); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
for (size_t i = 0; i < num_commands; i++) { |
|
|
for (size_t i = 0; i < p->num_commands; i++) { |
|
|
if (streq(cmd->methodname, commands[i].name)) { |
|
|
if (streq(cmd->methodname, p->commands[i].name)) { |
|
|
commands[i].handle(cmd, membuf_elems(&request_conn->mb), |
|
|
p->commands[i].handle(cmd, membuf_elems(&request_conn->mb), |
|
|
params); |
|
|
params); |
|
|
membuf_consume(&request_conn->mb, reqlen); |
|
|
membuf_consume(&request_conn->mb, reqlen); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
@ -757,9 +757,44 @@ void plugin_log(enum log_level l, const char *fmt, ...) |
|
|
va_end(ap); |
|
|
va_end(ap); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct plugin *new_plugin(const tal_t *ctx, |
|
|
|
|
|
const enum plugin_restartability restartability, |
|
|
|
|
|
const struct plugin_command *commands, |
|
|
|
|
|
size_t num_commands, |
|
|
|
|
|
const struct plugin_notification *notif_subs, |
|
|
|
|
|
size_t num_notif_subs, |
|
|
|
|
|
const struct plugin_hook *hook_subs, |
|
|
|
|
|
size_t num_hook_subs, |
|
|
|
|
|
va_list ap) |
|
|
|
|
|
{ |
|
|
|
|
|
const char *optname; |
|
|
|
|
|
struct plugin *p = tal(ctx, struct plugin); |
|
|
|
|
|
|
|
|
|
|
|
p->restartability = restartability; |
|
|
|
|
|
p->commands = commands; |
|
|
|
|
|
p->num_commands = num_commands; |
|
|
|
|
|
p->notif_subs = notif_subs; |
|
|
|
|
|
p->num_notif_subs = num_notif_subs; |
|
|
|
|
|
p->hook_subs = hook_subs; |
|
|
|
|
|
p->num_hook_subs = num_hook_subs; |
|
|
|
|
|
p->opts = tal_arr(p, struct plugin_option, 0); |
|
|
|
|
|
|
|
|
|
|
|
while ((optname = va_arg(ap, const char *)) != NULL) { |
|
|
|
|
|
struct plugin_option o; |
|
|
|
|
|
o.name = optname; |
|
|
|
|
|
o.type = va_arg(ap, const char *); |
|
|
|
|
|
o.description = va_arg(ap, const char *); |
|
|
|
|
|
o.handle = va_arg(ap, char *(*)(const char *str, void *arg)); |
|
|
|
|
|
o.arg = va_arg(ap, void *); |
|
|
|
|
|
tal_arr_expand(&p->opts, o); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return p; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void plugin_main(char *argv[], |
|
|
void plugin_main(char *argv[], |
|
|
void (*init)(struct plugin_conn *rpc, |
|
|
void (*init)(struct plugin_conn *rpc, |
|
|
const char *buf, const jsmntok_t *), |
|
|
const char *buf, const jsmntok_t *), |
|
|
const enum plugin_restartability restartability, |
|
|
const enum plugin_restartability restartability, |
|
|
const struct plugin_command *commands, |
|
|
const struct plugin_command *commands, |
|
|
size_t num_commands, |
|
|
size_t num_commands, |
|
@ -769,15 +804,13 @@ void plugin_main(char *argv[], |
|
|
size_t num_hook_subs, |
|
|
size_t num_hook_subs, |
|
|
...) |
|
|
...) |
|
|
{ |
|
|
{ |
|
|
|
|
|
struct plugin *plugin; |
|
|
struct plugin_conn request_conn; |
|
|
struct plugin_conn request_conn; |
|
|
const tal_t *ctx = tal(NULL, char); |
|
|
|
|
|
struct command *cmd; |
|
|
struct command *cmd; |
|
|
const jsmntok_t *params; |
|
|
const jsmntok_t *params; |
|
|
int reqlen; |
|
|
int reqlen; |
|
|
struct pollfd fds[2]; |
|
|
struct pollfd fds[2]; |
|
|
struct plugin_option *opts = tal_arr(ctx, struct plugin_option, 0); |
|
|
|
|
|
va_list ap; |
|
|
va_list ap; |
|
|
const char *optname; |
|
|
|
|
|
|
|
|
|
|
|
setup_locale(); |
|
|
setup_locale(); |
|
|
|
|
|
|
|
@ -788,36 +821,29 @@ void plugin_main(char *argv[], |
|
|
|
|
|
|
|
|
setup_command_usage(commands, num_commands); |
|
|
setup_command_usage(commands, num_commands); |
|
|
|
|
|
|
|
|
|
|
|
va_start(ap, num_hook_subs); |
|
|
|
|
|
plugin = new_plugin(NULL, restartability, commands, num_commands, |
|
|
|
|
|
notif_subs, num_notif_subs, hook_subs, |
|
|
|
|
|
num_hook_subs, ap); |
|
|
|
|
|
va_end(ap); |
|
|
|
|
|
|
|
|
timers_init(&timers, time_mono()); |
|
|
timers_init(&timers, time_mono()); |
|
|
membuf_init(&rpc_conn.mb, |
|
|
membuf_init(&rpc_conn.mb, |
|
|
tal_arr(ctx, char, READ_CHUNKSIZE), READ_CHUNKSIZE, |
|
|
tal_arr(plugin, char, READ_CHUNKSIZE), READ_CHUNKSIZE, |
|
|
membuf_tal_realloc); |
|
|
membuf_tal_realloc); |
|
|
request_conn.fd = STDIN_FILENO; |
|
|
request_conn.fd = STDIN_FILENO; |
|
|
membuf_init(&request_conn.mb, |
|
|
membuf_init(&request_conn.mb, |
|
|
tal_arr(ctx, char, READ_CHUNKSIZE), READ_CHUNKSIZE, |
|
|
tal_arr(plugin, char, READ_CHUNKSIZE), READ_CHUNKSIZE, |
|
|
membuf_tal_realloc); |
|
|
membuf_tal_realloc); |
|
|
uintmap_init(&out_reqs); |
|
|
uintmap_init(&out_reqs); |
|
|
|
|
|
|
|
|
va_start(ap, num_hook_subs); |
|
|
|
|
|
while ((optname = va_arg(ap, const char *)) != NULL) { |
|
|
|
|
|
struct plugin_option o; |
|
|
|
|
|
o.name = optname; |
|
|
|
|
|
o.type = va_arg(ap, const char *); |
|
|
|
|
|
o.description = va_arg(ap, const char *); |
|
|
|
|
|
o.handle = va_arg(ap, char *(*)(const char *str, void *arg)); |
|
|
|
|
|
o.arg = va_arg(ap, void *); |
|
|
|
|
|
tal_arr_expand(&opts, o); |
|
|
|
|
|
} |
|
|
|
|
|
va_end(ap); |
|
|
|
|
|
|
|
|
|
|
|
cmd = read_json_request(tmpctx, &request_conn, NULL, |
|
|
cmd = read_json_request(tmpctx, &request_conn, NULL, |
|
|
¶ms, &reqlen); |
|
|
¶ms, &reqlen); |
|
|
if (!streq(cmd->methodname, "getmanifest")) |
|
|
if (!streq(cmd->methodname, "getmanifest")) |
|
|
plugin_err("Expected getmanifest not %s", cmd->methodname); |
|
|
plugin_err("Expected getmanifest not %s", cmd->methodname); |
|
|
|
|
|
|
|
|
membuf_consume(&request_conn.mb, reqlen); |
|
|
membuf_consume(&request_conn.mb, reqlen); |
|
|
handle_getmanifest(cmd, commands, num_commands, notif_subs, num_notif_subs, |
|
|
handle_getmanifest(cmd, plugin); |
|
|
hook_subs, num_hook_subs, opts, restartability); |
|
|
|
|
|
|
|
|
|
|
|
cmd = read_json_request(tmpctx, &request_conn, &rpc_conn, |
|
|
cmd = read_json_request(tmpctx, &request_conn, &rpc_conn, |
|
|
¶ms, &reqlen); |
|
|
¶ms, &reqlen); |
|
@ -825,7 +851,7 @@ void plugin_main(char *argv[], |
|
|
plugin_err("Expected init not %s", cmd->methodname); |
|
|
plugin_err("Expected init not %s", cmd->methodname); |
|
|
|
|
|
|
|
|
handle_init(cmd, membuf_elems(&request_conn.mb), |
|
|
handle_init(cmd, membuf_elems(&request_conn.mb), |
|
|
params, opts, init); |
|
|
params, plugin->opts, init); |
|
|
membuf_consume(&request_conn.mb, reqlen); |
|
|
membuf_consume(&request_conn.mb, reqlen); |
|
|
|
|
|
|
|
|
/* Set up fds for poll. */ |
|
|
/* Set up fds for poll. */ |
|
@ -843,9 +869,7 @@ void plugin_main(char *argv[], |
|
|
|
|
|
|
|
|
/* If we already have some input, process now. */ |
|
|
/* If we already have some input, process now. */ |
|
|
if (membuf_num_elems(&request_conn.mb) != 0) { |
|
|
if (membuf_num_elems(&request_conn.mb) != 0) { |
|
|
handle_new_command(ctx, &request_conn, &rpc_conn, |
|
|
handle_new_command(plugin, &request_conn, &rpc_conn, plugin); |
|
|
commands, num_commands, notif_subs, num_notif_subs, |
|
|
|
|
|
hook_subs, num_hook_subs); |
|
|
|
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
if (membuf_num_elems(&rpc_conn.mb) != 0) { |
|
|
if (membuf_num_elems(&rpc_conn.mb) != 0) { |
|
@ -871,10 +895,10 @@ void plugin_main(char *argv[], |
|
|
poll(fds, 2, t); |
|
|
poll(fds, 2, t); |
|
|
|
|
|
|
|
|
if (fds[0].revents & POLLIN) |
|
|
if (fds[0].revents & POLLIN) |
|
|
handle_new_command(ctx, &request_conn, &rpc_conn, |
|
|
handle_new_command(plugin, &request_conn, &rpc_conn, plugin); |
|
|
commands, num_commands, notif_subs, num_notif_subs, |
|
|
|
|
|
hook_subs, num_hook_subs); |
|
|
|
|
|
if (fds[1].revents & POLLIN) |
|
|
if (fds[1].revents & POLLIN) |
|
|
handle_rpc_reply(&rpc_conn); |
|
|
handle_rpc_reply(&rpc_conn); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tal_free(plugin); |
|
|
} |
|
|
} |
|
|