1use std::marker::PhantomData;
4use std::sync::Arc;
5
6use rskit_errors::{AppError, AppResult, ErrorCode};
7use tokio::sync::broadcast;
8
9use crate::Event;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct EventBusConfig {
14 pub capacity: usize,
19}
20
21impl Default for EventBusConfig {
22 fn default() -> Self {
23 Self { capacity: 1024 }
24 }
25}
26
27pub struct EventBus<E: Event> {
32 sender: broadcast::Sender<Arc<E>>,
33}
34
35impl<E: Event> Clone for EventBus<E> {
36 fn clone(&self) -> Self {
37 Self {
38 sender: self.sender.clone(),
39 }
40 }
41}
42
43impl<E: Event> EventBus<E> {
44 #[must_use]
46 pub fn new(config: EventBusConfig) -> Self {
47 let capacity = config.capacity.max(1);
48 let (sender, _) = broadcast::channel(capacity);
49 Self { sender }
50 }
51
52 pub fn publish(&self, event: E) -> AppResult<usize> {
57 self.sender.send(Arc::new(event)).or(Ok(0))
58 }
59
60 #[must_use]
62 pub fn subscribe(&self) -> Subscriber<E> {
63 Subscriber {
64 receiver: self.sender.subscribe(),
65 }
66 }
67}
68
69pub struct EventRegistry<E: Event> {
71 bus: EventBus<E>,
72}
73
74impl<E: Event> EventRegistry<E> {
75 #[must_use]
77 pub fn new(config: EventBusConfig) -> Self {
78 Self {
79 bus: EventBus::new(config),
80 }
81 }
82
83 #[must_use]
85 pub fn publisher(&self) -> EventBus<E> {
86 self.bus.clone()
87 }
88
89 #[must_use]
91 pub fn register_subscriber(&self) -> Subscriber<E> {
92 self.bus.subscribe()
93 }
94}
95
96impl<E: Event> Default for EventRegistry<E> {
97 fn default() -> Self {
98 Self::new(EventBusConfig::default())
99 }
100}
101
102pub struct Subscriber<E: Event> {
104 receiver: broadcast::Receiver<Arc<E>>,
105}
106
107impl<E: Event> Subscriber<E> {
108 pub async fn recv(&mut self) -> AppResult<Arc<E>> {
113 self.receiver.recv().await.map_err(|error| match error {
114 broadcast::error::RecvError::Closed => {
115 AppError::new(ErrorCode::Cancelled, "event bus publisher closed")
116 }
117 broadcast::error::RecvError::Lagged(skipped) => AppError::new(
118 ErrorCode::RateLimited,
119 format!("event subscriber lagged by {skipped} messages"),
120 ),
121 })
122 }
123}
124
125impl<E: Event> std::fmt::Debug for EventBus<E> {
126 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127 f.debug_struct("EventBus")
128 .field("event_type", &std::any::type_name::<E>())
129 .field("receiver_count", &self.sender.receiver_count())
130 .finish()
131 }
132}
133
134impl<E: Event> std::fmt::Debug for EventRegistry<E> {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 f.debug_struct("EventRegistry")
137 .field("event_type", &std::any::type_name::<E>())
138 .finish_non_exhaustive()
139 }
140}
141
142impl<E: Event> std::fmt::Debug for Subscriber<E> {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 let _phantom = PhantomData::<E>;
145 f.debug_struct("Subscriber")
146 .field("event_type", &std::any::type_name::<E>())
147 .finish_non_exhaustive()
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::{EventBus, EventBusConfig, EventRegistry};
154 use crate::{Event, EventType};
155
156 #[derive(Debug)]
157 struct Ping(u32);
158
159 impl Event for Ping {
160 fn event_type(&self) -> EventType {
161 EventType::new("ping")
162 }
163 }
164
165 #[tokio::test]
166 async fn bus_publishes_to_registered_subscriber() {
167 let bus = EventBus::<Ping>::new(EventBusConfig { capacity: 4 });
168 let mut subscriber = bus.subscribe();
169
170 assert_eq!(bus.publish(Ping(7)).expect("publish"), 1);
171 let event = subscriber.recv().await.expect("receive");
172 assert_eq!(event.0, 7);
173 }
174
175 #[tokio::test]
176 async fn publish_without_subscribers_succeeds() {
177 let bus = EventBus::<Ping>::new(EventBusConfig { capacity: 4 });
178 assert_eq!(bus.publish(Ping(1)).expect("publish"), 0);
179 }
180
181 #[tokio::test]
182 async fn subscriber_reports_lag() {
183 let bus = EventBus::<Ping>::new(EventBusConfig { capacity: 1 });
184 let mut subscriber = bus.subscribe();
185
186 let _ = bus.publish(Ping(1)).expect("first");
187 let _ = bus.publish(Ping(2)).expect("second");
188 let err = subscriber.recv().await.expect_err("lag should be reported");
189 assert_eq!(err.code(), rskit_errors::ErrorCode::RateLimited);
190 }
191
192 #[test]
193 fn event_registry_registers_subscribers_explicitly() {
194 let registry = EventRegistry::<Ping>::new(EventBusConfig { capacity: 4 });
195 let _subscriber = registry.register_subscriber();
196 let publisher = registry.publisher();
197 assert_eq!(publisher.publish(Ping(1)).expect("publish"), 1);
198 }
199}