Skip to main content

arcly_http/
event.rs

1//! Lock-free async event bus. Listeners register once; emissions iterate a
2//! frozen snapshot under a single `RwLock` read.
3
4use std::collections::HashMap;
5use std::sync::{Arc, RwLock};
6
7use futures::future::{join_all, BoxFuture};
8
9pub trait Listener: Send + Sync + 'static {
10    fn on_event(&self, payload: &serde_json::Value) -> BoxFuture<'static, ()>;
11}
12
13type Listeners = HashMap<&'static str, Vec<Arc<dyn Listener>>>;
14
15#[derive(Default, Clone)]
16pub struct EventBus {
17    inner: Arc<RwLock<Listeners>>,
18}
19
20impl EventBus {
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    pub fn subscribe(&self, event: &'static str, listener: Arc<dyn Listener>) {
26        self.inner
27            .write()
28            .unwrap()
29            .entry(event)
30            .or_default()
31            .push(listener);
32    }
33
34    pub async fn emit(&self, event: &'static str, payload: serde_json::Value) {
35        let snapshot: Vec<Arc<dyn Listener>> = self
36            .inner
37            .read()
38            .unwrap()
39            .get(event)
40            .cloned()
41            .unwrap_or_default();
42        let futs = snapshot.iter().map(|l| l.on_event(&payload));
43        join_all(futs).await;
44    }
45}