use anyhow::{Result, bail};
use super::channel::Channel;
pub struct ChannelOrchestrator {
channels: Vec<Box<dyn Channel>>,
}
impl ChannelOrchestrator {
pub fn new() -> Self {
Self {
channels: Vec::new(),
}
}
pub fn add(&mut self, channel: Box<dyn Channel>) {
self.channels.push(channel);
}
pub fn is_empty(&self) -> bool {
self.channels.is_empty()
}
pub fn channel_names(&self) -> Vec<&'static str> {
self.channels.iter().map(|c| c.name()).collect()
}
pub async fn run(self) -> Result<()> {
if self.channels.is_empty() {
bail!("No channels configured");
}
let names = self.channel_names();
crate::log_info!("Starting {} channel(s): {}", names.len(), names.join(", "));
let mut total_restored = 0usize;
let mut channels = self.channels;
for channel in channels.iter_mut() {
if let Some(store) = channel.store() {
match channel.restore_sessions(store.clone()) {
Ok(count) => total_restored += count,
Err(e) => {
crate::log_error!(
"Failed to restore sessions for {}: {}",
channel.name(),
e
);
}
}
}
}
if total_restored > 0 {
crate::log_info!("Restored {} session(s) from disk", total_restored);
}
let mut handles = Vec::new();
for mut channel in channels {
let handle = tokio::task::spawn_local(async move {
let name = channel.name();
if let Err(e) = channel.run().await {
crate::log_error!("Channel {} failed: {}", name, e);
Err(e)
} else {
Ok(())
}
});
handles.push(handle);
}
let mut any_error = None;
for handle in handles {
match handle.await {
Ok(Ok(())) => {}
Ok(Err(e)) => {
if any_error.is_none() {
any_error = Some(e);
}
}
Err(e) => {
crate::log_error!("Channel task panicked: {}", e);
if any_error.is_none() {
any_error = Some(anyhow::anyhow!("Channel task panicked: {}", e));
}
}
}
}
if let Some(e) = any_error {
Err(e)
} else {
Ok(())
}
}
}
impl Default for ChannelOrchestrator {
fn default() -> Self {
Self::new()
}
}