elif_core/modules/
loader.rs

1use crate::container::{Container, ContainerBuilder};
2use crate::modules::{Module, ModuleError, ModuleRegistry};
3use std::time::Instant;
4
5/// Module loader for orchestrating module loading process
6pub struct ModuleLoader {
7    registry: ModuleRegistry,
8    loading_stats: LoadingStats,
9}
10
11impl ModuleLoader {
12    /// Create a new module loader
13    pub fn new() -> Self {
14        Self {
15            registry: ModuleRegistry::new(),
16            loading_stats: LoadingStats::new(),
17        }
18    }
19    
20    /// Create a new module loader with existing registry
21    pub fn with_registry(registry: ModuleRegistry) -> Self {
22        Self {
23            registry,
24            loading_stats: LoadingStats::new(),
25        }
26    }
27    
28    /// Register a module
29    pub fn register<M: Module + 'static>(&mut self, module: M) {
30        self.registry.register(module);
31    }
32    
33    /// Register multiple modules at once
34    pub fn register_modules<M: Module + 'static>(&mut self, modules: Vec<M>) {
35        for module in modules {
36            self.registry.register(module);
37        }
38    }
39    
40    /// Load all modules and create container
41    pub async fn load(&mut self) -> Result<Container, ModuleError> {
42        let start_time = Instant::now();
43        
44        tracing::info!("Starting module loading process...");
45        
46        // Validate modules
47        self.registry.validate()?;
48        self.loading_stats.validation_time = start_time.elapsed();
49        
50        // Resolve dependencies
51        let dep_start = Instant::now();
52        self.registry.resolve_dependencies()?;
53        self.loading_stats.dependency_resolution_time = dep_start.elapsed();
54        
55        // Configure container
56        let config_start = Instant::now();
57        let builder = ContainerBuilder::new();
58        let builder = self.registry.configure_all(builder)?;
59        let mut container = builder.build()?;
60        self.loading_stats.configuration_time = config_start.elapsed();
61        
62        // Initialize container
63        let init_start = Instant::now();
64        container.initialize().await?;
65        self.loading_stats.initialization_time = init_start.elapsed();
66        
67        // Boot modules
68        let boot_start = Instant::now();
69        self.registry.boot_all(&container)?;
70        self.loading_stats.boot_time = boot_start.elapsed();
71        
72        self.loading_stats.total_time = start_time.elapsed();
73        self.loading_stats.module_count = self.registry.module_count();
74        
75        tracing::info!(
76            "Module loading completed successfully in {:?} with {} modules",
77            self.loading_stats.total_time,
78            self.loading_stats.module_count
79        );
80        
81        Ok(container)
82    }
83    
84    /// Load modules without creating container (for testing)
85    pub fn load_modules_only(&mut self) -> Result<(), ModuleError> {
86        self.registry.validate()?;
87        self.registry.resolve_dependencies()?;
88        Ok(())
89    }
90    
91    /// Get loading statistics
92    pub fn loading_stats(&self) -> &LoadingStats {
93        &self.loading_stats
94    }
95    
96    /// Get module registry
97    pub fn registry(&self) -> &ModuleRegistry {
98        &self.registry
99    }
100    
101    /// Get mutable module registry
102    pub fn registry_mut(&mut self) -> &mut ModuleRegistry {
103        &mut self.registry
104    }
105    
106    /// Get all routes from loaded modules
107    pub fn routes(&mut self) -> Vec<crate::modules::RouteDefinition> {
108        self.registry.collect_routes()
109    }
110    
111    /// Get all middleware from loaded modules
112    pub fn middleware(&mut self) -> Vec<crate::modules::MiddlewareDefinition> {
113        self.registry.collect_middleware()
114    }
115    
116    /// Print loading summary
117    pub fn print_summary(&self) {
118        let stats = &self.loading_stats;
119        
120        println!("\n=== Module Loading Summary ===");
121        println!("Modules loaded: {}", stats.module_count);
122        println!("Total time: {:?}", stats.total_time);
123        println!("  - Validation: {:?}", stats.validation_time);
124        println!("  - Dependency resolution: {:?}", stats.dependency_resolution_time);
125        println!("  - Configuration: {:?}", stats.configuration_time);
126        println!("  - Initialization: {:?}", stats.initialization_time);
127        println!("  - Boot: {:?}", stats.boot_time);
128        println!("===============================\n");
129    }
130}
131
132impl Default for ModuleLoader {
133    fn default() -> Self {
134        Self::new()
135    }
136}
137
138/// Statistics for module loading process
139#[derive(Debug, Clone)]
140pub struct LoadingStats {
141    pub module_count: usize,
142    pub total_time: std::time::Duration,
143    pub validation_time: std::time::Duration,
144    pub dependency_resolution_time: std::time::Duration,
145    pub configuration_time: std::time::Duration,
146    pub initialization_time: std::time::Duration,
147    pub boot_time: std::time::Duration,
148}
149
150impl LoadingStats {
151    /// Create new loading stats
152    pub fn new() -> Self {
153        Self {
154            module_count: 0,
155            total_time: std::time::Duration::ZERO,
156            validation_time: std::time::Duration::ZERO,
157            dependency_resolution_time: std::time::Duration::ZERO,
158            configuration_time: std::time::Duration::ZERO,
159            initialization_time: std::time::Duration::ZERO,
160            boot_time: std::time::Duration::ZERO,
161        }
162    }
163    
164    /// Get the percentage of time spent on each phase
165    pub fn phase_percentages(&self) -> PhasePercentages {
166        let total_micros = self.total_time.as_micros() as f64;
167        
168        if total_micros == 0.0 {
169            return PhasePercentages::default();
170        }
171        
172        PhasePercentages {
173            validation: (self.validation_time.as_micros() as f64 / total_micros) * 100.0,
174            dependency_resolution: (self.dependency_resolution_time.as_micros() as f64 / total_micros) * 100.0,
175            configuration: (self.configuration_time.as_micros() as f64 / total_micros) * 100.0,
176            initialization: (self.initialization_time.as_micros() as f64 / total_micros) * 100.0,
177            boot: (self.boot_time.as_micros() as f64 / total_micros) * 100.0,
178        }
179    }
180}
181
182impl Default for LoadingStats {
183    fn default() -> Self {
184        Self::new()
185    }
186}
187
188/// Phase percentages for loading stats
189#[derive(Debug, Clone, Default)]
190pub struct PhasePercentages {
191    pub validation: f64,
192    pub dependency_resolution: f64,
193    pub configuration: f64,
194    pub initialization: f64,
195    pub boot: f64,
196}
197
198/// Builder for module loader
199pub struct ModuleLoaderBuilder {
200    loader: ModuleLoader,
201}
202
203impl ModuleLoaderBuilder {
204    /// Create a new module loader builder
205    pub fn new() -> Self {
206        Self {
207            loader: ModuleLoader::new(),
208        }
209    }
210    
211    /// Add a module
212    pub fn add_module<M: Module + 'static>(mut self, module: M) -> Self {
213        self.loader.register(module);
214        self
215    }
216    
217    /// Add multiple modules
218    pub fn add_modules<M: Module + 'static>(mut self, modules: Vec<M>) -> Self {
219        self.loader.register_modules(modules);
220        self
221    }
222    
223    /// Build and return the module loader
224    pub fn build(self) -> ModuleLoader {
225        self.loader
226    }
227    
228    /// Build, load modules, and return container
229    pub async fn load(mut self) -> Result<Container, ModuleError> {
230        self.loader.load().await
231    }
232}
233
234impl Default for ModuleLoaderBuilder {
235    fn default() -> Self {
236        Self::new()
237    }
238}
239
240#[cfg(test)]
241mod tests {
242    use super::*;
243    use crate::modules::BaseModule;
244    
245    #[tokio::test]
246    async fn test_module_loader() -> Result<(), ModuleError> {
247        let mut loader = ModuleLoader::new();
248        
249        loader.register(BaseModule::new("test_module_1"));
250        loader.register(BaseModule::new("test_module_2"));
251        
252        let container = loader.load().await?;
253        
254        assert!(container.is_initialized());
255        assert_eq!(loader.loading_stats().module_count, 2);
256        
257        Ok(())
258    }
259    
260    #[tokio::test]
261    async fn test_module_loader_builder() -> Result<(), ModuleError> {
262        let container = ModuleLoaderBuilder::new()
263            .add_module(BaseModule::new("test_module_1"))
264            .add_module(BaseModule::new("test_module_2"))
265            .load()
266            .await?;
267        
268        assert!(container.is_initialized());
269        
270        Ok(())
271    }
272}