mecha10_runtime/
launcher.rs

1//! Launcher service integration for dynamic node launching
2
3use crate::node::NodeRunner;
4use crate::supervisor::{NodeHandle, Supervisor};
5use anyhow::Result;
6use std::collections::HashMap;
7use std::sync::Arc;
8use tokio::sync::RwLock;
9
10/// Registry for node types that can be dynamically launched
11pub type NodeFactory = Box<dyn Fn() -> Box<dyn NodeRunner> + Send + Sync>;
12
13/// Launcher service for dynamic node management
14pub struct Launcher {
15    supervisor: Arc<Supervisor>,
16    factories: Arc<RwLock<HashMap<String, NodeFactory>>>,
17    running_nodes: Arc<RwLock<HashMap<String, NodeHandle>>>,
18}
19
20impl Launcher {
21    /// Create a new launcher
22    pub fn new(supervisor: Arc<Supervisor>) -> Self {
23        Self {
24            supervisor,
25            factories: Arc::new(RwLock::new(HashMap::new())),
26            running_nodes: Arc::new(RwLock::new(HashMap::new())),
27        }
28    }
29
30    /// Register a node type with a factory function
31    pub async fn register<F>(&self, node_type: String, factory: F)
32    where
33        F: Fn() -> Box<dyn NodeRunner> + Send + Sync + 'static,
34    {
35        let mut factories = self.factories.write().await;
36        factories.insert(node_type, Box::new(factory));
37    }
38
39    /// Launch a node by type name
40    pub async fn launch(&self, node_type: &str) -> Result<String> {
41        let factories = self.factories.read().await;
42        let factory = factories
43            .get(node_type)
44            .ok_or_else(|| anyhow::anyhow!("Unknown node type: {}", node_type))?;
45
46        let node = factory();
47        let node_name = node.name().to_string();
48
49        // Check if already running
50        let running = self.running_nodes.read().await;
51        if running.contains_key(&node_name) {
52            anyhow::bail!("Node already running: {}", node_name);
53        }
54        drop(running);
55
56        // Launch the node
57        let handle = self.supervisor.launch_node(node);
58        let name = handle.name().to_string();
59
60        let mut running = self.running_nodes.write().await;
61        running.insert(name.clone(), handle);
62
63        Ok(name)
64    }
65
66    /// Stop a running node
67    pub async fn stop(&self, node_name: &str) -> Result<()> {
68        let mut running = self.running_nodes.write().await;
69        let handle = running
70            .remove(node_name)
71            .ok_or_else(|| anyhow::anyhow!("Node not running: {}", node_name))?;
72
73        handle.abort();
74        Ok(())
75    }
76
77    /// List all running nodes
78    pub async fn list_running(&self) -> Vec<String> {
79        let running = self.running_nodes.read().await;
80        running.keys().cloned().collect()
81    }
82
83    /// Check if a node is running
84    pub async fn is_running(&self, node_name: &str) -> bool {
85        let running = self.running_nodes.read().await;
86        running.contains_key(node_name)
87    }
88
89    /// Get list of registered node types
90    pub async fn list_types(&self) -> Vec<String> {
91        let factories = self.factories.read().await;
92        factories.keys().cloned().collect()
93    }
94}