use crate::composition::config::NodeConfig;
use crate::composition::lifecycle::ModuleLifecycle;
use crate::composition::registry::ModuleRegistry;
use crate::composition::schema::validate_config_schema;
use crate::composition::types::*;
use crate::composition::validation::validate_composition;
use std::path::Path;
pub struct NodeComposer {
lifecycle: ModuleLifecycle,
}
impl NodeComposer {
pub fn new<P: AsRef<Path>>(modules_dir: P) -> Self {
let registry = ModuleRegistry::new(modules_dir);
let lifecycle = ModuleLifecycle::new(registry);
Self { lifecycle }
}
pub async fn compose_from_config<P: AsRef<Path>>(
&mut self,
config_path: P,
) -> Result<ComposedNode> {
let config = NodeConfig::from_file(config_path)?;
let schema_validation = validate_config_schema(&config)?;
if !schema_validation.valid {
return Err(CompositionError::ValidationFailed(format!(
"Schema validation failed: {:?}",
schema_validation.errors
)));
}
let spec = config.to_spec()?;
self.compose_node(spec).await
}
pub async fn compose_node(&mut self, spec: NodeSpec) -> Result<ComposedNode> {
let validation = self.validate_composition(&spec)?;
if !validation.valid {
return Err(CompositionError::ValidationFailed(format!(
"Composition validation failed: {:?}",
validation.errors
)));
}
let mut loaded_modules = Vec::new();
for module_spec in &spec.modules {
if !module_spec.enabled {
continue;
}
let info = self
.lifecycle
.registry
.get_module(&module_spec.name, module_spec.version.as_deref())?;
self.lifecycle_mut()
.start_module(&info.name, Some(&module_spec.config))
.await?;
let status = self.lifecycle().get_module_status(&info.name).await?;
let health = self.lifecycle().health_check(&info.name).await?;
loaded_modules.push(LoadedModule {
info,
status,
health,
});
}
Ok(ComposedNode {
spec,
modules: loaded_modules,
status: NodeStatus::Running,
})
}
pub fn validate_composition(&self, spec: &NodeSpec) -> Result<ValidationResult> {
validate_composition(spec, &self.lifecycle.registry)
}
pub fn generate_config(&self) -> String {
let config = NodeConfig::template();
toml::to_string_pretty(&config)
.unwrap_or_else(|_| "# Error generating config template".to_string())
}
pub fn registry(&self) -> &ModuleRegistry {
&self.lifecycle.registry
}
pub fn registry_mut(&mut self) -> &mut ModuleRegistry {
&mut self.lifecycle.registry
}
pub fn lifecycle(&self) -> &ModuleLifecycle {
&self.lifecycle
}
pub fn lifecycle_mut(&mut self) -> &mut ModuleLifecycle {
&mut self.lifecycle
}
}