Skip to content

Commit c814064

Browse files
authored
Merge pull request #51 from G8XSU/2025-03-12-events
Introduce EventPublisher trait.
2 parents fbe65df + 5ffb7d8 commit c814064

File tree

16 files changed

+143
-18
lines changed

16 files changed

+143
-18
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ldk-server-protos/build.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ fn generate_protos() {
1515
prost_build::Config::new()
1616
.bytes(&["."])
1717
.compile_protos(
18-
&["src/proto/api.proto", "src/proto/types.proto", "src/proto/error.proto"],
18+
&[
19+
"src/proto/api.proto",
20+
"src/proto/types.proto",
21+
"src/proto/events.proto",
22+
"src/proto/error.proto",
23+
],
1924
&["src/proto/"],
2025
)
2126
.expect("protobuf compilation failed");
@@ -24,6 +29,8 @@ fn generate_protos() {
2429
fs::copy(from_path, "src/api.rs").unwrap();
2530
let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("types.rs");
2631
fs::copy(from_path, "src/types.rs").unwrap();
32+
let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("events.rs");
33+
fs::copy(from_path, "src/events.rs").unwrap();
2734
let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("error.rs");
2835
fs::copy(from_path, "src/error.rs").unwrap();
2936
}

ldk-server-protos/src/events.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// EventEnvelope wraps different event types in a single message to be used by EventPublisher.
2+
#[allow(clippy::derive_partial_eq_without_eq)]
3+
#[derive(Clone, PartialEq, ::prost::Message)]
4+
pub struct EventEnvelope {
5+
#[prost(oneof = "event_envelope::Event", tags = "2")]
6+
pub event: ::core::option::Option<event_envelope::Event>,
7+
}
8+
/// Nested message and enum types in `EventEnvelope`.
9+
pub mod event_envelope {
10+
#[allow(clippy::derive_partial_eq_without_eq)]
11+
#[derive(Clone, PartialEq, ::prost::Oneof)]
12+
pub enum Event {
13+
#[prost(message, tag = "2")]
14+
PaymentForwarded(super::PaymentForwarded),
15+
}
16+
}
17+
/// PaymentForwarded indicates a payment was forwarded through the node.
18+
#[allow(clippy::derive_partial_eq_without_eq)]
19+
#[derive(Clone, PartialEq, ::prost::Message)]
20+
pub struct PaymentForwarded {
21+
#[prost(message, optional, tag = "1")]
22+
pub forwarded_payment: ::core::option::Option<super::types::ForwardedPayment>,
23+
}

ldk-server-protos/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod api;
22
pub mod error;
3+
pub mod events;
34
pub mod types;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
syntax = "proto3";
2+
import "types.proto";
3+
package events;
4+
5+
// EventEnvelope wraps different event types in a single message to be used by EventPublisher.
6+
message EventEnvelope {
7+
oneof event {
8+
PaymentForwarded payment_forwarded = 2;
9+
}
10+
}
11+
12+
// PaymentForwarded indicates a payment was forwarded through the node.
13+
message PaymentForwarded {
14+
types.ForwardedPayment forwarded_payment = 1;
15+
}

ldk-server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ bytes = { version = "1.4.0", default-features = false }
1717
hex = { package = "hex-conservative", version = "0.2.1", default-features = false }
1818
rusqlite = { version = "0.31.0", features = ["bundled"] }
1919
rand = { version = "0.8.5", default-features = false }
20+
async-trait = { version = "0.1.85", default-features = false }

ldk-server/src/api/list_forwarded_payments.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::api::error::LdkServerError;
22
use crate::api::error::LdkServerErrorCode::InternalServerError;
3-
use crate::io::{
3+
use crate::io::persist::{
44
FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE,
55
FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE,
66
};

ldk-server/src/api/list_payments.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::api::error::LdkServerError;
22
use crate::api::error::LdkServerErrorCode::InternalServerError;
3-
use crate::io::{PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE};
3+
use crate::io::persist::{
4+
PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE,
5+
};
46
use crate::service::Context;
57
use bytes::Bytes;
68
use ldk_server_protos::api::{ListPaymentsRequest, ListPaymentsResponse};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use crate::api::error::LdkServerError;
2+
use async_trait::async_trait;
3+
use ldk_server_protos::events::EventEnvelope;
4+
5+
/// A trait for publishing events or notifications from the LDK Server.
6+
///
7+
/// Implementors of this trait define how events are sent to various messaging
8+
/// systems. It provides a consistent, asynchronous interface for event publishing, while allowing
9+
/// each implementation to manage its own initialization and configuration, typically sourced from
10+
/// the `ldk-server.config` file. A no-op implementation is included by default,
11+
/// with specific implementations enabled via feature flags.
12+
///
13+
/// Events are represented as [`EventEnvelope`] messages, which are Protocol Buffers
14+
/// ([protobuf](https://protobuf.dev/)) objects defined in [`ldk_server_protos::events`].
15+
/// These events are serialized to bytes by the publisher before transmission, and consumers can
16+
/// deserialize them using the protobuf definitions.
17+
///
18+
/// The underlying messaging system is expected to support durably buffered events,
19+
/// enabling easy decoupling between the LDK Server and event consumers.
20+
#[async_trait]
21+
pub trait EventPublisher {
22+
/// Publishes an event to the underlying messaging system.
23+
///
24+
/// # Arguments
25+
/// * `event` - The event message to publish, provided as an [`EventEnvelope`]
26+
/// defined in [`ldk_server_protos::events`]. Implementors must serialize
27+
/// the whole [`EventEnvelope`] to bytes before publishing.
28+
///
29+
/// In order to ensure no events are lost, implementors of this trait must publish events
30+
/// durably to underlying messaging system. An event is considered published when
31+
/// [`EventPublisher::publish`] returns `Ok(())`, thus implementors MUST durably persist/publish events *before*
32+
/// returning `Ok(())`.
33+
///
34+
/// # Errors
35+
/// May return an [`LdkServerErrorCode::InternalServerError`] if the event cannot be published,
36+
/// such as due to network failures, misconfiguration, or transport-specific issues.
37+
/// If event publishing fails, the LDK Server will retry publishing the event indefinitely, which
38+
/// may degrade performance until the underlying messaging system is operational again.
39+
///
40+
/// [`LdkServerErrorCode::InternalServerError`]: crate::api::error::LdkServerErrorCode
41+
async fn publish(&self, event: EventEnvelope) -> Result<(), LdkServerError>;
42+
}
43+
44+
pub(crate) struct NoopEventPublisher;
45+
46+
#[async_trait]
47+
impl EventPublisher for NoopEventPublisher {
48+
/// Publishes an event to a no-op sink, effectively discarding it.
49+
///
50+
/// This implementation does nothing and always returns `Ok(())`, serving as a
51+
/// default when no messaging system is configured.
52+
async fn publish(&self, _event: EventEnvelope) -> Result<(), LdkServerError> {
53+
Ok(())
54+
}
55+
}

ldk-server/src/io/events/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub(crate) mod event_publisher;

0 commit comments

Comments
 (0)