Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 148 additions & 52 deletions lightningd/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,108 +4,183 @@
#include <lightningd/notification.h>
#include <lightningd/peer_htlcs.h>

const char *notification_topics[] = {
"connect",
"disconnect",
"warning",
"invoice_payment",
"channel_opened",
"forward_event"
};
static struct notification *find_notification_by_topic(const char* topic)
{
static struct notification **notilist = NULL;
static size_t num_notis;
if (!notilist)
notilist = autodata_get(notifications, &num_notis);

for (size_t i=0; i<num_notis; i++)
if (streq(notilist[i]->topic, topic))
return notilist[i];
return NULL;
}

bool notifications_have_topic(const char *topic)
{
for (size_t i=0; i<ARRAY_SIZE(notification_topics); i++)
if (streq(topic, notification_topics[i]))
return true;
struct notification *noti = find_notification_by_topic(topic);
if (noti)
return true;

return false;
}

static void connect_notification_serialize(struct json_stream *stream,
struct node_id *nodeid,
struct wireaddr_internal *addr)
{
json_add_node_id(stream, "id", nodeid);
json_add_address_internal(stream, "address", addr);
}

REGISTER_NOTIFICATION(connect,
connect_notification_serialize);

void notify_connect(struct lightningd *ld, struct node_id *nodeid,
struct wireaddr_internal *addr)
{
struct jsonrpc_notification *n =
jsonrpc_notification_start(NULL, "connect");
json_add_node_id(n->stream, "id", nodeid);
json_add_address_internal(n->stream, "address", addr);
void (*serialize)(struct json_stream *,
struct node_id *,
struct wireaddr_internal *) = connect_notification_gen.serialize;

struct jsonrpc_notification *n
= jsonrpc_notification_start(NULL, connect_notification_gen.topic);
serialize(n->stream, nodeid, addr);
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}

static void disconnect_notification_serialize(struct json_stream *stream,
struct node_id *nodeid)
{
json_add_node_id(stream, "id", nodeid);
}

REGISTER_NOTIFICATION(disconnect,
disconnect_notification_serialize);

void notify_disconnect(struct lightningd *ld, struct node_id *nodeid)
{
struct jsonrpc_notification *n =
jsonrpc_notification_start(NULL, "disconnect");
json_add_node_id(n->stream, "id", nodeid);
void (*serialize)(struct json_stream *,
struct node_id *) = disconnect_notification_gen.serialize;

struct jsonrpc_notification *n
= jsonrpc_notification_start(NULL, disconnect_notification_gen.topic);
serialize(n->stream, nodeid);
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}

/*'warning' is based on LOG_UNUSUAL/LOG_BROKEN level log
*(in plugin module, they're 'warn'/'error' level). */
void notify_warning(struct lightningd *ld, struct log_entry *l)
static void warning_notification_serialize(struct json_stream *stream,
struct log_entry *l)
{
struct jsonrpc_notification *n =
jsonrpc_notification_start(NULL, "warning");
json_object_start(n->stream, "warning");
json_object_start(stream, "warning");
/* Choose "BROKEN"/"UNUSUAL" to keep consistent with the habit
* of plugin. But this may confuses the users who want to 'getlog'
* with the level indicated by notifications. It is the duty of a
* plugin to eliminate this misunderstanding.
*/
json_add_string(n->stream, "level",
json_add_string(stream, "level",
l->level == LOG_BROKEN ? "error"
: "warn");
/* unsuaul/broken event is rare, plugin pay more attentions on
* the absolute time, like when channels failed. */
json_add_time(n->stream, "time", l->time.ts);
json_add_string(n->stream, "source", l->prefix);
json_add_string(n->stream, "log", l->log);
json_object_end(n->stream); /* .warning */
json_add_time(stream, "time", l->time.ts);
json_add_string(stream, "source", l->prefix);
json_add_string(stream, "log", l->log);
json_object_end(stream); /* .warning */
}

REGISTER_NOTIFICATION(warning,
warning_notification_serialize);

void notify_warning(struct lightningd *ld, struct log_entry *l)
{
void (*serialize)(struct json_stream *,
struct log_entry *) = warning_notification_gen.serialize;

struct jsonrpc_notification *n
= jsonrpc_notification_start(NULL, warning_notification_gen.topic);
serialize(n->stream, l);
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}

static void invoice_payment_notification_serialize(struct json_stream *stream,
struct amount_msat amount,
struct preimage preimage,
const struct json_escape *label)
{
json_object_start(stream, "invoice_payment");
json_add_string(stream, "msat",
type_to_string(tmpctx, struct amount_msat, &amount));
json_add_hex(stream, "preimage", &preimage, sizeof(preimage));
json_add_escaped_string(stream, "label", label);
json_object_end(stream);
}

REGISTER_NOTIFICATION(invoice_payment,
invoice_payment_notification_serialize)

void notify_invoice_payment(struct lightningd *ld, struct amount_msat amount,
struct preimage preimage, const struct json_escape *label)
{
struct jsonrpc_notification *n =
jsonrpc_notification_start(NULL, "invoice_payment");
json_object_start(n->stream, "invoice_payment");
json_add_string(n->stream, "msat",
type_to_string(tmpctx, struct amount_msat, &amount));
json_add_hex(n->stream, "preimage", &preimage, sizeof(preimage));
json_add_escaped_string(n->stream, "label", label);
json_object_end(n->stream);
void (*serialize)(struct json_stream *,
struct amount_msat,
struct preimage,
const struct json_escape *) = invoice_payment_notification_gen.serialize;

struct jsonrpc_notification *n
= jsonrpc_notification_start(NULL, invoice_payment_notification_gen.topic);
serialize(n->stream, amount, preimage, label);
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}

static void channel_opened_notification_serialize(struct json_stream *stream,
struct node_id *node_id,
struct amount_sat *funding_sat,
struct bitcoin_txid *funding_txid,
bool *funding_locked)
{
json_object_start(stream, "channel_opened");
json_add_node_id(stream, "id", node_id);
json_add_amount_sat_only(stream, "amount", *funding_sat);
json_add_txid(stream, "funding_txid", funding_txid);
json_add_bool(stream, "funding_locked", funding_locked);
json_object_end(stream);
}

REGISTER_NOTIFICATION(channel_opened,
channel_opened_notification_serialize)

void notify_channel_opened(struct lightningd *ld, struct node_id *node_id,
struct amount_sat *funding_sat, struct bitcoin_txid *funding_txid,
bool *funding_locked)
{
struct jsonrpc_notification *n =
jsonrpc_notification_start(NULL, "channel_opened");
json_object_start(n->stream, "channel_opened");
json_add_node_id(n->stream, "id", node_id);
json_add_amount_sat_only(n->stream, "amount", *funding_sat);
json_add_txid(n->stream, "funding_txid", funding_txid);
json_add_bool(n->stream, "funding_locked", funding_locked);
json_object_end(n->stream);
void (*serialize)(struct json_stream *,
struct node_id *,
struct amount_sat *,
struct bitcoin_txid *,
bool *) = channel_opened_notification_gen.serialize;

struct jsonrpc_notification *n
= jsonrpc_notification_start(NULL, channel_opened_notification_gen.topic);
serialize(n->stream, node_id, funding_sat, funding_txid, funding_locked);
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}

void notify_forward_event(struct lightningd *ld,
const struct htlc_in *in,
const struct htlc_out *out,
enum forward_status state,
enum onion_type failcode,
struct timeabs *resolved_time)
static void forward_event_notification_serialize(struct json_stream *stream,
const struct htlc_in *in,
const struct htlc_out *out,
enum forward_status state,
enum onion_type failcode,
struct timeabs *resolved_time)
{
struct jsonrpc_notification *n =
jsonrpc_notification_start(NULL, "forward_event");
/* Here is more neat to initial a forwarding structure than
* to pass in a bunch of parameters directly*/
struct forwarding *cur = tal(tmpctx, struct forwarding);
Expand All @@ -126,8 +201,29 @@ void notify_forward_event(struct lightningd *ld,
cur->received_time = in->received_time;
cur->resolved_time = tal_steal(cur, resolved_time);

json_format_forwarding_object(n->stream, "forward_event", cur);
json_format_forwarding_object(stream, "forward_event", cur);
}

REGISTER_NOTIFICATION(forward_event,
forward_event_notification_serialize);

void notify_forward_event(struct lightningd *ld,
const struct htlc_in *in,
const struct htlc_out *out,
enum forward_status state,
enum onion_type failcode,
struct timeabs *resolved_time)
{
void (*serialize)(struct json_stream *,
const struct htlc_in *,
const struct htlc_out *,
enum forward_status,
enum onion_type,
struct timeabs *) = forward_event_notification_gen.serialize;

struct jsonrpc_notification *n
= jsonrpc_notification_start(NULL, forward_event_notification_gen.topic);
serialize(n->stream, in, out, state, failcode, resolved_time);
jsonrpc_notification_end(n);
plugins_notify(ld->plugins, take(n));
}
17 changes: 17 additions & 0 deletions lightningd/notification.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "config.h"
#include <bitcoin/short_channel_id.h>
#include <bitcoin/tx.h>
#include <ccan/autodata/autodata.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/time/time.h>
#include <common/amount.h>
Expand All @@ -17,6 +18,22 @@

bool notifications_have_topic(const char *topic);

struct notification {
const char *topic;
/* the serialization interface */
void *serialize;
};

AUTODATA_TYPE(notifications, struct notification);

/* FIXME: Find a way to avoid back-to-back declaration and definition */
#define REGISTER_NOTIFICATION(topic, serialize) \
struct notification topic##_notification_gen = { \
stringify(topic), \
serialize, \
}; \
AUTODATA(notifications, &topic##_notification_gen);

void notify_connect(struct lightningd *ld, struct node_id *nodeid,
struct wireaddr_internal *addr);
void notify_disconnect(struct lightningd *ld, struct node_id *nodeid);
Expand Down
5 changes: 3 additions & 2 deletions lightningd/peer_htlcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ void htlcs_resubmit(struct lightningd *ld, struct htlc_in_map *unprocessed);
void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage);
void fail_htlc(struct htlc_in *hin, enum onion_type failcode);

/* This json process will be both used in 'notify_forward_event()'
* and 'listforwardings_add_forwardings()'*/
/* This json process will be used as the serialize method for
* forward_event_notification_gen and be used in
* `listforwardings_add_forwardings()`. */
void json_format_forwarding_object(struct json_stream *response, const char *fieldname,
const struct forwarding *cur);
#endif /* LIGHTNING_LIGHTNINGD_PEER_HTLCS_H */