1use serde::{Deserialize, Serialize};
8use sklears_core::error::{Result as SklResult, SklearsError};
9use std::any::Any;
10use std::collections::HashMap;
11use std::sync::Arc;
12use thiserror::Error;
13
14pub trait PluggableComponent: Send + Sync + Any {
19 fn initialize(&mut self, config: &ComponentConfig) -> SklResult<()>;
21
22 fn start(&mut self) -> SklResult<()>;
24
25 fn stop(&mut self) -> SklResult<()>;
27
28 fn pause(&mut self) -> SklResult<()>;
30
31 fn resume(&mut self) -> SklResult<()>;
33
34 fn component_id(&self) -> &str;
36
37 fn component_type(&self) -> &str;
39
40 fn version(&self) -> &str;
42
43 fn current_state(&self) -> ComponentState;
45
46 fn health_check(&self) -> SklResult<HealthStatus>;
48
49 fn capabilities(&self) -> Vec<ComponentCapability>;
51
52 fn dependencies(&self) -> Vec<ComponentDependency>;
54
55 fn validate_config(&self, config: &ComponentConfig) -> SklResult<()>;
57
58 fn get_metrics(&self) -> ComponentMetrics;
60
61 fn handle_event(&mut self, event: &ComponentEvent) -> SklResult<()>;
63
64 fn clone_component(&self) -> Box<dyn PluggableComponent>;
66
67 fn as_any(&self) -> &dyn Any;
69
70 fn as_any_mut(&mut self) -> &mut dyn Any;
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76pub enum ComponentState {
77 Created,
79 Initializing,
81 Ready,
83 Running,
85 Paused,
87 Stopping,
89 Stopped,
91 Error(String),
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
97pub enum HealthStatus {
98 Healthy,
100 Warning(String),
102 Degraded(String),
104 Unhealthy(String),
106 Unresponsive,
108}
109
110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
112pub struct ComponentCapability {
113 pub name: String,
115 pub description: String,
117 pub required_config: Vec<String>,
119 pub optional_config: Vec<String>,
121 pub version: String,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
127pub struct ComponentDependency {
128 pub component_type: String,
130 pub version_requirement: String,
132 pub optional: bool,
134 pub required_capabilities: Vec<String>,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct ComponentConfig {
141 pub component_id: String,
143 pub component_type: String,
145 pub parameters: HashMap<String, ConfigValue>,
147 pub environment: HashMap<String, String>,
149 pub resources: ResourceConstraints,
151 pub features: HashMap<String, bool>,
153}
154
155impl ComponentConfig {
156 #[must_use]
158 pub fn new(component_id: &str, component_type: &str) -> Self {
159 Self {
160 component_id: component_id.to_string(),
161 component_type: component_type.to_string(),
162 parameters: HashMap::new(),
163 environment: HashMap::new(),
164 resources: ResourceConstraints::default(),
165 features: HashMap::new(),
166 }
167 }
168
169 #[must_use]
171 pub fn with_parameter(mut self, key: &str, value: ConfigValue) -> Self {
172 self.parameters.insert(key.to_string(), value);
173 self
174 }
175
176 #[must_use]
178 pub fn with_environment(mut self, key: &str, value: &str) -> Self {
179 self.environment.insert(key.to_string(), value.to_string());
180 self
181 }
182
183 #[must_use]
185 pub fn with_resources(mut self, resources: ResourceConstraints) -> Self {
186 self.resources = resources;
187 self
188 }
189
190 #[must_use]
192 pub fn with_feature(mut self, feature: &str, enabled: bool) -> Self {
193 self.features.insert(feature.to_string(), enabled);
194 self
195 }
196
197 #[must_use]
199 pub fn get_parameter(&self, key: &str) -> Option<&ConfigValue> {
200 self.parameters.get(key)
201 }
202
203 pub fn get_environment(&self, key: &str) -> Option<&str> {
205 self.environment.get(key).map(String::as_str)
206 }
207
208 #[must_use]
210 pub fn is_feature_enabled(&self, feature: &str) -> bool {
211 self.features.get(feature).copied().unwrap_or(false)
212 }
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
217pub enum ConfigValue {
218 String(String),
220 Integer(i64),
222 Float(f64),
224 Boolean(bool),
226 Array(Vec<ConfigValue>),
228 Object(HashMap<String, ConfigValue>),
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize, Default)]
234pub struct ResourceConstraints {
235 pub max_memory: Option<u64>,
237 pub max_cpu: Option<f64>,
239 pub max_threads: Option<u32>,
241 pub max_disk: Option<u64>,
243 pub max_bandwidth: Option<u64>,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct ComponentMetrics {
250 pub uptime: std::time::Duration,
252 pub memory_usage: u64,
254 pub cpu_usage: f64,
256 pub processed_requests: u64,
258 pub failed_requests: u64,
260 pub average_processing_time: std::time::Duration,
262 pub custom_metrics: HashMap<String, MetricValue>,
264}
265
266impl ComponentMetrics {
267 #[must_use]
268 pub fn new() -> Self {
269 Self {
270 uptime: std::time::Duration::from_secs(0),
271 memory_usage: 0,
272 cpu_usage: 0.0,
273 processed_requests: 0,
274 failed_requests: 0,
275 average_processing_time: std::time::Duration::from_secs(0),
276 custom_metrics: HashMap::new(),
277 }
278 }
279
280 pub fn add_custom_metric(&mut self, name: &str, value: MetricValue) {
282 self.custom_metrics.insert(name.to_string(), value);
283 }
284
285 #[must_use]
287 pub fn success_rate(&self) -> f64 {
288 if self.processed_requests == 0 {
289 1.0
290 } else {
291 (self.processed_requests - self.failed_requests) as f64 / self.processed_requests as f64
292 }
293 }
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize)]
298pub enum MetricValue {
299 Counter(u64),
301 Gauge(f64),
303 Histogram(Vec<f64>),
305 Timer(std::time::Duration),
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct ComponentEvent {
312 pub event_id: String,
314 pub source: String,
316 pub event_type: String,
318 pub data: HashMap<String, String>,
320 pub timestamp: std::time::SystemTime,
322}
323
324pub trait ComponentFactory: Send + Sync {
326 fn create_component(&self, config: &ComponentConfig) -> SklResult<Box<dyn PluggableComponent>>;
328
329 fn supported_types(&self) -> Vec<String>;
331
332 fn validate_config(&self, config: &ComponentConfig) -> SklResult<()>;
334
335 fn factory_metadata(&self) -> FactoryMetadata;
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
341pub struct FactoryMetadata {
342 pub name: String,
344 pub version: String,
346 pub supported_types: Vec<String>,
348 pub description: String,
350}
351
352pub struct ComponentRegistry {
354 factories: HashMap<String, Arc<dyn ComponentFactory>>,
356 type_metadata: HashMap<String, ComponentTypeMetadata>,
358 config: RegistryConfig,
360}
361
362impl ComponentRegistry {
363 #[must_use]
365 pub fn new() -> Self {
366 Self {
367 factories: HashMap::new(),
368 type_metadata: HashMap::new(),
369 config: RegistryConfig::default(),
370 }
371 }
372
373 pub fn register_factory(
375 &mut self,
376 component_type: &str,
377 factory: Arc<dyn ComponentFactory>,
378 ) -> SklResult<()> {
379 if self.factories.contains_key(component_type) && !self.config.allow_overrides {
380 return Err(SklearsError::InvalidInput(format!(
381 "Component type {component_type} already registered"
382 )));
383 }
384
385 self.factories
386 .insert(component_type.to_string(), factory.clone());
387
388 let metadata = ComponentTypeMetadata {
389 component_type: component_type.to_string(),
390 factory_metadata: factory.factory_metadata(),
391 registration_time: std::time::SystemTime::now(),
392 };
393
394 self.type_metadata
395 .insert(component_type.to_string(), metadata);
396 Ok(())
397 }
398
399 pub fn create_component(
401 &self,
402 component_type: &str,
403 config: &ComponentConfig,
404 ) -> SklResult<Box<dyn PluggableComponent>> {
405 let factory = self.factories.get(component_type).ok_or_else(|| {
406 SklearsError::InvalidInput(format!("Component type {component_type} not registered"))
407 })?;
408
409 factory.create_component(config)
410 }
411
412 #[must_use]
414 pub fn get_registered_types(&self) -> Vec<String> {
415 self.factories.keys().cloned().collect()
416 }
417
418 #[must_use]
420 pub fn is_registered(&self, component_type: &str) -> bool {
421 self.factories.contains_key(component_type)
422 }
423
424 #[must_use]
426 pub fn get_type_metadata(&self, component_type: &str) -> Option<&ComponentTypeMetadata> {
427 self.type_metadata.get(component_type)
428 }
429
430 pub fn unregister(&mut self, component_type: &str) -> SklResult<()> {
432 self.factories.remove(component_type);
433 self.type_metadata.remove(component_type);
434 Ok(())
435 }
436}
437
438impl std::fmt::Debug for ComponentRegistry {
439 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
440 f.debug_struct("ComponentRegistry")
441 .field(
442 "factories",
443 &format!("<{} factories>", self.factories.len()),
444 )
445 .field("type_metadata", &self.type_metadata)
446 .field("config", &self.config)
447 .finish()
448 }
449}
450
451#[derive(Debug, Clone)]
453pub struct ComponentTypeMetadata {
454 pub component_type: String,
456 pub factory_metadata: FactoryMetadata,
458 pub registration_time: std::time::SystemTime,
460}
461
462#[derive(Debug, Clone)]
464pub struct RegistryConfig {
465 pub allow_overrides: bool,
467 pub enable_type_validation: bool,
469 pub max_registered_types: Option<usize>,
471}
472
473impl Default for RegistryConfig {
474 fn default() -> Self {
475 Self {
476 allow_overrides: false,
477 enable_type_validation: true,
478 max_registered_types: None,
479 }
480 }
481}
482
483#[derive(Debug, Error)]
485pub enum ComponentError {
486 #[error("Component initialization failed: {0}")]
487 InitializationFailed(String),
488
489 #[error("Component state transition invalid: {from} -> {to}")]
490 InvalidStateTransition { from: String, to: String },
491
492 #[error("Component configuration invalid: {0}")]
493 InvalidConfiguration(String),
494
495 #[error("Component dependency not satisfied: {0}")]
496 DependencyNotSatisfied(String),
497
498 #[error("Component health check failed: {0}")]
499 HealthCheckFailed(String),
500
501 #[error("Component capability not supported: {0}")]
502 CapabilityNotSupported(String),
503}
504
505impl Default for ComponentRegistry {
506 fn default() -> Self {
507 Self::new()
508 }
509}
510
511impl Default for ComponentMetrics {
512 fn default() -> Self {
513 Self::new()
514 }
515}
516
517#[derive(Debug, Clone, Serialize, Deserialize)]
521pub struct ComponentInfo {
522 pub id: String,
524 pub component_type: String,
526 pub version: String,
528 pub description: Option<String>,
530 pub status: ComponentStatus,
532 pub metadata: ComponentMetadata,
534}
535
536#[derive(Debug, Clone, Serialize, Deserialize)]
538pub struct ComponentMetadata {
539 pub author: Option<String>,
541 pub created_at: String,
543 pub modified_at: String,
545 pub tags: Vec<String>,
547 pub properties: HashMap<String, String>,
549}
550
551#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
553pub enum ComponentStatus {
554 Inactive,
556 Initializing,
558 Active,
560 Paused,
562 Stopping,
564 Failed,
566 Error(String),
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
572pub struct ComponentNode {
573 pub id: String,
575 pub component: ComponentInfo,
577 pub dependencies: Vec<String>,
579 pub dependents: Vec<String>,
581 pub level: usize,
583}
584
585#[derive(Debug, Clone, Serialize, Deserialize)]
587pub struct CapabilityMismatch {
588 pub required: String,
590 pub available: Option<String>,
592 pub description: String,
594 pub severity: CapabilityMismatchSeverity,
596}
597
598#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
600pub enum CapabilityMismatchSeverity {
601 Warning,
603 Error,
605 Critical,
607}
608
609#[derive(Debug, Clone, Serialize, Deserialize)]
611pub struct CompatibilityReport {
612 pub is_compatible: bool,
614 pub compatibility_score: f32,
616 pub mismatches: Vec<CapabilityMismatch>,
618 pub warnings: Vec<String>,
620 pub generated_at: String,
622}
623
624#[derive(Debug, Clone, Serialize, Deserialize)]
626pub struct EnvironmentSettings {
627 pub name: String,
629 pub variables: HashMap<String, String>,
631 pub working_directory: Option<String>,
633 pub resource_limits: Option<ResourceLimits>,
635 pub security_settings: Option<SecuritySettings>,
637}
638
639#[derive(Debug, Clone, Serialize, Deserialize)]
641pub struct SecuritySettings {
642 pub sandbox_enabled: bool,
644 pub network_access: bool,
646 pub filesystem_access: bool,
648 pub policy: Option<String>,
650}
651
652#[derive(Debug, Clone, Serialize, Deserialize)]
654pub struct ExecutionCondition {
655 pub expression: String,
657 pub variables: HashMap<String, String>,
659 pub condition_type: ExecutionConditionType,
661}
662
663#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
665pub enum ExecutionConditionType {
666 Always,
668 Never,
670 Expression,
672 DependencyBased,
674 ResourceBased,
676}
677
678#[derive(Debug, Clone, Serialize, Deserialize)]
680pub struct ExecutionMetadata {
681 pub execution_id: String,
683 pub start_time: String,
685 pub end_time: Option<String>,
687 pub duration_ms: Option<u64>,
689 pub status: ExecutionStatus,
691 pub resource_usage: Option<ResourceUsage>,
693}
694
695#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
697pub enum ExecutionStatus {
698 Pending,
700 Running,
702 Completed,
704 Failed,
706 Cancelled,
708 TimedOut,
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize)]
714pub struct ResourceUsage {
715 pub cpu_usage: f32,
717 pub memory_usage_mb: f32,
719 pub disk_usage_mb: f32,
721 pub network_usage_mb: f32,
723}
724
725#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
727pub enum LogLevel {
728 Trace,
730 Debug,
732 Info,
734 Warn,
736 Error,
738 Critical,
740}
741
742#[derive(Debug, Clone, Serialize, Deserialize)]
744pub struct MissingDependency {
745 pub component_id: String,
747 pub dependency_name: String,
749 pub required_version: Option<String>,
751 pub suggested_resolution: Option<String>,
753}
754
755#[derive(Debug, Clone, Serialize, Deserialize)]
757pub struct VersionConflict {
758 pub component_id: String,
760 pub required_version: String,
762 pub available_version: String,
764 pub description: String,
766}
767
768#[derive(Debug, Clone, Serialize, Deserialize)]
770pub struct ResourceLimits {
771 pub max_cpu_cores: Option<usize>,
773 pub max_memory_mb: Option<usize>,
775 pub max_disk_mb: Option<usize>,
777 pub max_network_mbps: Option<f32>,
779 pub timeout_sec: Option<u64>,
781}
782
783impl Default for ComponentStatus {
784 fn default() -> Self {
785 Self::Inactive
786 }
787}
788
789impl Default for CapabilityMismatchSeverity {
790 fn default() -> Self {
791 Self::Warning
792 }
793}
794
795impl Default for ExecutionConditionType {
796 fn default() -> Self {
797 Self::Always
798 }
799}
800
801impl Default for ExecutionStatus {
802 fn default() -> Self {
803 Self::Pending
804 }
805}
806
807impl Default for LogLevel {
808 fn default() -> Self {
809 Self::Info
810 }
811}
812
813#[allow(non_snake_case)]
814#[cfg(test)]
815mod tests {
816 use super::*;
817
818 struct MockComponent {
820 id: String,
821 component_type: String,
822 state: ComponentState,
823 metrics: ComponentMetrics,
824 }
825
826 impl MockComponent {
827 fn new(id: &str, component_type: &str) -> Self {
828 Self {
829 id: id.to_string(),
830 component_type: component_type.to_string(),
831 state: ComponentState::Created,
832 metrics: ComponentMetrics::new(),
833 }
834 }
835 }
836
837 impl PluggableComponent for MockComponent {
838 fn initialize(&mut self, _config: &ComponentConfig) -> SklResult<()> {
839 self.state = ComponentState::Ready;
840 Ok(())
841 }
842
843 fn start(&mut self) -> SklResult<()> {
844 self.state = ComponentState::Running;
845 Ok(())
846 }
847
848 fn stop(&mut self) -> SklResult<()> {
849 self.state = ComponentState::Stopped;
850 Ok(())
851 }
852
853 fn pause(&mut self) -> SklResult<()> {
854 self.state = ComponentState::Paused;
855 Ok(())
856 }
857
858 fn resume(&mut self) -> SklResult<()> {
859 self.state = ComponentState::Running;
860 Ok(())
861 }
862
863 fn component_id(&self) -> &str {
864 &self.id
865 }
866
867 fn component_type(&self) -> &str {
868 &self.component_type
869 }
870
871 fn version(&self) -> &str {
872 "1.0.0"
873 }
874
875 fn current_state(&self) -> ComponentState {
876 self.state.clone()
877 }
878
879 fn health_check(&self) -> SklResult<HealthStatus> {
880 Ok(HealthStatus::Healthy)
881 }
882
883 fn capabilities(&self) -> Vec<ComponentCapability> {
884 vec![ComponentCapability {
885 name: "test_capability".to_string(),
886 description: "Test capability".to_string(),
887 required_config: vec![],
888 optional_config: vec![],
889 version: "1.0.0".to_string(),
890 }]
891 }
892
893 fn dependencies(&self) -> Vec<ComponentDependency> {
894 vec![]
895 }
896
897 fn validate_config(&self, _config: &ComponentConfig) -> SklResult<()> {
898 Ok(())
899 }
900
901 fn get_metrics(&self) -> ComponentMetrics {
902 self.metrics.clone()
903 }
904
905 fn handle_event(&mut self, _event: &ComponentEvent) -> SklResult<()> {
906 Ok(())
907 }
908
909 fn clone_component(&self) -> Box<dyn PluggableComponent> {
910 Box::new(MockComponent::new(&self.id, &self.component_type))
911 }
912
913 fn as_any(&self) -> &dyn Any {
914 self
915 }
916
917 fn as_any_mut(&mut self) -> &mut dyn Any {
918 self
919 }
920 }
921
922 struct MockFactory;
924
925 impl ComponentFactory for MockFactory {
926 fn create_component(
927 &self,
928 config: &ComponentConfig,
929 ) -> SklResult<Box<dyn PluggableComponent>> {
930 Ok(Box::new(MockComponent::new(
931 &config.component_id,
932 &config.component_type,
933 )))
934 }
935
936 fn supported_types(&self) -> Vec<String> {
937 vec!["mock_component".to_string()]
938 }
939
940 fn validate_config(&self, _config: &ComponentConfig) -> SklResult<()> {
941 Ok(())
942 }
943
944 fn factory_metadata(&self) -> FactoryMetadata {
945 FactoryMetadata {
947 name: "MockFactory".to_string(),
948 version: "1.0.0".to_string(),
949 supported_types: vec!["mock_component".to_string()],
950 description: "Mock factory for testing".to_string(),
951 }
952 }
953 }
954
955 #[test]
956 fn test_component_config_creation() {
957 let config = ComponentConfig::new("test_component", "test_type")
958 .with_parameter("param1", ConfigValue::String("value1".to_string()))
959 .with_environment("ENV_VAR", "env_value")
960 .with_feature("feature1", true);
961
962 assert_eq!(config.component_id, "test_component");
963 assert_eq!(config.component_type, "test_type");
964 assert!(config.is_feature_enabled("feature1"));
965 assert_eq!(config.get_environment("ENV_VAR"), Some("env_value"));
966 }
967
968 #[test]
969 fn test_component_lifecycle() {
970 let mut component = MockComponent::new("test", "mock");
971 let config = ComponentConfig::new("test", "mock");
972
973 assert_eq!(component.current_state(), ComponentState::Created);
974
975 component.initialize(&config).unwrap();
976 assert_eq!(component.current_state(), ComponentState::Ready);
977
978 component.start().unwrap();
979 assert_eq!(component.current_state(), ComponentState::Running);
980
981 component.pause().unwrap();
982 assert_eq!(component.current_state(), ComponentState::Paused);
983
984 component.resume().unwrap();
985 assert_eq!(component.current_state(), ComponentState::Running);
986
987 component.stop().unwrap();
988 assert_eq!(component.current_state(), ComponentState::Stopped);
989 }
990
991 #[test]
992 fn test_component_registry() {
993 let mut registry = ComponentRegistry::new();
994 let factory = Arc::new(MockFactory);
995
996 registry
997 .register_factory("mock_component", factory)
998 .unwrap();
999 assert!(registry.is_registered("mock_component"));
1000
1001 let config = ComponentConfig::new("test_instance", "mock_component");
1002 let component = registry
1003 .create_component("mock_component", &config)
1004 .unwrap();
1005
1006 assert_eq!(component.component_id(), "test_instance");
1007 assert_eq!(component.component_type(), "mock_component");
1008 }
1009
1010 #[test]
1011 fn test_component_metrics() {
1012 let mut metrics = ComponentMetrics::new();
1013 metrics.processed_requests = 100;
1014 metrics.failed_requests = 5;
1015
1016 assert_eq!(metrics.success_rate(), 0.95);
1017
1018 metrics.add_custom_metric("test_metric", MetricValue::Counter(42));
1019 assert!(metrics.custom_metrics.contains_key("test_metric"));
1020 }
1021}