use std::collections::HashMap; use std::sync::{Arc, Mutex}; use serde_json::Value; use tauri::{AppHandle, Manager}; use tokio::sync::mpsc; use tracing::{debug, info}; use uuid::Uuid; pub type EventHandler = Box; pub struct EventBus { subscribers: Arc>>>, sender: mpsc::UnboundedSender, } pub type SubscriptionId = String; #[derive(Clone, Debug)] pub struct Event { pub event_type: String, pub data: Value, pub timestamp: chrono::DateTime, pub source: String, } impl EventBus { pub fn new() -> Self { let (sender, mut receiver) = mpsc::unbounded_channel::(); let subscribers: Arc>>> = Arc::new(Mutex::new(HashMap::new())); let subs_clone = subscribers.clone(); // Event dispatch loop tokio::spawn(async move { while let Some(event) = receiver.recv().await { let subs = subs_clone.lock().unwrap(); if let Some(handlers) = subs.get(&event.event_type) { for (_, handler) in handlers.iter() { handler(event.data.clone()); } } // Also dispatch to wildcard subscribers if let Some(wildcard_handlers) = subs.get("*") { for (_, handler) in wildcard_handlers.iter() { handler(event.data.clone()); } } } }); Self { subscribers, sender, } } pub fn subscribe( &self, event_type: &str, handler_id: String ) -> SubscriptionId { let id = Uuid::new_v4().to_string(); // Store subscription info - actual handler would be connected via frontend let mut subs = self.subscribers.lock().unwrap(); let handlers = subs.entry(event_type.to_string()).or_insert_with(Vec::new); // Create a handler that emits to frontend let handler = Box::new(move |data: Value| { debug!("Event {} dispatched to {}", event_type, handler_id); // Frontend callback handled via Tauri events }) as EventHandler; handlers.push((id.clone(), handler)); info!("Subscribed {} to event type {}", id, event_type); id } pub fn unsubscribe(&self, subscription_id: &str) { let mut subs = self.subscribers.lock().unwrap(); for handlers in subs.values_mut() { handlers.retain(|(id, _)| id != subscription_id); } info!("Unsubscribed {}", subscription_id); } pub fn publish(&self, event_type: &str, data: Value ) { let event = Event { event_type: event_type.to_string(), data, timestamp: chrono::Utc::now(), source: "core".to_string(), }; let _ = self.sender.send(event); debug!("Published event: {}", event_type); } pub fn emit_to_frontend( &self, app_handle: &tauri::AppHandle, event_type: &str, data: Value ) { app_handle.emit_all(event_type, data).ok(); } }