//! Système d'événements et d'abonnements générique pour les nodes //! //! Ce module fournit une infrastructure d'abonnement type-safe permettant //! à chaque node d'émettre et de recevoir différents types d'événements. use crate::AudioChunk; use std::sync::Arc; use tokio::sync::mpsc; /// Trait de base pour tous les événements de node /// /// Chaque type d'événement doit implémenter ce trait pour pouvoir /// être utilisé dans le système d'abonnement. pub trait NodeEvent: Send + Sync + Clone + 'static {} /// Événement : données audio disponibles #[derive(Debug, Clone)] pub struct AudioDataEvent { pub chunk: Arc, } impl NodeEvent for AudioDataEvent {} /// Événement : changement de volume #[derive(Debug, Clone)] pub struct VolumeChangeEvent { pub volume: f32, pub source_node_id: String, } impl NodeEvent for VolumeChangeEvent {} /// Événement : mise à jour du nom de la source #[derive(Debug, Clone)] pub struct SourceNameUpdateEvent { pub source_name: String, pub device_name: Option, } impl NodeEvent for SourceNameUpdateEvent {} /// Trait pour les listeners d'événements /// /// Les nodes qui souhaitent recevoir des événements d'un type particulier /// doivent implémenter ce trait pour ce type. #[async_trait::async_trait] pub trait NodeListener: Send + Sync { /// Appelé lorsqu'un événement est reçu async fn on_event(&self, event: E); } /// Gestionnaire d'abonnements pour un type d'événement spécifique /// /// Permet d'enregistrer des listeners et de broadcaster des événements. #[derive(Clone)] pub struct EventPublisher { subscribers: Vec>, } impl EventPublisher { /// Crée un nouveau publisher vide pub fn new() -> Self { Self { subscribers: Vec::new(), } } /// Ajoute un subscriber via un channel pub fn subscribe(&mut self, tx: mpsc::Sender) { self.subscribers.push(tx); } /// Publie un événement à tous les subscribers pub async fn publish(&self, event: E) { for tx in &self.subscribers { // Utiliser try_send pour éviter de bloquer si un subscriber est lent let _ = tx.try_send(event.clone()); } } /// Publie un événement de manière bloquante (attend que tous les subscribers reçoivent) pub async fn publish_blocking(&self, event: E) { for tx in &self.subscribers { let _ = tx.send(event.clone()).await; } } /// Retourne le nombre de subscribers actifs pub fn subscriber_count(&self) -> usize { self.subscribers.len() } } impl Default for EventPublisher { fn default() -> Self { Self::new() } } /// Helper pour créer un listener basé sur une closure pub struct ClosureListener where F: Fn(E) + Send + Sync + 'static, { callback: Arc, _phantom: std::marker::PhantomData, } impl ClosureListener where F: Fn(E) + Send + Sync + 'static, { pub fn new(callback: F) -> Self { Self { callback: Arc::new(callback), _phantom: std::marker::PhantomData, } } } #[async_trait::async_trait] impl NodeListener for ClosureListener where F: Fn(E) + Send + Sync + 'static, { async fn on_event(&self, event: E) { (self.callback)(event); } } /// Receiver helper pour consommer des événements depuis un channel pub struct EventReceiver { rx: mpsc::Receiver, } impl EventReceiver { /// Crée un nouveau receiver pub fn new(rx: mpsc::Receiver) -> Self { Self { rx } } /// Attend le prochain événement pub async fn recv(&mut self) -> Option { self.rx.recv().await } /// Tente de recevoir un événement sans bloquer pub fn try_recv(&mut self) -> Result { self.rx.try_recv() } } /// Macro pour faciliter la création de publishers multiples dans un node /// /// # Exemple /// /// ```ignore /// struct MyNode { /// audio_publisher: EventPublisher, /// volume_publisher: EventPublisher, /// } /// ``` #[macro_export] macro_rules! publishers { ($($field:ident: $event_type:ty),* $(,)?) => { $( pub $field: $crate::events::EventPublisher<$event_type>, )* }; } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_event_publisher_basic() { let mut publisher = EventPublisher::::new(); let (tx, mut rx) = mpsc::channel(10); publisher.subscribe(tx); let event = VolumeChangeEvent { volume: 0.5, source_node_id: "test".to_string(), }; publisher.publish(event.clone()).await; let received = rx.recv().await.unwrap(); assert_eq!(received.volume, 0.5); assert_eq!(received.source_node_id, "test"); } #[tokio::test] async fn test_multiple_subscribers() { let mut publisher = EventPublisher::::new(); let (tx1, mut rx1) = mpsc::channel(10); let (tx2, mut rx2) = mpsc::channel(10); publisher.subscribe(tx1); publisher.subscribe(tx2); let event = VolumeChangeEvent { volume: 0.7, source_node_id: "test".to_string(), }; publisher.publish(event.clone()).await; let received1 = rx1.recv().await.unwrap(); let received2 = rx2.recv().await.unwrap(); assert_eq!(received1.volume, 0.7); assert_eq!(received2.volume, 0.7); } #[tokio::test] async fn test_event_receiver() { let (tx, rx) = mpsc::channel(10); let mut receiver = EventReceiver::new(rx); let event = VolumeChangeEvent { volume: 0.3, source_node_id: "test".to_string(), }; tx.send(event.clone()).await.unwrap(); let received = receiver.recv().await.unwrap(); assert_eq!(received.volume, 0.3); } }