Skip to content

Commit 9a6486e

Browse files
committed
cln-plugin: add a hook builder to make use of before, after and filters options
1 parent 8732410 commit 9a6486e

File tree

5 files changed

+123
-7
lines changed

5 files changed

+123
-7
lines changed

plugins/examples/cln-plugin-startup.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use cln_plugin::options::{
77
DefaultStringArrayConfigOption, IntegerArrayConfigOption, IntegerConfigOption,
88
StringArrayConfigOption,
99
};
10-
use cln_plugin::{messages, Builder, Error, Plugin};
10+
use cln_plugin::{messages, Builder, Error, HookBuilder, Plugin};
1111

1212
const TEST_NOTIF_TAG: &str = "test_custom_notification";
1313

@@ -79,7 +79,12 @@ async fn main() -> Result<(), anyhow::Error> {
7979
.rpcmethod("test-log-levels", "send on all log levels", test_log_levels)
8080
.subscribe("connect", connect_handler)
8181
.subscribe("test_custom_notification", test_receive_custom_notification)
82-
.hook("peer_connected", peer_connected_handler)
82+
.hook_from_builder(
83+
HookBuilder::new("peer_connected", peer_connected_handler)
84+
.after(Vec::new())
85+
.before(Vec::new())
86+
.filters(Vec::new()),
87+
)
8388
.notification(messages::NotificationTopic::new(TEST_NOTIF_TAG))
8489
.start(state)
8590
.await?

plugins/lsps-plugin/src/client.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use cln_lsps::jsonrpc::client::JsonRpcClient;
55
use cln_lsps::lsps0::primitives::Msat;
66
use cln_lsps::lsps0::{
77
self,
8-
transport::{Bolt8Transport, CustomMessageHookManager, WithCustomMessageHookManager},
8+
transport::{
9+
Bolt8Transport, CustomMessageHookManager, WithCustomMessageHookManager, LSPS0_MESSAGE_TYPE,
10+
},
911
};
1012
use cln_lsps::lsps2::cln::tlv::encode_tu64;
1113
use cln_lsps::lsps2::cln::{
@@ -19,6 +21,7 @@ use cln_lsps::lsps2::model::{
1921
use cln_lsps::util;
2022
use cln_lsps::LSP_FEATURE_BIT;
2123
use cln_plugin::options;
24+
use cln_plugin::{HookBuilder, HookFilter};
2225
use cln_rpc::model::requests::{
2326
DatastoreMode, DatastoreRequest, DeldatastoreRequest, DelinvoiceRequest, DelinvoiceStatus,
2427
ListdatastoreRequest, ListinvoicesRequest, ListpeersRequest,
@@ -55,7 +58,10 @@ async fn main() -> Result<(), anyhow::Error> {
5558
let state = State { hook_manager };
5659

5760
if let Some(plugin) = cln_plugin::Builder::new(tokio::io::stdin(), tokio::io::stdout())
58-
.hook("custommsg", CustomMessageHookManager::on_custommsg::<State>)
61+
.hook_from_builder(
62+
HookBuilder::new("custommsg", CustomMessageHookManager::on_custommsg::<State>)
63+
.filters(vec![HookFilter::Int(i64::from(LSPS0_MESSAGE_TYPE))]),
64+
)
5965
.option(OPTION_ENABLED)
6066
.rpcmethod(
6167
"lsps-listprotocols",

plugins/lsps-plugin/src/service.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use cln_lsps::lsps2::model::{Lsps2BuyRequest, Lsps2GetInfoRequest};
1212
use cln_lsps::util::wrap_payload_with_peer_id;
1313
use cln_lsps::{lsps0, lsps2};
1414
use cln_plugin::Plugin;
15+
use cln_plugin::{HookBuilder, HookFilter};
1516
use cln_rpc::notifications::CustomMsgNotification;
1617
use cln_rpc::primitives::PublicKey;
1718
use log::debug;
@@ -42,7 +43,9 @@ async fn main() -> Result<(), anyhow::Error> {
4243
// cln_plugin::FeatureBitsKind::Init,
4344
// util::feature_bit_to_hex(LSP_FEATURE_BIT),
4445
// )
45-
.hook("custommsg", on_custommsg)
46+
.hook_from_builder(HookBuilder::new("custommsg", on_custommsg).filters(vec![
47+
HookFilter::Int(i64::from(lsps0::transport::LSPS0_MESSAGE_TYPE)),
48+
]))
4649
.hook("htlc_accepted", on_htlc_accepted)
4750
.configure()
4851
.await?

plugins/src/lib.rs

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::codec::{JsonCodec, JsonRpcCodec};
22
pub use anyhow::anyhow;
33
use anyhow::{Context, Result};
44
use futures::sink::SinkExt;
5+
use serde::Serialize;
56
use tokio::io::{AsyncReadExt, AsyncWriteExt};
67
extern crate log;
78
use log::trace;
@@ -204,12 +205,21 @@ where
204205
self.hooks.insert(
205206
hookname.to_string(),
206207
Hook {
208+
name: hookname.to_string(),
207209
callback: Box::new(move |p, r| Box::pin(callback(p, r))),
210+
before: Vec::new(),
211+
after: Vec::new(),
212+
filters: None,
208213
},
209214
);
210215
self
211216
}
212217

218+
pub fn hook_from_builder(mut self, hook: HookBuilder<S>) -> Builder<S, I, O> {
219+
self.hooks.insert(hook.name.clone(), hook.build());
220+
self
221+
}
222+
213223
/// Register a custom RPC method for the RPC passthrough from the
214224
/// main daemon
215225
pub fn rpcmethod<C, F>(mut self, name: &str, description: &str, callback: C) -> Builder<S, I, O>
@@ -411,10 +421,21 @@ where
411421
.chain(self.wildcard_subscription.iter().map(|_| String::from("*")))
412422
.collect();
413423

424+
let hooks: Vec<messages::Hook> = self
425+
.hooks
426+
.values()
427+
.map(|v| messages::Hook {
428+
name: v.name.clone(),
429+
before: v.before.clone(),
430+
after: v.after.clone(),
431+
filters: v.filters.clone(),
432+
})
433+
.collect();
434+
414435
messages::GetManifestResponse {
415436
options: self.options.values().cloned().collect(),
416437
subscriptions,
417-
hooks: self.hooks.keys().map(|s| s.clone()).collect(),
438+
hooks,
418439
rpcmethods,
419440
notifications: self.notifications.clone(),
420441
featurebits: self.featurebits.clone(),
@@ -458,6 +479,56 @@ where
458479
}
459480
}
460481

482+
impl<S> HookBuilder<S>
483+
where
484+
S: Send + Clone,
485+
{
486+
pub fn new<C, F>(name: &str, callback: C) -> Self
487+
where
488+
C: Send + Sync + 'static,
489+
C: Fn(Plugin<S>, Request) -> F + 'static,
490+
F: Future<Output = Response> + Send + 'static,
491+
{
492+
Self {
493+
name: name.to_string(),
494+
callback: Box::new(move |p, r| Box::pin(callback(p, r))),
495+
before: Vec::new(),
496+
after: Vec::new(),
497+
filters: None,
498+
}
499+
}
500+
501+
pub fn before(mut self, before: Vec<String>) -> Self {
502+
self.before = before;
503+
self
504+
}
505+
506+
pub fn after(mut self, after: Vec<String>) -> Self {
507+
self.after = after;
508+
self
509+
}
510+
511+
pub fn filters(mut self, filters: Vec<HookFilter>) -> Self {
512+
// Empty Vec would filter everything, must be None instead to not get serialized
513+
if filters.is_empty() {
514+
self.filters = None;
515+
} else {
516+
self.filters = Some(filters);
517+
}
518+
self
519+
}
520+
521+
fn build(self) -> Hook<S> {
522+
Hook {
523+
callback: self.callback,
524+
name: self.name,
525+
before: self.before,
526+
after: self.after,
527+
filters: self.filters,
528+
}
529+
}
530+
}
531+
461532
impl<S> RpcMethodBuilder<S>
462533
where
463534
S: Send + Clone,
@@ -542,7 +613,29 @@ struct Hook<S>
542613
where
543614
S: Clone + Send,
544615
{
616+
name: String,
617+
callback: AsyncCallback<S>,
618+
before: Vec<String>,
619+
after: Vec<String>,
620+
filters: Option<Vec<HookFilter>>,
621+
}
622+
623+
pub struct HookBuilder<S>
624+
where
625+
S: Clone + Send,
626+
{
627+
name: String,
545628
callback: AsyncCallback<S>,
629+
before: Vec<String>,
630+
after: Vec<String>,
631+
filters: Option<Vec<HookFilter>>,
632+
}
633+
634+
#[derive(Debug, Clone, Serialize)]
635+
#[serde(untagged)]
636+
pub enum HookFilter {
637+
Str(String),
638+
Int(i64),
546639
}
547640

548641
impl<S> Plugin<S>

plugins/src/messages.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::options::UntypedConfigOption;
2+
use crate::HookFilter;
23
use serde::de::{self, Deserializer};
34
use serde::{Deserialize, Serialize};
45
use serde_json::Value;
@@ -150,6 +151,14 @@ pub(crate) struct RpcMethod {
150151
pub(crate) usage: String,
151152
}
152153

154+
#[derive(Serialize, Default, Debug)]
155+
pub(crate) struct Hook {
156+
pub(crate) name: String,
157+
pub(crate) before: Vec<String>,
158+
pub(crate) after: Vec<String>,
159+
#[serde(skip_serializing_if = "Option::is_none")]
160+
pub(crate) filters: Option<Vec<HookFilter>>,
161+
}
153162
#[derive(Serialize, Default, Debug, Clone)]
154163
pub struct NotificationTopic {
155164
pub method: String,
@@ -175,7 +184,7 @@ pub(crate) struct GetManifestResponse {
175184
pub(crate) rpcmethods: Vec<RpcMethod>,
176185
pub(crate) subscriptions: Vec<String>,
177186
pub(crate) notifications: Vec<NotificationTopic>,
178-
pub(crate) hooks: Vec<String>,
187+
pub(crate) hooks: Vec<Hook>,
179188
pub(crate) dynamic: bool,
180189
pub(crate) featurebits: FeatureBits,
181190
pub(crate) nonnumericids: bool,

0 commit comments

Comments
 (0)