use crate::hub::hub_event::HubEvent;
use std::sync::{Arc, LazyLock};
use tokio::sync::broadcast;
pub struct Hub {
tx: Arc<broadcast::Sender<HubEvent>>,
_rx: broadcast::Receiver<HubEvent>,
}
impl Hub {
pub fn new() -> Self {
let (tx, _rx) = broadcast::channel(500);
Self { tx: Arc::new(tx), _rx }
}
pub async fn publish(&self, event: impl Into<HubEvent>) {
let event = event.into();
match self.tx.send(event) {
Ok(_) => (),
Err(err) => println!("AIPACK INTERNAL ERROR - failed to send event to hub - {err}"),
}
}
pub fn publish_sync(&self, event: impl Into<HubEvent>) {
tokio::task::block_in_place(|| {
let event = event.into();
let rt = tokio::runtime::Handle::try_current();
match rt {
Ok(rt) => rt.block_on(async { self.publish(event).await }),
Err(err) => println!("AIPACK INTERNAL ERROR - no current tokio handle - {err}"),
}
});
}
pub fn subscriber(&self) -> broadcast::Receiver<HubEvent> {
self.tx.subscribe()
}
}
static HUB: LazyLock<Hub> = LazyLock::new(Hub::new);
pub fn get_hub() -> &'static Hub {
&HUB
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_hub() {
let hub = get_hub();
let mut rx = hub.subscriber();
tokio::spawn(async move {
while let Ok(event) = rx.recv().await {
#[allow(clippy::single_match)]
match event {
HubEvent::Message(msg) => {
println!("Received Message: {}", msg);
}
_ => (),
}
}
});
hub.publish(HubEvent::Message("Hello, world!".into())).await;
}
}