use super::types::{ChannelPlugin, MessageHandler};
use echo_core::error::Result;
use std::collections::HashMap;
use std::sync::Arc;
use tracing::{info, warn};
pub struct ChannelManager {
channels: HashMap<String, Box<dyn ChannelPlugin>>,
}
impl Default for ChannelManager {
fn default() -> Self {
Self::new()
}
}
impl ChannelManager {
pub fn new() -> Self {
Self {
channels: HashMap::new(),
}
}
pub fn register(&mut self, plugin: Box<dyn ChannelPlugin>) {
let id = plugin.id().to_string();
info!("Registering channel: {}", id);
self.channels.insert(id, plugin);
}
pub fn len(&self) -> usize {
self.channels.len()
}
pub fn is_empty(&self) -> bool {
self.channels.is_empty()
}
pub async fn start_all(
&mut self,
handler_factory: impl Fn(&str) -> Arc<dyn MessageHandler> + Sync,
) -> Vec<Result<()>> {
info!("Starting all channels (count: {})", self.channels.len());
let mut results = Vec::with_capacity(self.channels.len());
for (id, plugin) in self.channels.iter_mut() {
let handler = handler_factory(id);
match plugin.start(handler).await {
Ok(()) => {
info!("Channel '{}' started successfully", id);
results.push(Ok(()));
}
Err(e) => {
warn!("Failed to start channel '{}': {}", id, e);
results.push(Err(e));
}
}
}
results
}
pub async fn stop(&mut self, channel_id: &str) -> Result<()> {
if let Some(plugin) = self.channels.get_mut(channel_id) {
info!("Stopping channel: {}", channel_id);
plugin.stop().await?;
info!("Channel '{}' stopped", channel_id);
Ok(())
} else {
Err(echo_core::error::ReactError::Channel(
echo_core::error::ChannelError::Other(format!(
"Channel '{}' not found",
channel_id
)),
))
}
}
pub async fn stop_all(&mut self) -> Result<()> {
info!("Stopping all channels...");
for (id, plugin) in self.channels.iter_mut() {
match plugin.stop().await {
Ok(()) => info!("Channel '{}' stopped", id),
Err(e) => warn!("Failed to stop channel '{}': {}", id, e),
}
}
Ok(())
}
pub fn get(&self, id: &str) -> Option<&(dyn ChannelPlugin + '_)> {
match self.channels.get(id) {
Some(plugin) => Some(plugin.as_ref()),
None => None,
}
}
pub fn get_mut(&mut self, id: &str) -> Option<&mut (dyn ChannelPlugin + '_)> {
match self.channels.get_mut(id) {
Some(plugin) => Some(plugin.as_mut()),
None => None,
}
}
pub fn channel_ids(&self) -> Vec<&str> {
self.channels.keys().map(|k| k.as_str()).collect()
}
}
impl Drop for ChannelManager {
fn drop(&mut self) {
if !self.channels.is_empty() {
info!(
"ChannelManager dropped with {} channels remaining, \
consider calling stop_all() before drop",
self.channels.len()
);
}
}
}