use async_trait::async_trait; use log::{debug, info}; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::{mpsc, Mutex}; use crate::shared::models::BotResponse; #[async_trait] pub trait ChannelAdapter: Send + Sync { async fn send_message( &self, response: BotResponse, ) -> Result<(), Box>; } pub struct WebChannelAdapter { connections: Arc>>>, } impl WebChannelAdapter { pub fn new() -> Self { Self { connections: Arc::new(Mutex::new(HashMap::new())), } } pub async fn add_connection(&self, session_id: String, tx: mpsc::Sender) { self.connections.lock().await.insert(session_id, tx); } pub async fn remove_connection(&self, session_id: &str) { self.connections.lock().await.remove(session_id); } pub async fn send_message_to_session( &self, session_id: &str, message: BotResponse, ) -> Result<(), Box> { let connections = self.connections.lock().await; if let Some(tx) = connections.get(session_id) { if let Err(e) = tx.send(message).await { log::error!( "Failed to send message to WebSocket session {}: {}", session_id, e ); return Err(Box::new(e)); } debug!("Message sent to WebSocket session: {}", session_id); Ok(()) } else { debug!("No WebSocket connection found for session: {}", session_id); Err("No WebSocket connection found".into()) } } } #[async_trait] impl ChannelAdapter for WebChannelAdapter { async fn send_message( &self, response: BotResponse, ) -> Result<(), Box> { let connections = self.connections.lock().await; if let Some(tx) = connections.get(&response.session_id) { tx.send(response).await?; } Ok(()) } } pub struct VoiceAdapter { livekit_url: String, api_key: String, api_secret: String, rooms: Arc>>, connections: Arc>>>, } impl VoiceAdapter { pub fn new(livekit_url: String, api_key: String, api_secret: String) -> Self { Self { livekit_url, api_key, api_secret, rooms: Arc::new(Mutex::new(HashMap::new())), connections: Arc::new(Mutex::new(HashMap::new())), } } pub async fn start_voice_session( &self, session_id: &str, user_id: &str, ) -> Result> { info!( "Starting voice session for user: {} with session: {}", user_id, session_id ); let token = format!("mock_token_{}_{}", session_id, user_id); self.rooms .lock() .await .insert(session_id.to_string(), token.clone()); Ok(token) } pub async fn stop_voice_session( &self, session_id: &str, ) -> Result<(), Box> { self.rooms.lock().await.remove(session_id); Ok(()) } pub async fn add_connection(&self, session_id: String, tx: mpsc::Sender) { self.connections.lock().await.insert(session_id, tx); } pub async fn send_voice_response( &self, session_id: &str, text: &str, ) -> Result<(), Box> { info!("Sending voice response to session {}: {}", session_id, text); Ok(()) } } #[async_trait] impl ChannelAdapter for VoiceAdapter { async fn send_message( &self, response: BotResponse, ) -> Result<(), Box> { info!("Sending voice response to: {}", response.user_id); self.send_voice_response(&response.session_id, &response.content) .await } }