backbone_messaging/
subscriber.rs1use std::future::Future;
21use std::pin::Pin;
22use std::sync::Arc;
23
24use crate::envelope::EventEnvelope;
25use crate::error::EventError;
26use crate::event::DomainEvent;
27use crate::handler::EventHandler;
28
29pub type SubscriberCallback<Event> =
33 Arc<dyn Fn(Event) -> Pin<Box<dyn Future<Output = Result<(), EventError>> + Send>> + Send + Sync>;
34
35pub struct GenericEventSubscriber<Event: DomainEvent> {
44 subscribed_types: Vec<&'static str>,
47
48 handlers: Vec<Arc<dyn EventHandler<Event>>>,
50
51 name: &'static str,
53}
54
55impl<Event: DomainEvent + Clone> GenericEventSubscriber<Event> {
56 pub fn new(
61 subscribed_types: Vec<&'static str>,
62 handlers: Vec<Arc<dyn EventHandler<Event>>>,
63 ) -> Self {
64 Self {
65 subscribed_types,
66 handlers,
67 name: std::any::type_name::<Event>(),
68 }
69 }
70
71 pub fn all(handlers: Vec<Arc<dyn EventHandler<Event>>>) -> Self {
73 Self::new(vec![], handlers)
74 }
75
76 pub fn with_name(mut self, name: &'static str) -> Self {
78 self.name = name;
79 self
80 }
81
82 pub fn with_handler(mut self, handler: Arc<dyn EventHandler<Event>>) -> Self {
84 self.handlers.push(handler);
85 self
86 }
87
88 pub fn is_interested(&self, event_type: &str) -> bool {
90 self.subscribed_types.is_empty() || self.subscribed_types.contains(&event_type)
91 }
92
93 pub async fn dispatch(&self, event: Event) -> Result<(), EventError> {
98 if !self.is_interested(event.event_type()) {
99 return Ok(());
100 }
101 let envelope = EventEnvelope::new(event);
102 for handler in &self.handlers {
103 handler.handle(envelope.clone()).await?;
104 }
105 Ok(())
106 }
107
108 pub fn name(&self) -> &'static str {
110 self.name
111 }
112
113 pub fn subscribed_types(&self) -> &[&'static str] {
115 &self.subscribed_types
116 }
117
118 pub fn handler_count(&self) -> usize {
120 self.handlers.len()
121 }
122}
123
124pub struct SubscriberRegistry<Event: Clone + Send + Sync + 'static> {
132 subscribers: Vec<SubscriberCallback<Event>>,
133}
134
135impl<Event: Clone + Send + Sync + 'static> SubscriberRegistry<Event> {
136 pub fn new() -> Self {
137 Self {
138 subscribers: Vec::new(),
139 }
140 }
141
142 pub fn register<F, Fut>(&mut self, handler: F)
144 where
145 F: Fn(Event) -> Fut + Send + Sync + 'static,
146 Fut: Future<Output = Result<(), EventError>> + Send + 'static,
147 {
148 self.subscribers
149 .push(Arc::new(move |event| Box::pin(handler(event))));
150 }
151
152 pub async fn dispatch_all(&self, event: Event) -> Vec<EventError> {
154 let mut errors = Vec::new();
155 for subscriber in &self.subscribers {
156 if let Err(e) = subscriber(event.clone()).await {
157 errors.push(e);
158 }
159 }
160 errors
161 }
162
163 pub fn subscriber_count(&self) -> usize {
164 self.subscribers.len()
165 }
166}
167
168impl<Event: Clone + Send + Sync + 'static> Default for SubscriberRegistry<Event> {
169 fn default() -> Self {
170 Self::new()
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177 use crate::event::DomainEvent;
178
179 #[derive(Clone, Debug)]
181 struct FakeEvent {
182 event_type: &'static str,
183 id: String,
184 }
185
186 impl DomainEvent for FakeEvent {
187 fn event_type(&self) -> &'static str {
188 self.event_type
189 }
190 fn aggregate_id(&self) -> &str {
191 &self.id
192 }
193 }
194
195 struct CountingHandler {
197 count: Arc<tokio::sync::Mutex<u32>>,
198 }
199
200 impl CountingHandler {
201 fn new(count: Arc<tokio::sync::Mutex<u32>>) -> Self {
202 Self { count }
203 }
204 }
205
206 #[async_trait::async_trait]
207 impl EventHandler<FakeEvent> for CountingHandler {
208 async fn handle(&self, _envelope: EventEnvelope<FakeEvent>) -> Result<(), EventError> {
209 *self.count.lock().await += 1;
210 Ok(())
211 }
212 fn event_types(&self) -> Vec<&'static str> {
213 vec![]
214 }
215 }
216
217 #[tokio::test]
218 async fn subscriber_fires_for_matching_type() {
219 let count = Arc::new(tokio::sync::Mutex::new(0u32));
220 let handler = Arc::new(CountingHandler::new(count.clone()));
221
222 let subscriber = GenericEventSubscriber::new(
223 vec!["created"],
224 vec![handler as Arc<dyn EventHandler<FakeEvent>>],
225 );
226
227 assert!(subscriber.is_interested("created"));
228 assert!(!subscriber.is_interested("deleted"));
229
230 let event = FakeEvent { event_type: "created", id: "e1".into() };
231 subscriber.dispatch(event).await.unwrap();
232 assert_eq!(*count.lock().await, 1);
233 }
234
235 #[tokio::test]
236 async fn subscriber_skips_non_matching_type() {
237 let count = Arc::new(tokio::sync::Mutex::new(0u32));
238 let handler = Arc::new(CountingHandler::new(count.clone()));
239
240 let subscriber = GenericEventSubscriber::new(
241 vec!["created"],
242 vec![handler as Arc<dyn EventHandler<FakeEvent>>],
243 );
244
245 let event = FakeEvent { event_type: "deleted", id: "e1".into() };
246 subscriber.dispatch(event).await.unwrap();
247 assert_eq!(*count.lock().await, 0);
249 }
250
251 #[tokio::test]
252 async fn registry_dispatches_to_all_subscribers() {
253 let mut registry = SubscriberRegistry::<FakeEvent>::new();
254 let counter = Arc::new(tokio::sync::Mutex::new(0u32));
255
256 for _ in 0..3 {
257 let c = counter.clone();
258 registry.register(move |_event: FakeEvent| {
259 let cc = c.clone();
260 async move {
261 *cc.lock().await += 1;
262 Ok(())
263 }
264 });
265 }
266
267 let errors = registry
268 .dispatch_all(FakeEvent { event_type: "created", id: "1".into() })
269 .await;
270 assert!(errors.is_empty());
271 assert_eq!(*counter.lock().await, 3);
272 }
273}