/* Helper library for C plugins. */
#ifndef LIGHTNING_PLUGINS_LIBPLUGIN_H
#define LIGHTNING_PLUGINS_LIBPLUGIN_H
#include "config.h"

#include <ccan/timer/timer.h>
#include <common/htlc.h>
#include <common/json_command.h>
#include <common/node_id.h>
#include <common/utils.h>

struct json_out;
struct htable;
struct plugin;
struct rpc_conn;

enum plugin_restartability {
	PLUGIN_STATIC,
	PLUGIN_RESTARTABLE
};

struct out_req {
	/* The unique id of this request. */
	const char *id;
	/* The command which is why we're calling this rpc. */
	struct command *cmd;
	/* The method this is calling */
	const char *method;
	/* The request stream. */
	struct json_stream *js;
	/* The callback when we get a response. */
	struct command_result *(*cb)(struct command *command,
				     const char *method,
				     const char *buf,
				     const jsmntok_t *result,
				     void *arg);
	/* The callback when we get an error. */
	struct command_result *(*errcb)(struct command *command,
					const char *method,
					const char *buf,
					const jsmntok_t *error,
					void *arg);
	void *arg;
};

enum command_type {
	/* Terminate with jsonrpc_stream_success/fail etc */
	COMMAND_TYPE_NORMAL,
	/* Terminate with command_hook_success or command_success */
	COMMAND_TYPE_HOOK,
	/* Terminate with aux_command_done */
	COMMAND_TYPE_AUX,
	/* Terminate with notification_handled */
	COMMAND_TYPE_NOTIFICATION,
	/* Terminate with timer_complete */
	COMMAND_TYPE_TIMER,
	/* These self-terminate */
	COMMAND_TYPE_CHECK,
	COMMAND_TYPE_USAGE_ONLY,
};

struct command {
	const char *id;
	const char *methodname;
	enum command_type type;
	struct plugin *plugin;
	/* Optional output field filter. */
	struct json_filter *filter;
};

/* Create an array of these, one for each command you support. */
struct plugin_command {
	const char *name;
	struct command_result *(*handle)(struct command *cmd,
					 const char *buf,
					 const jsmntok_t *params);
	/* If it's deprecated from a particular release (or NULL) */
	const char *depr_start, *depr_end;
	/* If true, this option requires --developer to be enabled */
	bool dev_only;
};

/* Create an array of these, one for each notification you subscribe to. */
struct plugin_notification {
	/* "*" means wildcard: notify me on everything (should be last!) */
	const char *name;
	/* The handler must eventually trigger a `notification_handled`
	 * call.  */
	struct command_result* (*handle)(struct command *cmd,
					 const char *buf,
					 const jsmntok_t *params);
};

/* Create an array of these, one for each hook you subscribe to. */
struct plugin_hook {
	const char *name;
	struct command_result *(*handle)(struct command *cmd,
	                                 const char *buf,
	                                 const jsmntok_t *params);
	/* If non-NULL, these are NULL-terminated arrays of deps */
	const char **before, **after;

	/* String filters (you can only set this *or* intfilters) */
	const char **strfilters;
	size_t num_strfilters;

	/* Integer filters */
	const u64 *intfilters;
	size_t num_intfilters;
};

/* Return the feature set of the current lightning node */
const struct feature_set *plugin_feature_set(const struct plugin *p);

/* Ignore the result, and terminate the command */
struct command_result *ignore_and_complete(struct command *cmd,
					   const char *method,
					   const char *buf,
					   const jsmntok_t *result,
					   void *arg);

/* Broken the result, and terminate the command */
struct command_result *log_broken_and_complete(struct command *cmd,
					       const char *method,
					       const char *buf,
					       const jsmntok_t *result,
					       void *arg);

/* Call plugin_err */
struct command_result *plugin_broken_cb(struct command *cmd,
					const char *method,
					const char *buf,
					const jsmntok_t *result,
					void *arg);

/* Helper to create a JSONRPC2 request stream. Send it with `send_outreq`. */
struct out_req *jsonrpc_request_start_(struct command *cmd,
				       const char *method,
				       const char *id_prefix,
				       const char *filter,
				       struct command_result *(*cb)(struct command *command,
								    const char *methodname,
								    const char *buf,
								    const jsmntok_t *result,
								    void *arg),
				       struct command_result *(*errcb)(struct command *command,
								       const char *methodname,
								       const char *buf,
								       const jsmntok_t *result,
								       void *arg),
				       void *arg)
	NON_NULL_ARGS(1, 2, 5);

#define jsonrpc_request_start(cmd, method, cb, errcb, arg)		\
	jsonrpc_request_start_((cmd), (method), NULL, NULL,		\
		     typesafe_cb_preargs(struct command_result *, void *, \
					 (cb), (arg),			\
					 struct command *command,	\
					 const char *mthod,		\
					 const char *buf,		\
					 const jsmntok_t *result),	\
		     typesafe_cb_preargs(struct command_result *, void *, \
					 (errcb), (arg),		\
					 struct command *command,	\
					 const char *mthod,		\
					 const char *buf,		\
					 const jsmntok_t *result),	\
		     (arg))

#define jsonrpc_request_with_filter_start(cmd, method, filter, cb, errcb, arg) \
	jsonrpc_request_start_((cmd), (method),	NULL, (filter),		\
		     typesafe_cb_preargs(struct command_result *, void *, \
					 (cb), (arg),			\
					 struct command *command,	\
					 const char *mthod,		\
					 const char *buf,		\
					 const jsmntok_t *result),	\
		     typesafe_cb_preargs(struct command_result *, void *, \
					 (errcb), (arg),		\
					 struct command *command,	\
					 const char *mthod,			\
					 const char *buf,		\
					 const jsmntok_t *result),	\
		     (arg))

/* This variant has callbacks received whole obj, not "result" or
 * "error" members.  It also doesn't start params{}. */
#define jsonrpc_request_whole_object_start(cmd, method, id_prefix, cb, arg) \
	jsonrpc_request_start_((cmd), (method), (id_prefix), NULL,	\
			       typesafe_cb_preargs(struct command_result *, void *, \
						   (cb), (arg),		\
						   struct command *command, \
						   const char *mthod,	\
						   const char *buf,	\
						   const jsmntok_t *result), \
			       NULL,					\
			       (arg))

/* Batch of requests: cb and errcb are optional, finalcb is called when all complete. */
struct request_batch *request_batch_new_(const tal_t *ctx,
					 struct command_result *(*cb)(struct command *,
								      const char *method,
								      const char *,
								      const jsmntok_t *,
								      void *),
					 struct command_result *(*errcb)(struct command *,
									 const char *method,
									 const char *,
									 const jsmntok_t *,
									 void *),
					 struct command_result *(*finalcb)(struct command *,
									   void *),
					 void *arg);

#define request_batch_new(ctx, cb, errcb, finalcb, arg)			\
	request_batch_new_((ctx),					\
		     typesafe_cb_preargs(struct command_result *, void *, \
					 (cb), (arg),			\
					 struct command *command,	\
					 const char *method,		\
					 const char *buf,		\
					 const jsmntok_t *result),	\
		     typesafe_cb_preargs(struct command_result *, void *, \
					 (errcb), (arg),		\
					 struct command *command,	\
					 const char *method,		\
					 const char *buf,		\
					 const jsmntok_t *result),	\
		     typesafe_cb_preargs(struct command_result *, void *, \
					 (finalcb), (arg),		\
					 struct command *command),	\
		     (arg))

struct out_req *add_to_batch(struct command *cmd,
			     struct request_batch *batch,
			     const char *cmdname)
	NON_NULL_ARGS(1, 2, 3);

/* We want some commands to live after this command (possibly)
 * completes.  This creates a new command with the same id but its own
 * lifetime: use aux_command_done() or tal_free() when you're done. */
struct command *aux_command(const struct command *cmd)
	NON_NULL_ARGS(1);

/* Runs finalcb immediately if batch is empty. */
struct command_result *batch_done(struct command *cmd,
				  struct request_batch *batch)
	NON_NULL_ARGS(1, 2);

/* Helper to create a JSONRPC2 response stream with a "result" object. */
struct json_stream *jsonrpc_stream_success(struct command *cmd)
	NON_NULL_ARGS(1);

/* Helper to create a JSONRPC2 response stream with an "error" object. */
struct json_stream *jsonrpc_stream_fail(struct command *cmd,
					int code,
					const char *err)
	NON_NULL_ARGS(1, 3);

/* Helper to create a JSONRPC2 response stream with an "error" object,
 * to which will be added a "data" object. */
struct json_stream *jsonrpc_stream_fail_data(struct command *cmd,
					     int code,
					     const char *err)
	NON_NULL_ARGS(1, 3);

/* Helper to jsonrpc_request_start() and send_outreq() to update datastore.
 * NULL cb means ignore, NULL errcb means plugin_error.
 */
struct command_result *jsonrpc_set_datastore_(struct command *cmd,
					      const char **keys,
					      const void *value,
					      int len_or_str,
					      const char *mode,
					      struct command_result *(*cb)(struct command *command,
									   const char *method,
									   const char *buf,
									   const jsmntok_t *result,
									   void *arg),
					      struct command_result *(*errcb)(struct command *command,
									      const char *method,
									      const char *buf,
									      const jsmntok_t *result,
									      void *arg),
					      void *arg)
	NON_NULL_ARGS(1, 2, 3, 5);

#define jsonrpc_set_datastore_string(cmd, keys, str, mode, cb, errcb, arg) \
	jsonrpc_set_datastore_((cmd), (keys), (str), -1, (mode),	\
			       typesafe_cb_preargs(struct command_result *, void *, \
						   (cb), (arg),		\
						   struct command *command, \
						   const char *method,	\
						   const char *buf,	\
						   const jsmntok_t *result), \
			       typesafe_cb_preargs(struct command_result *, void *, \
						   (errcb), (arg),	\
						   struct command *command, \
						   const char *method,	\
						   const char *buf,	\
						   const jsmntok_t *result), \
			       (arg))

#define jsonrpc_set_datastore_binary(cmd, keys, ptr, len, mode, cb, errcb, arg) \
	jsonrpc_set_datastore_((cmd), (keys), (ptr), (len), (mode),	\
			       typesafe_cb_preargs(struct command_result *, void *, \
						   (cb), (arg),		\
						   struct command *command, \
						   const char *method,	\
						   const char *buf,	\
						   const jsmntok_t *result), \
			       typesafe_cb_preargs(struct command_result *, void *, \
						   (errcb), (arg),	\
						   struct command *command, \
						   const char *method,	\
						   const char *buf,	\
						   const jsmntok_t *result), \
			       (arg))

/* Helper to jsonrpc_request_start() and send_outreq() to read datastore.
 * If the value not found, cb gets NULL @val.
 */
struct command_result *jsonrpc_get_datastore_(struct command *cmd,
					      const char **keys,
					      struct command_result *(*string_cb)(struct command *command,
									   const char *val,
									   void *arg),
					      struct command_result *(*binary_cb)(struct command *command,
									   const u8 *val,
									   void *arg),
					      void *arg)
	NON_NULL_ARGS(1, 2);

#define jsonrpc_get_datastore_string(cmd, keys, cb, arg)		\
	jsonrpc_get_datastore_((cmd), (keys),				\
			       typesafe_cb_preargs(struct command_result *, \
						   void *,		\
						   (cb), (arg),		\
						   struct command *command, \
						   const char *val),	\
			       NULL,				     \
			       (arg))

#define jsonrpc_get_datastore_binary(cmd, keys, cb, arg)		\
	jsonrpc_get_datastore_((cmd), (keys),				\
			       NULL,					\
			       typesafe_cb_preargs(struct command_result *, \
						   void *,		\
						   (cb), (arg),		\
						   struct command *command, \
						   const u8 *val),	\
			       (arg))


/* This command is finished, here's the response (the content of the
 * "result" or "error" field) */
WARN_UNUSED_RESULT
struct command_result *command_finished(struct command *cmd, struct json_stream *response)
	NON_NULL_ARGS(1, 2);

/* Helper for a command that'll be finished in a callback. */
WARN_UNUSED_RESULT
struct command_result *command_still_pending(struct command *cmd)
	NON_NULL_ARGS(1);

/* Forward this raw JSON string as the command response */
WARN_UNUSED_RESULT
struct command_result *command_finish_rawstr(struct command *cmd,
					     const char *json,
					     size_t json_len)
	NO_NULL_ARGS;

/* Helper to create a zero or single-value JSON object; if @str is NULL,
 * object is empty. */
struct json_out *json_out_obj(const tal_t *ctx,
			      const char *fieldname,
			      const char *str TAKES);

/* Return this iff the param() call failed in your handler. */
struct command_result *command_param_failed(void);

/* Helper for sql command, which is a front-end to other commands. */
bool command_deprecated_in_named_ok(struct command *cmd,
				    const char *cmdname,
				    const char *param,
				    const char *depr_start,
				    const char *depr_end);

/* Should we include this field in the notification? */
bool notification_deprecated_out_ok(struct plugin *plugin,
				    const char *method,
				    const char *fieldname,
				    const char *depr_start,
				    const char *depr_end);

/* Call this on fatal error. */
void NORETURN PRINTF_FMT(2,3) plugin_err(struct plugin *p, const char *fmt, ...);

/* Call this on fatal error. */
void NORETURN plugin_errv(struct plugin *p, const char *fmt, va_list ap);

/* Normal exit (makes sure to flush output!). */
void NORETURN plugin_exit(struct plugin *p, int exitcode);

/* This command is finished, here's a detailed error; @cmd cannot be
 * NULL, data can be NULL; otherwise it must be a JSON object. */
struct command_result *WARN_UNUSED_RESULT
command_done_err(struct command *cmd,
		 enum jsonrpc_errcode code,
		 const char *errmsg,
		 const struct json_out *data)
	NON_NULL_ARGS(1, 3);

/* Send a raw error response. Useful for forwarding a previous
 * error after cleanup */
struct command_result *command_err_raw(struct command *cmd,
				       const char *json_str)
	NON_NULL_ARGS(1, 2);

/* This command is finished, here's the result object; @cmd cannot be NULL. */
struct command_result *WARN_UNUSED_RESULT
command_success(struct command *cmd, const struct json_out *result)
	NON_NULL_ARGS(1, 2);

/* End a hook normally (with "result": "continue") */
struct command_result *command_hook_success(struct command *cmd)
	WARN_UNUSED_RESULT NON_NULL_ARGS(1);

/* End a notification handler.  */
struct command_result *notification_handled(struct command *cmd)
	WARN_UNUSED_RESULT NON_NULL_ARGS(1);

/* End a command created with aux_command.  */
struct command_result *WARN_UNUSED_RESULT
aux_command_done(struct command *cmd)
	NON_NULL_ARGS(1);

/**
 * What's the deprecation_ok state for this cmd?
 * @cmd: the command.
 *
 * Either the default, or the explicit connection override.
 */
bool command_deprecated_ok_flag(const struct command *cmd)
	NON_NULL_ARGS(1);

/* Helper for notification handler that will be finished in a callback.  */
#define notification_handler_pending(cmd) command_still_pending(cmd)

/* Synchronous helper to send command and extract fields from
 * response. */
void rpc_scan(struct command *cmd,
	      const char *method,
	      const struct json_out *params TAKES,
	      const char *guide,
	      ...);

/* Helper to scan datastore.  Returns error msg (usually meaning field
 * does not exist), or NULL on success. keys is usually from mkdatastorekey.  Final
 * arg is JSON_SCAN or JSON_SCAN_TAL.
 */
const char *rpc_scan_datastore_str(const tal_t *ctx,
				   struct command *cmd,
				   const char **keys,
				   ...);
/* This variant scans the hex encoding, not the string */
const char *rpc_scan_datastore_hex(const tal_t *ctx,
				   struct command *cmd,
				   const char **keys,
				   ...);

/* This sets batching of database commitments */
void rpc_enable_batching(struct plugin *plugin);

/* Send an async rpc request to lightningd. */
struct command_result *send_outreq(const struct out_req *req);

/* Callback to just forward error and close request; @cmd cannot be NULL */
struct command_result *forward_error(struct command *cmd,
				     const char *method,
				     const char *buf,
				     const jsmntok_t *error,
				     void *arg)
	NON_NULL_ARGS(1, 2, 3, 4);

/* Callback to just forward result and close request; @cmd cannot be NULL */
struct command_result *forward_result(struct command *cmd,
				     const char *method,
				      const char *buf,
				      const jsmntok_t *result,
				      void *arg)
	NON_NULL_ARGS(1, 2, 3, 4);

/* Callback for timer where we expect a 'command_result'.  All timers
 * must return this eventually, though they may do so via a convoluted
 * send_req() path. */
struct command_result *timer_complete(struct command *cmd)
	NON_NULL_ARGS(1);

/* Access timer infrastructure to add a global timer for the plugin.
 *
 * This is a timer with the same lifetime as the plugin.
 */
struct plugin_timer *global_timer_(struct plugin *p,
				   struct timerel t,
				   struct command_result *(*cb)(struct command *cmd, void *cb_arg),
				   void *cb_arg);

#define global_timer(plugin, time, cb, cb_arg)				\
	global_timer_((plugin), (time),					\
		      typesafe_cb_preargs(struct command_result *,	\
					  void *,			\
					  (cb), (cb_arg),		\
					  struct command *),		\
		      (cb_arg))						\

/* Timer based off specific cmd */
struct plugin_timer *command_timer_(struct command *cmd,
				    struct timerel t,
				    struct command_result *(*cb)(struct command *cmd, void *cb_arg),
				    void *cb_arg);

#define command_timer(cmd, time, cb, cb_arg)				\
	command_timer_((cmd), (time),					\
		       typesafe_cb_preargs(struct command_result *,	\
					   void *,			\
					   (cb), (cb_arg),		\
					   struct command *),		\
		       (cb_arg))					\

/* Log something */
void plugin_log(struct plugin *p, enum log_level l, const char *fmt, ...) PRINTF_FMT(3, 4);
void plugin_logv(struct plugin *p, enum log_level l, const char *fmt, va_list ap);

/* plogin_logv wrapper for gossmap */
void plugin_gossmap_logcb(struct plugin *plugin,
			  enum log_level level,
			  const char *fmt,
			  ...);

/* Notify the caller of something. */
struct json_stream *plugin_notify_start(struct command *cmd, const char *method);
void plugin_notify_end(struct command *cmd, struct json_stream *js);

/* Send a notification for a custom notification topic. These are sent
 * to lightningd and distributed to subscribing plugins. */
struct json_stream *plugin_notification_start(const tal_t *ctx,
					      const char *method);
void plugin_notification_end(struct plugin *plugin,
			     struct json_stream *stream STEALS);

/* Obsolete versions: do not use for new code! */
struct json_stream *plugin_notification_start_obs(const tal_t *ctx,
						  const char *method);
void plugin_notification_end_obs(struct plugin *plugin,
				 struct json_stream *stream TAKES);

/* Convenience wrapper for notify "message" */
void plugin_notify_message(struct command *cmd,
			   enum log_level level,
			   const char *fmt, ...)
	PRINTF_FMT(3, 4);

/* Convenience wrapper for progress: num_stages is normally 0. */
void plugin_notify_progress(struct command *cmd,
			    u32 num_stages, u32 stage,
			    u32 num_progress, u32 progress);

/* Simply exists to check that `set` to plugin_option* is correct type */
static inline void *plugin_option_cb_check(char *(*set)(struct command *cmd,
							const char *arg,
							bool check_only,
							void *))
{
	return set;
}

/* Simply exists to check that `jsonfmt` to plugin_option* is correct type */
static inline void *plugin_option_jsonfmt_check(bool (*jsonfmt)(struct command *,
								struct json_stream *,
								const char *,
								void *))
{
	return jsonfmt;
}

/* Is --developer enabled? */
bool plugin_developer_mode(const struct plugin *plugin);

/* Store a single pointer for our state in the plugin */
void plugin_set_data(struct plugin *plugin, void *data TAKES);
void *plugin_get_data_(struct plugin *plugin);
#define plugin_get_data(plugin, type) ((type *)(plugin_get_data_(plugin)))

/* Macro to define arguments */
#define plugin_option_(name, type, description, set, jsonfmt, arg, dev_only, depr_start, depr_end, dynamic, multi) \
	(name),								\
	(type),								\
	(description),							\
	plugin_option_cb_check(typesafe_cb_preargs(char *, void *,	\
						   (set), (arg),	\
						   struct command *,	\
						   const char *, bool)),\
	plugin_option_jsonfmt_check(typesafe_cb_preargs(bool, void *,	\
							(jsonfmt), (arg), \
							struct command *, \
							struct json_stream *, \
							const char *)),	\
	(arg),								\
	(dev_only),							\
	(depr_start),							\
	(depr_end),							\
	(dynamic),							\
	(multi)

/* jsonfmt can be NULL, but then default won't be printed */
#define plugin_option(name, type, description, set, jsonfmt, arg)	\
	plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, false, false)

#define plugin_option_dev(name, type, description, set, jsonfmt, arg)	\
	plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, false, false)

#define plugin_option_dev_dynamic(name, type, description, set, jsonfmt, arg) \
	plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), true, NULL, NULL, true, false)

#define plugin_option_dynamic(name, type, description, set, jsonfmt, arg) \
	plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, true, false)

#define plugin_option_deprecated(name, type, description, depr_start, depr_end, set, jsonfmt, arg) \
	plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, (depr_start), (depr_end), false, false)

#define plugin_option_multi(name, type, description, set, jsonfmt, arg)	\
	plugin_option_((name), (type), (description), (set), (jsonfmt), (arg), false, NULL, NULL, false, true)

/* Standard helpers */
char *u64_option(struct command *cmd, const char *arg, bool check_only, u64 *i);
char *u32_option(struct command *cmd, const char *arg, bool check_only, u32 *i);
char *u16_option(struct command *cmd, const char *arg, bool check_only, u16 *i);
char *bool_option(struct command *cmd, const char *arg, bool check_only, bool *i);
char *charp_option(struct command *cmd, const char *arg, bool check_only, char **p);
char *multi_string_option(struct command *cmd, const char *arg, bool check_only,
			  const char ***arr);
char *flag_option(struct command *cmd, const char *arg, bool check_only, bool *i);

bool u64_jsonfmt(struct command *cmd, struct json_stream *js, const char *fieldname,
		 u64 *i);
bool u32_jsonfmt(struct command *cmd, struct json_stream *js, const char *fieldname,
		 u32 *i);
bool u16_jsonfmt(struct command *cmd, struct json_stream *js, const char *fieldname,
		 u16 *i);
bool bool_jsonfmt(struct command *cmd, struct json_stream *js, const char *fieldname,
		  bool *i);
bool charp_jsonfmt(struct command *cmd, struct json_stream *js, const char *fieldname,
		   char **p);
bool string_array_jsonfmt(struct command *cmd, struct json_stream *js,
			  const char *fieldname, const char ***arr);

/* Usually equivalent to NULL, since flag must default to false be useful! */
bool flag_jsonfmt(struct command *cmd, struct json_stream *js, const char *fieldname,
		  bool *i);

/* The main plugin runner: append with 0 or more plugin_option(), then NULL. */
void NORETURN LAST_ARG_NULL plugin_main(char *argv[],
					const char *(*init)(struct command *init_cmd,
							    const char *buf,
							    const jsmntok_t *),
					void *data TAKES,
					const enum plugin_restartability restartability,
					bool init_rpc,
					struct feature_set *features STEALS,
					const struct plugin_command *commands TAKES,
					size_t num_commands,
					const struct plugin_notification *notif_subs TAKES,
					size_t num_notif_subs,
					const struct plugin_hook *hook_subs TAKES,
					size_t num_hook_subs,
					const char **notif_topics TAKES,
					size_t num_notif_topics,
					...);

struct listpeers_channel {
	struct node_id id;
	bool connected;
	bool private;
	struct bitcoin_txid funding_txid;
	const char *state;
	/* scid or alias[LOCAL] is always non-NULL */
	struct short_channel_id *alias[NUM_SIDES];
	struct short_channel_id *scid;
	int direction;
	struct amount_msat total_msat;
	struct amount_msat spendable_msat;
	u16 max_accepted_htlcs;
	size_t num_htlcs;
	/* TODO Add fields as we need them. */
};

/* Returns an array of listpeers_channel from listpeerchannels * */
struct listpeers_channel **json_to_listpeers_channels(const tal_t *ctx,
						      const char *buffer,
						      const jsmntok_t *tok);

/* Helper to write keys[] array (mainly for datastore ops) */
void json_add_keypath(struct json_out *jout,
		      const char *fieldname,
		      const char **keys);

struct createonion_response {
	u8 *onion;
	struct secret *shared_secrets;
};

struct createonion_response *json_to_createonion_response(const tal_t *ctx,
							  const char *buffer,
							  const jsmntok_t *toks);

struct route_hop *json_to_route(const tal_t *ctx, const char *buffer,
				const jsmntok_t *toks);

void plugin_set_memleak_handler(struct plugin *plugin,
				void (*mark_mem)(struct plugin *plugin,
						 struct htable *memtable));

/* Synchronously call a JSON-RPC method and return its contents and
 * the parser token. params may be NULL for an empty object. */
const jsmntok_t *jsonrpc_request_sync(const tal_t *ctx,
				      struct command *cmd,
				      const char *method,
				      const struct json_out *params TAKES,
				      const char **resp);

#endif /* LIGHTNING_PLUGINS_LIBPLUGIN_H */
