use crate::node::NodeRunner;
use crate::supervisor::{NodeHandle, Supervisor};
use anyhow::Result;
use mecha10_core::rwlock_collections::RwLockMapExt;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
pub type NodeFactory = Box<dyn Fn() -> Box<dyn NodeRunner> + Send + Sync>;
pub struct Launcher {
supervisor: Arc<Supervisor>,
factories: Arc<RwLock<HashMap<String, NodeFactory>>>,
running_nodes: Arc<RwLock<HashMap<String, NodeHandle>>>,
}
impl Launcher {
pub fn new(supervisor: Arc<Supervisor>) -> Self {
Self {
supervisor,
factories: Arc::new(RwLock::new(HashMap::new())),
running_nodes: Arc::new(RwLock::new(HashMap::new())),
}
}
pub async fn register<F>(&self, node_type: String, factory: F)
where
F: Fn() -> Box<dyn NodeRunner> + Send + Sync + 'static,
{
let mut factories = self.factories.write().await;
factories.insert(node_type, Box::new(factory));
}
pub async fn launch(&self, node_type: &str) -> Result<String> {
let factories = self.factories.read().await;
let factory = factories
.get(node_type)
.ok_or_else(|| anyhow::anyhow!("Unknown node type: {}", node_type))?;
let node = factory();
let node_name = node.name().to_string();
let running = self.running_nodes.read().await;
if running.contains_key(&node_name) {
anyhow::bail!("Node already running: {}", node_name);
}
drop(running);
let handle = self.supervisor.launch_node(node);
let name = handle.name().to_string();
let mut running = self.running_nodes.write().await;
running.insert(name.clone(), handle);
Ok(name)
}
pub async fn stop(&self, node_name: &str) -> Result<()> {
let mut running = self.running_nodes.write().await;
let handle = running
.remove(node_name)
.ok_or_else(|| anyhow::anyhow!("Node not running: {}", node_name))?;
handle.abort();
Ok(())
}
pub async fn list_running(&self) -> Vec<String> {
let running = self.running_nodes.read().await;
running.keys().cloned().collect()
}
pub async fn is_running(&self, node_name: &str) -> bool {
let running = self.running_nodes.read().await;
running.contains_key(node_name)
}
pub async fn list_types(&self) -> Vec<String> {
self.factories.cloned_keys().await
}
}