use dashmap::DashMap;
use tokio::sync::broadcast;
use crate::WatchEvent;
const ALL_CHANNEL: &str = "__all__";
#[derive(Clone)]
pub struct EventBus {
channels: DashMap<String, broadcast::Sender<WatchEvent>>,
}
impl EventBus {
pub fn new() -> Self {
let channels = DashMap::new();
let (tx, _) = broadcast::channel(256);
channels.insert(ALL_CHANNEL.to_string(), tx);
Self { channels }
}
fn get_or_create_sender(&self, key: &str) -> broadcast::Sender<WatchEvent> {
self.channels
.entry(key.to_string())
.or_insert_with(|| {
let (tx, _) = broadcast::channel(256);
tx
})
.clone()
}
pub fn publish(&self, event: WatchEvent) {
let repo_id = &event.repo_id;
if !repo_id.is_empty() {
let tx = self.get_or_create_sender(repo_id);
let _ = tx.send(event.clone());
}
if let Some(tx) = self.channels.get(ALL_CHANNEL) {
let _ = tx.send(event);
}
}
pub fn subscribe(&self, repo_id: &str) -> broadcast::Receiver<WatchEvent> {
self.channels
.entry(repo_id.to_string())
.or_insert_with(|| {
let (tx, _) = broadcast::channel(256);
tx
})
.subscribe()
}
pub fn subscribe_all(&self) -> broadcast::Receiver<WatchEvent> {
self.channels
.entry(ALL_CHANNEL.to_string())
.or_insert_with(|| {
let (tx, _) = broadcast::channel(256);
tx
})
.subscribe()
}
pub fn remove_repo(&self, repo_id: &str) {
if repo_id != ALL_CHANNEL {
self.channels.remove(repo_id);
}
}
pub fn cleanup_idle(&self) {
self.channels.retain(|key, sender| {
key == ALL_CHANNEL || sender.receiver_count() > 0
});
}
}