mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-24 01:24:26 +01:00
cln-plugin: Make notification handlers asynchronous
This commit is contained in:
committed by
Rusty Russell
parent
af4eed3787
commit
1bd2b8c9f7
@@ -3,7 +3,6 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
use cln_plugin::{options, Builder, Error, Plugin};
|
use cln_plugin::{options, Builder, Error, Plugin};
|
||||||
use std::pin::Pin;
|
|
||||||
use tokio;
|
use tokio;
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), anyhow::Error> {
|
async fn main() -> Result<(), anyhow::Error> {
|
||||||
@@ -14,7 +13,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||||||
"a test-option with default 42",
|
"a test-option with default 42",
|
||||||
))
|
))
|
||||||
.rpcmethod("testmethod", "This is a test", testmethod)
|
.rpcmethod("testmethod", "This is a test", testmethod)
|
||||||
.subscribe("connect", Box::new(connect_handler))
|
.subscribe("connect", connect_handler)
|
||||||
.hook("peer_connected", peer_connected_handler)
|
.hook("peer_connected", peer_connected_handler)
|
||||||
.start()
|
.start()
|
||||||
.await?;
|
.await?;
|
||||||
@@ -25,7 +24,7 @@ async fn testmethod(_p: Plugin<()>, _v: serde_json::Value) -> Result<serde_json:
|
|||||||
Ok(json!("Hello"))
|
Ok(json!("Hello"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_handler(_p: Plugin<()>, v: &serde_json::Value) -> Result<(), Error> {
|
async fn connect_handler(_p: Plugin<()>, v: serde_json::Value) -> Result<(), Error> {
|
||||||
log::info!("Got a connect notification: {}", v);
|
log::info!("Got a connect notification: {}", v);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,10 +71,36 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subscribe to notifications for the given `topic`.
|
/// Subscribe to notifications for the given `topic`. The handler
|
||||||
pub fn subscribe(mut self, topic: &str, callback: NotificationCallback<S>) -> Builder<S, I, O> {
|
/// is an async function that takes a `Plugin<S>` and the
|
||||||
self.subscriptions
|
/// notification as a `serde_json::Value` as inputs. Since
|
||||||
.insert(topic.to_string(), Subscription { callback });
|
/// notifications do not expect a result the handler should only
|
||||||
|
/// report errors while processing. Any error reported while
|
||||||
|
/// processing the notification will be logged in the cln logs.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use cln_plugin::{options, Builder, Error, Plugin};
|
||||||
|
///
|
||||||
|
/// async fn connect_handler(_p: Plugin<()>, v: serde_json::Value) -> Result<(), Error> {
|
||||||
|
/// println!("Got a connect notification: {}", v);
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let b = Builder::new((), tokio::io::stdin(), tokio::io::stdout())
|
||||||
|
/// .subscribe("connect", connect_handler);
|
||||||
|
/// ```
|
||||||
|
pub fn subscribe<C, F>(mut self, topic: &str, callback: C) -> Builder<S, I, O>
|
||||||
|
where
|
||||||
|
C: Send + Sync + 'static,
|
||||||
|
C: Fn(Plugin<S>, Request) -> F + 'static,
|
||||||
|
F: Future<Output = Result<(), Error>> + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
self.subscriptions.insert(
|
||||||
|
topic.to_string(),
|
||||||
|
Subscription {
|
||||||
|
callback: Box::new(move |p, r| Box::pin(callback(p, r))),
|
||||||
|
},
|
||||||
|
);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +281,11 @@ type Request = serde_json::Value;
|
|||||||
type Response = Result<serde_json::Value, Error>;
|
type Response = Result<serde_json::Value, Error>;
|
||||||
type AsyncCallback<S> =
|
type AsyncCallback<S> =
|
||||||
Box<dyn Fn(Plugin<S>, Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync>;
|
Box<dyn Fn(Plugin<S>, Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync>;
|
||||||
type NotificationCallback<S> = Box<fn(Plugin<S>, &Request) -> Result<(), Error>>;
|
type AsyncNotificationCallback<S> = Box<
|
||||||
|
dyn Fn(Plugin<S>, Request) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>>
|
||||||
|
+ Send
|
||||||
|
+ Sync,
|
||||||
|
>;
|
||||||
|
|
||||||
/// A struct collecting the metadata required to register a custom
|
/// A struct collecting the metadata required to register a custom
|
||||||
/// rpcmethod with the main daemon upon init. It'll get deconstructed
|
/// rpcmethod with the main daemon upon init. It'll get deconstructed
|
||||||
@@ -273,7 +303,7 @@ struct Subscription<S>
|
|||||||
where
|
where
|
||||||
S: Clone + Send,
|
S: Clone + Send,
|
||||||
{
|
{
|
||||||
callback: NotificationCallback<S>,
|
callback: AsyncNotificationCallback<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Hook<S>
|
struct Hook<S>
|
||||||
@@ -312,7 +342,7 @@ where
|
|||||||
|
|
||||||
#[allow(dead_code)] // Unused until we fill in the Hook structs.
|
#[allow(dead_code)] // Unused until we fill in the Hook structs.
|
||||||
hooks: HashMap<String, AsyncCallback<S>>,
|
hooks: HashMap<String, AsyncCallback<S>>,
|
||||||
subscriptions: HashMap<String, NotificationCallback<S>>,
|
subscriptions: HashMap<String, AsyncNotificationCallback<S>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
@@ -464,7 +494,7 @@ where
|
|||||||
method,
|
method,
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
if let Err(e) = callback(plugin.clone(), params) {
|
if let Err(e) = callback(plugin.clone(), params.clone()).await {
|
||||||
log::error!("Error in notification handler '{}': {}", method, e);
|
log::error!("Error in notification handler '{}': {}", method, e);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user