Skip to main content

blvm_sdk/composition/
composer.rs

1//! Node Composer
2//!
3//! High-level API for composing Bitcoin nodes from modules.
4
5use crate::composition::config::NodeConfig;
6use crate::composition::lifecycle::ModuleLifecycle;
7use crate::composition::registry::ModuleRegistry;
8use crate::composition::schema::validate_config_schema;
9use crate::composition::types::*;
10use crate::composition::validation::validate_composition;
11use std::path::Path;
12
13/// Node composer for building nodes from modules
14pub struct NodeComposer {
15    /// Module lifecycle manager (owns the registry)
16    lifecycle: ModuleLifecycle,
17}
18
19impl NodeComposer {
20    /// Create a new node composer
21    pub fn new<P: AsRef<Path>>(modules_dir: P) -> Self {
22        let registry = ModuleRegistry::new(modules_dir);
23        let lifecycle = ModuleLifecycle::new(registry);
24
25        Self { lifecycle }
26    }
27
28    /// Compose node from configuration file
29    pub async fn compose_from_config<P: AsRef<Path>>(
30        &mut self,
31        config_path: P,
32    ) -> Result<ComposedNode> {
33        // Load configuration
34        let config = NodeConfig::from_file(config_path)?;
35
36        // Validate schema
37        let schema_validation = validate_config_schema(&config)?;
38        if !schema_validation.valid {
39            return Err(CompositionError::ValidationFailed(format!(
40                "Schema validation failed: {:?}",
41                schema_validation.errors
42            )));
43        }
44
45        // Convert to spec
46        let spec = config.to_spec()?;
47
48        // Compose from spec
49        self.compose_node(spec).await
50    }
51
52    /// Compose node from specification
53    pub async fn compose_node(&mut self, spec: NodeSpec) -> Result<ComposedNode> {
54        // Validate composition
55        let validation = self.validate_composition(&spec)?;
56        if !validation.valid {
57            return Err(CompositionError::ValidationFailed(format!(
58                "Composition validation failed: {:?}",
59                validation.errors
60            )));
61        }
62
63        // Load all modules
64        let mut loaded_modules = Vec::new();
65        for module_spec in &spec.modules {
66            if !module_spec.enabled {
67                continue;
68            }
69
70            let info = self
71                .lifecycle
72                .registry
73                .get_module(&module_spec.name, module_spec.version.as_deref())?;
74
75            // Start module via lifecycle with config from ModuleSpec
76            self.lifecycle_mut()
77                .start_module(&info.name, Some(&module_spec.config))
78                .await?;
79            let status = self.lifecycle().get_module_status(&info.name).await?;
80            let health = self.lifecycle().health_check(&info.name).await?;
81
82            loaded_modules.push(LoadedModule {
83                info,
84                status,
85                health,
86            });
87        }
88
89        Ok(ComposedNode {
90            spec,
91            modules: loaded_modules,
92            status: NodeStatus::Running,
93        })
94    }
95
96    /// Validate composition
97    pub fn validate_composition(&self, spec: &NodeSpec) -> Result<ValidationResult> {
98        validate_composition(spec, &self.lifecycle.registry)
99    }
100
101    /// Generate configuration template
102    pub fn generate_config(&self) -> String {
103        let config = NodeConfig::template();
104        toml::to_string_pretty(&config)
105            .unwrap_or_else(|_| "# Error generating config template".to_string())
106    }
107
108    /// Get module registry (via lifecycle)
109    pub fn registry(&self) -> &ModuleRegistry {
110        &self.lifecycle.registry
111    }
112
113    /// Get mutable module registry (via lifecycle)
114    pub fn registry_mut(&mut self) -> &mut ModuleRegistry {
115        &mut self.lifecycle.registry
116    }
117
118    /// Get module lifecycle manager
119    pub fn lifecycle(&self) -> &ModuleLifecycle {
120        &self.lifecycle
121    }
122
123    /// Get mutable module lifecycle manager
124    pub fn lifecycle_mut(&mut self) -> &mut ModuleLifecycle {
125        &mut self.lifecycle
126    }
127}