Conversation
renepickhardt
left a comment
There was a problem hiding this comment.
As far as I see you forgot to bump the version number of the pylightning file to 0.0.7 that would be required (followed by a push to pylightning after merging) other than that from what I see this looks good to me and I am excited to test this out with other notifications than connect or disconnect
| plugin.log("Plugin helloworld.py initialized") | ||
|
|
||
|
|
||
| @plugin.subscribe("connect") |
There was a problem hiding this comment.
this is an awesome API!
There was a problem hiding this comment.
Thanks, Flask was a huge inspiration.
| return false; | ||
| } | ||
|
|
||
| void plugins_notify(struct plugins *plugins, |
There was a problem hiding this comment.
LGTM ( I was searching if subscriptions to the same events would work if several plugins subscribed to the same event ) and from how I understand the code it seems to me that it works. I wasn't able to execute this code though
There was a problem hiding this comment.
That is indeed supported, since unlike jsonrpc calls and hooks there is no problem with notification semantics.
| return false; | ||
| } | ||
|
|
||
| void notify_connect(struct lightningd *ld, struct pubkey *nodeid, |
There was a problem hiding this comment.
so just for the gist I could create a method void notify_incoming_htlc(struct lightningd *ld, struct pubkey *nodeid, struct channel *chan, struct htlc *h) (not sure if struct channel and struct htlc exist) and create a json string and send it via plugin_notify to the plugin. I would obviously have to call that function at the place where incoming htlc's are being handled. But other than that (and of course adding the definition of the method to notification.h) I would not have to extend other parts of c-lightning or am I missing something?
There was a problem hiding this comment.
Yes, the idea is that you'd create a notify_xyz function that gathers all the information and formats it into a JSON message and then passes that to plugins_notify which will take care of dispatching notifications to all subscribers.
|
I will push the new version of the pylightning library once we have the Should get a 0.0.7 out by the end of the week though. |
|
Possible other notification:
|
rustyrussell
left a comment
There was a problem hiding this comment.
This is masterful code.
I was going to suggest we drop the static subscription-in-manifest idea for a dynamic RPC, but that actually makes it harder for plugins (at the moment they can treat STDIN as the source of all commands and notifications, and only read their rpc connection when they've sent some command).
But you should probably block subscriptions for a plugin until after it has returned from init (won't happen with these notifications, but may in future; my pay plugin actually makes rpc call before replying to init).
lightningd/plugin.c
Outdated
| return false; | ||
| } | ||
| topic = tal_strndup( | ||
| plugin, plugin->buffer + s->start, s->end - s->start); |
There was a problem hiding this comment.
Note: after rebase onto master, you'll be able to use json_strdup(plugin, plugin->buffer, s);
lightningd/plugin.c
Outdated
| if (!notifications_have_topic(topic)) { | ||
| plugin_kill( | ||
| plugin, | ||
| "topic %s is not a know notification topic", topic); |
There was a problem hiding this comment.
Slight simplification, I would skip the 's->type != JSMN_STRING' check above, and rely on it here (in which case, please put ' around the %s).
lightningd/plugin.c
Outdated
| static void plugin_send(struct plugin *plugin, struct json_stream *stream TAKES) | ||
| { | ||
| *tal_arr_expand(&plugin->js_arr) = req->stream; | ||
| *tal_arr_expand(&plugin->js_arr) = tal_steal(plugin->js_arr, stream); |
There was a problem hiding this comment.
Make this two lines: we got bitten by this evaluation order indeterminism before.
lightningd/plugin.c
Outdated
| */ | ||
| static void plugin_request_queue(struct plugin *plugin, | ||
| struct plugin_request *req) | ||
| static void plugin_send(struct plugin *plugin, struct json_stream *stream TAKES) |
There was a problem hiding this comment.
TAKES isn't quite right here: that means it takes ownership iff caller calls take(). Perhaps call it something more obviously "takes-ownership"-is, like "plugin_attach_stream()"?
lightningd/plugin.c
Outdated
| if (plugin_subscriptions_contains(p, n->method)) | ||
| plugin_send(p, json_stream_dup(p, n->stream)); | ||
| } | ||
| tal_free(n); |
There was a problem hiding this comment.
if (taken(n))
tal_free(n);
We could of course optimize this; when we optimize to a per-topic queue of plugins, we'd not have to copy the last one if it's taken().
lightningd/plugin.c
Outdated
| || !plugin_rpcmethods_add(plugin, buffer, resulttok)) | ||
| || !plugin_rpcmethods_add(plugin, buffer, resulttok) | ||
| || !plugin_subscriptions_add(plugin, buffer, resulttok)) | ||
| plugin_kill(plugin, "Failed to register options or methods"); |
There was a problem hiding this comment.
There's one other thing here now: subscriptions
lightningd/plugin.c
Outdated
| } | ||
|
|
||
| /** | ||
| * Determine whethe a plugin is subscribed to a given topic/method. |
| #include <ccan/array_size/array_size.h> | ||
|
|
||
| const char *notification_topics[] = { | ||
| "connect", |
There was a problem hiding this comment.
i think it'd be a bit easier to tell what these refer to if we include that it's a node action, something like 'connect-node' ?
There was a problem hiding this comment.
I bikeshedded a couple of variants for this, with broader topics, and naming variants, but in the end I just picked the simplest and shortest variant I could think of, i.e., just the actions that are performed. Happy to discuss the naming here further, but then I'd split the addition of this topic out and just get the infrastructure merged, so I can continue working on top of this 😉
There was a problem hiding this comment.
sounds good. 👍
fwiw, i like how the 'actor_action' pattern (ie 'node_connected') gives a bit more insight at a glance as to what this refers to, but being as i'm more familiar with the codebase now, connect is pretty easy to map back to RPC commands, which is also nice :)
| { | ||
| struct jsonrpc_notification *n = | ||
| jsonrpc_notification_start(NULL, notification_topics[0]); | ||
| json_add_pubkey(n->stream, "id", nodeid); |
There was a problem hiding this comment.
i'd propose changing this to peer_id instead of just id
There was a problem hiding this comment.
No, "id" is standard for the RPC layer, unless it's confusing. In this case, it's not.
There was a problem hiding this comment.
Ack. I totally misread some python code earlier; I redact this comment.
| void notify_disconnect(struct lightningd *ld, struct pubkey *nodeid) | ||
| { | ||
| struct jsonrpc_notification *n = | ||
| jsonrpc_notification_start(NULL, notification_topics[1]); |
There was a problem hiding this comment.
is there a way to not use hardcoded array indices for these? seems like this will be easy to break without meaning to if the notification_topics ever get reordered.
There was a problem hiding this comment.
There is a facility to generate names from enums, maybe we want to use that instead? I had an enum that represented the indices into this array, but it got really repetitive, so I dropped it for now.
There was a problem hiding this comment.
We use AUTODATA to generate an array of conmands, cannot we use same to generate array of notifications?
There was a problem hiding this comment.
We could do that, and I think I'm doing something similar in the hooks PR. We can revisit this later I think. The hooks PR also has some nice things like non-dynamic dispatch of serializers and callback, which might be interesting here as an optimization (skipping serialization if nobody has subscribed).
|
Rebased and addressed the feedback in fixups. @rustyrussell and @niftynei thanks for the reviews, if you're happy with the fixups I'll squash and merge :-) P.S.: I know it looks like a lot of fixups, but they are all single-lines and address a single comment each to make reviewing easier 😉 |
db3b21d to
91c9ce7
Compare
|
I do want "peer_id" changed back to "id" though, since that's the nomenclature used everywhere else. Rest is fine. Using an enum for notifications is a win, but that's a simple neatening which can be done later. |
|
Ack d9839bc |
conscott
left a comment
There was a problem hiding this comment.
Right now the docstring for plugin commands includes newline junk in the description text - like
hello [params]
This is the documentation string for the hello-function.\n\nIt gets reported as the description when registering the function\nas a method with `lightningd`.
You could just add a line here to convert docstring newlines to spaces (if desired)
doc = re.sub('\n+', ' ', doc)|
Tested ACK 91c9ce7 Just left a minor nit above. |
|
Rebased, dropped the |
|
Re-ACK 7de1399 |
Signed-off-by: Christian Decker <decker.christian@gmail.com>
Signed-off-by: Christian Decker <decker.christian@gmail.com>
Will be used in the next commit to fan out notifications to multiple subscribing plugins. We can't just use `tal_dup` from outside since the definition is hidden outside the compilation unit. Signed-off-by: Christian Decker <decker.christian@gmail.com>
This used to be request-specific, but we now want to send notifications and requests. As a drive-by we also clarify the ownership of the json_stream instance that is being sent. Signed-off-by: Christian Decker <decker.christian@gmail.com>
Signed-off-by: Christian Decker <decker.christian@gmail.com>
Signed-off-by: Christian Decker <decker.christian@gmail.com>
Signed-off-by: Christian Decker <decker.christian@gmail.com>
Just like we added the RPC methods, the notification handlers can also be registered using a function decorator, and we auto-subscribe when asked for a manifest. Signed-off-by: Christian Decker <decker.christian@gmail.com>
Signed-off-by: Christian Decker <decker.christian@gmail.com>
|
Rebased and squashed on top of ACK 5a8c2c6 |
We're nearing the end of the endless plugin saga, with this new feature. It allows plugins to subscribe to a number of notifications/events that will then be streamed from
lightningdto the plugin when something happens.Notice that, while this provides the infrastructure, I've only implemented two very simple notification topics (
connectanddisconnect). We can (and will) add more as we come up with new use-cases.