1use scirs2_core::ndarray::{Array1, Array2, ArrayView1, ArrayView2};
8use serde::{Deserialize, Serialize};
9use sklears_core::{
10 error::{Result as SklResult, SklearsError},
11 traits::Estimator,
12 types::Float,
13};
14use std::any::Any;
15use std::collections::{HashMap, HashSet};
16use std::fmt::Debug;
17use std::path::PathBuf;
18use std::sync::{Arc, RwLock};
19
20pub struct PluginRegistry {
22 plugins: RwLock<HashMap<String, Box<dyn Plugin>>>,
24 metadata: RwLock<HashMap<String, PluginMetadata>>,
26 factories: RwLock<HashMap<String, Box<dyn ComponentFactory>>>,
28 dependencies: RwLock<HashMap<String, Vec<String>>>,
30 config: PluginConfig,
32}
33
34#[derive(Debug, Clone)]
36pub struct PluginConfig {
37 pub plugin_dirs: Vec<PathBuf>,
39 pub auto_load: bool,
41 pub sandbox: bool,
43 pub max_execution_time: std::time::Duration,
45 pub validate_plugins: bool,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct PluginMetadata {
52 pub name: String,
54 pub version: String,
56 pub description: String,
58 pub author: String,
60 pub license: String,
62 pub min_api_version: String,
64 pub dependencies: Vec<String>,
66 pub capabilities: Vec<String>,
68 pub tags: Vec<String>,
70 pub documentation_url: Option<String>,
72 pub source_url: Option<String>,
74}
75
76pub trait Plugin: Send + Sync + Debug {
78 fn metadata(&self) -> &PluginMetadata;
80
81 fn initialize(&mut self, context: &PluginContext) -> SklResult<()>;
83
84 fn shutdown(&mut self) -> SklResult<()>;
86
87 fn capabilities(&self) -> Vec<PluginCapability>;
89
90 fn create_component(
92 &self,
93 component_type: &str,
94 config: &ComponentConfig,
95 ) -> SklResult<Box<dyn PluginComponent>>;
96
97 fn validate_config(&self, config: &ComponentConfig) -> SklResult<()>;
99
100 fn get_component_schema(&self, component_type: &str) -> Option<ComponentSchema>;
102}
103
104#[derive(Debug, Clone)]
106pub struct PluginContext {
107 pub registry_id: String,
109 pub working_dir: PathBuf,
111 pub config: HashMap<String, String>,
113 pub available_apis: HashSet<String>,
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Hash)]
119pub enum PluginCapability {
120 Transformer,
122 Estimator,
124 Preprocessor,
126 FeatureSelector,
128 Ensemble,
130 Metric,
132 DataLoader,
134 Visualizer,
136 Custom(String),
138}
139
140#[derive(Debug, Clone)]
142pub struct ComponentConfig {
143 pub component_type: String,
145 pub parameters: HashMap<String, ConfigValue>,
147 pub metadata: HashMap<String, String>,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153#[serde(untagged)]
154pub enum ConfigValue {
155 String(String),
157 Integer(i64),
159 Float(f64),
161 Boolean(bool),
163 Array(Vec<ConfigValue>),
165 Object(HashMap<String, ConfigValue>),
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct ComponentSchema {
172 pub name: String,
174 pub required_parameters: Vec<ParameterSchema>,
176 pub optional_parameters: Vec<ParameterSchema>,
178 pub constraints: Vec<ParameterConstraint>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct ParameterSchema {
185 pub name: String,
187 pub parameter_type: ParameterType,
189 pub description: String,
191 pub default_value: Option<ConfigValue>,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub enum ParameterType {
198 String {
200 min_length: Option<usize>,
201 max_length: Option<usize>,
202 },
203 Integer {
205 min_value: Option<i64>,
206 max_value: Option<i64>,
207 },
208 Float {
210 min_value: Option<f64>,
211 max_value: Option<f64>,
212 },
213 Boolean,
215 Enum { values: Vec<String> },
217 Array {
219 item_type: Box<ParameterType>,
220 min_items: Option<usize>,
221 max_items: Option<usize>,
222 },
223 Object { schema: ComponentSchema },
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct ParameterConstraint {
230 pub name: String,
232 pub expression: String,
234 pub description: String,
236}
237
238pub trait PluginComponent: Send + Sync + Debug {
240 fn component_type(&self) -> &str;
242
243 fn config(&self) -> &ComponentConfig;
245
246 fn initialize(&mut self, context: &ComponentContext) -> SklResult<()>;
248
249 fn clone_component(&self) -> Box<dyn PluginComponent>;
251
252 fn as_any(&self) -> &dyn Any;
254
255 fn as_any_mut(&mut self) -> &mut dyn Any;
257}
258
259#[derive(Debug, Clone)]
261pub struct ComponentContext {
262 pub component_id: String,
264 pub pipeline_id: Option<String>,
266 pub execution_params: HashMap<String, String>,
268 pub logger: Option<String>,
270}
271
272pub trait PluginTransformer: PluginComponent {
274 fn fit(
276 &mut self,
277 x: &ArrayView2<'_, Float>,
278 y: Option<&ArrayView1<'_, Float>>,
279 ) -> SklResult<()>;
280
281 fn transform(&self, x: &ArrayView2<'_, Float>) -> SklResult<Array2<f64>>;
283
284 fn fit_transform(
286 &mut self,
287 x: &ArrayView2<'_, Float>,
288 y: Option<&ArrayView1<'_, Float>>,
289 ) -> SklResult<Array2<f64>> {
290 self.fit(x, y)?;
291 self.transform(x)
292 }
293
294 fn is_fitted(&self) -> bool;
296
297 fn get_feature_names_out(&self, input_features: Option<&[String]>) -> Vec<String>;
299}
300
301pub trait PluginEstimator: PluginComponent {
303 fn fit(&mut self, x: &ArrayView2<'_, Float>, y: &ArrayView1<'_, Float>) -> SklResult<()>;
305
306 fn predict(&self, x: &ArrayView2<'_, Float>) -> SklResult<Array1<f64>>;
308
309 fn predict_proba(&self, x: &ArrayView2<'_, Float>) -> SklResult<Array2<f64>> {
311 Err(SklearsError::InvalidOperation(
312 "predict_proba not implemented for this estimator".to_string(),
313 ))
314 }
315
316 fn score(&self, x: &ArrayView2<'_, Float>, y: &ArrayView1<'_, Float>) -> SklResult<f64>;
318
319 fn is_fitted(&self) -> bool;
321
322 fn feature_importances(&self) -> Option<Array1<f64>> {
324 None
325 }
326}
327
328pub trait ComponentFactory: Send + Sync + Debug {
330 fn create(
332 &self,
333 component_type: &str,
334 config: &ComponentConfig,
335 ) -> SklResult<Box<dyn PluginComponent>>;
336
337 fn available_types(&self) -> Vec<String>;
339
340 fn get_schema(&self, component_type: &str) -> Option<ComponentSchema>;
342}
343
344pub struct PluginLoader {
346 config: PluginConfig,
348 loaded_libraries: HashMap<String, PluginLibrary>,
350}
351
352#[derive(Debug)]
354struct PluginLibrary {
355 path: PathBuf,
357 handle: String,
359 plugins: Vec<String>,
361}
362
363impl PluginRegistry {
364 #[must_use]
365 pub fn new(config: PluginConfig) -> Self {
366 Self {
367 plugins: RwLock::new(HashMap::new()),
368 metadata: RwLock::new(HashMap::new()),
369 factories: RwLock::new(HashMap::new()),
370 dependencies: RwLock::new(HashMap::new()),
371 config,
372 }
373 }
374
375 pub fn register_plugin(
377 &self,
378 name: &str,
379 plugin: Box<dyn Plugin>,
380 factory: Box<dyn ComponentFactory>,
381 ) -> SklResult<()> {
382 let metadata = plugin.metadata().clone();
383
384 self.validate_plugin(&metadata)?;
386
387 self.check_dependencies(&metadata)?;
389
390 {
392 let mut plugins = self.plugins.write().map_err(|_| {
393 SklearsError::InvalidOperation(
394 "Failed to acquire write lock for plugins".to_string(),
395 )
396 })?;
397 plugins.insert(name.to_string(), plugin);
398 }
399
400 {
402 let mut meta = self.metadata.write().map_err(|_| {
403 SklearsError::InvalidOperation(
404 "Failed to acquire write lock for metadata".to_string(),
405 )
406 })?;
407 meta.insert(name.to_string(), metadata.clone());
408 }
409
410 {
412 let mut factories = self.factories.write().map_err(|_| {
413 SklearsError::InvalidOperation(
414 "Failed to acquire write lock for factories".to_string(),
415 )
416 })?;
417 factories.insert(name.to_string(), factory);
418 }
419
420 {
422 let mut deps = self.dependencies.write().map_err(|_| {
423 SklearsError::InvalidOperation(
424 "Failed to acquire write lock for dependencies".to_string(),
425 )
426 })?;
427 deps.insert(name.to_string(), metadata.dependencies);
428 }
429
430 Ok(())
431 }
432
433 pub fn unregister_plugin(&self, name: &str) -> SklResult<()> {
435 let dependents = self.get_dependents(name)?;
437 if !dependents.is_empty() {
438 return Err(SklearsError::InvalidOperation(format!(
439 "Cannot unregister plugin '{name}' - it has dependents: {dependents:?}"
440 )));
441 }
442
443 if let Ok(mut plugins) = self.plugins.write() {
445 if let Some(mut plugin) = plugins.remove(name) {
446 plugin.shutdown()?;
447 }
448 }
449
450 if let Ok(mut metadata) = self.metadata.write() {
452 metadata.remove(name);
453 }
454
455 if let Ok(mut factories) = self.factories.write() {
457 factories.remove(name);
458 }
459
460 if let Ok(mut dependencies) = self.dependencies.write() {
462 dependencies.remove(name);
463 }
464
465 Ok(())
466 }
467
468 pub fn create_component(
470 &self,
471 plugin_name: &str,
472 component_type: &str,
473 config: &ComponentConfig,
474 ) -> SklResult<Box<dyn PluginComponent>> {
475 let factory = {
476 let factories = self.factories.read().map_err(|_| {
477 SklearsError::InvalidOperation(
478 "Failed to acquire read lock for factories".to_string(),
479 )
480 })?;
481
482 factories
483 .get(plugin_name)
484 .ok_or_else(|| {
485 SklearsError::InvalidInput(format!("Plugin '{plugin_name}' not found"))
486 })?
487 .create(component_type, config)?
488 };
489
490 Ok(factory)
491 }
492
493 pub fn list_plugins(&self) -> SklResult<Vec<String>> {
495 let plugins = self.plugins.read().map_err(|_| {
496 SklearsError::InvalidOperation("Failed to acquire read lock for plugins".to_string())
497 })?;
498 Ok(plugins.keys().cloned().collect())
499 }
500
501 pub fn get_plugin_metadata(&self, name: &str) -> SklResult<PluginMetadata> {
503 let metadata = self.metadata.read().map_err(|_| {
504 SklearsError::InvalidOperation("Failed to acquire read lock for metadata".to_string())
505 })?;
506
507 metadata
508 .get(name)
509 .cloned()
510 .ok_or_else(|| SklearsError::InvalidInput(format!("Plugin '{name}' not found")))
511 }
512
513 pub fn list_component_types(&self, plugin_name: &str) -> SklResult<Vec<String>> {
515 let factories = self.factories.read().map_err(|_| {
516 SklearsError::InvalidOperation("Failed to acquire read lock for factories".to_string())
517 })?;
518
519 let factory = factories.get(plugin_name).ok_or_else(|| {
520 SklearsError::InvalidInput(format!("Plugin '{plugin_name}' not found"))
521 })?;
522
523 Ok(factory.available_types())
524 }
525
526 pub fn get_component_schema(
528 &self,
529 plugin_name: &str,
530 component_type: &str,
531 ) -> SklResult<Option<ComponentSchema>> {
532 let factories = self.factories.read().map_err(|_| {
533 SklearsError::InvalidOperation("Failed to acquire read lock for factories".to_string())
534 })?;
535
536 let factory = factories.get(plugin_name).ok_or_else(|| {
537 SklearsError::InvalidInput(format!("Plugin '{plugin_name}' not found"))
538 })?;
539
540 Ok(factory.get_schema(component_type))
541 }
542
543 fn validate_plugin(&self, metadata: &PluginMetadata) -> SklResult<()> {
545 if !self.is_api_version_compatible(&metadata.min_api_version) {
547 return Err(SklearsError::InvalidInput(format!(
548 "Plugin requires API version {} but current version is incompatible",
549 metadata.min_api_version
550 )));
551 }
552
553 Ok(())
555 }
556
557 fn is_api_version_compatible(&self, required_version: &str) -> bool {
559 const CURRENT_API_VERSION: &str = "1.0.0";
561 required_version <= CURRENT_API_VERSION
562 }
563
564 fn check_dependencies(&self, metadata: &PluginMetadata) -> SklResult<()> {
566 let plugins = self.plugins.read().map_err(|_| {
567 SklearsError::InvalidOperation("Failed to acquire read lock for plugins".to_string())
568 })?;
569
570 for dependency in &metadata.dependencies {
571 if !plugins.contains_key(dependency) {
572 return Err(SklearsError::InvalidInput(format!(
573 "Missing dependency: {dependency}"
574 )));
575 }
576 }
577
578 Ok(())
579 }
580
581 fn get_dependents(&self, plugin_name: &str) -> SklResult<Vec<String>> {
583 let dependencies = self.dependencies.read().map_err(|_| {
584 SklearsError::InvalidOperation(
585 "Failed to acquire read lock for dependencies".to_string(),
586 )
587 })?;
588
589 let dependents: Vec<String> = dependencies
590 .iter()
591 .filter(|(_, deps)| deps.contains(&plugin_name.to_string()))
592 .map(|(name, _)| name.clone())
593 .collect();
594
595 Ok(dependents)
596 }
597
598 pub fn initialize_all(&self) -> SklResult<()> {
600 let plugin_names = self.list_plugins()?;
601
602 for name in plugin_names {
603 self.initialize_plugin(&name)?;
604 }
605
606 Ok(())
607 }
608
609 fn initialize_plugin(&self, name: &str) -> SklResult<()> {
611 let context = PluginContext {
612 registry_id: "main".to_string(),
613 working_dir: std::env::current_dir().unwrap_or_default(),
614 config: HashMap::new(),
615 available_apis: HashSet::new(),
616 };
617
618 let mut plugins = self.plugins.write().map_err(|_| {
619 SklearsError::InvalidOperation("Failed to acquire write lock for plugins".to_string())
620 })?;
621
622 if let Some(plugin) = plugins.get_mut(name) {
623 plugin.initialize(&context)?;
624 }
625
626 Ok(())
627 }
628
629 pub fn shutdown_all(&self) -> SklResult<()> {
631 let mut plugins = self.plugins.write().map_err(|_| {
632 SklearsError::InvalidOperation("Failed to acquire write lock for plugins".to_string())
633 })?;
634
635 for (_, plugin) in plugins.iter_mut() {
636 let _ = plugin.shutdown(); }
638
639 Ok(())
640 }
641}
642
643impl PluginLoader {
644 #[must_use]
646 pub fn new(config: PluginConfig) -> Self {
647 Self {
648 config,
649 loaded_libraries: HashMap::new(),
650 }
651 }
652
653 pub fn load_plugins(&mut self, registry: &PluginRegistry) -> SklResult<()> {
655 let plugin_dirs = self.config.plugin_dirs.clone();
656 for plugin_dir in &plugin_dirs {
657 self.load_plugins_from_dir(plugin_dir, registry)?;
658 }
659 Ok(())
660 }
661
662 fn load_plugins_from_dir(&mut self, dir: &PathBuf, registry: &PluginRegistry) -> SklResult<()> {
664 println!("Loading plugins from directory: {dir:?}");
671
672 self.load_example_plugins(registry)?;
674
675 Ok(())
676 }
677
678 fn load_example_plugins(&mut self, registry: &PluginRegistry) -> SklResult<()> {
680 let transformer_plugin = Box::new(ExampleTransformerPlugin::new());
682 let transformer_factory = Box::new(ExampleTransformerFactory::new());
683
684 registry.register_plugin(
685 "example_transformer",
686 transformer_plugin,
687 transformer_factory,
688 )?;
689
690 let estimator_plugin = Box::new(ExampleEstimatorPlugin::new());
692 let estimator_factory = Box::new(ExampleEstimatorFactory::new());
693
694 registry.register_plugin("example_estimator", estimator_plugin, estimator_factory)?;
695
696 Ok(())
697 }
698}
699
700#[derive(Debug)]
702struct ExampleTransformerPlugin {
703 metadata: PluginMetadata,
704}
705
706impl ExampleTransformerPlugin {
707 fn new() -> Self {
708 Self {
709 metadata: PluginMetadata {
710 name: "Example Transformer Plugin".to_string(),
711 version: "1.0.0".to_string(),
712 description: "Example transformer plugin for demonstration".to_string(),
713 author: "Sklears Team".to_string(),
714 license: "MIT".to_string(),
715 min_api_version: "1.0.0".to_string(),
716 dependencies: vec![],
717 capabilities: vec!["transformer".to_string()],
718 tags: vec!["example".to_string(), "transformer".to_string()],
719 documentation_url: None,
720 source_url: None,
721 },
722 }
723 }
724
725 fn with_metadata(metadata: PluginMetadata) -> Self {
726 Self { metadata }
727 }
728}
729
730impl Plugin for ExampleTransformerPlugin {
731 fn metadata(&self) -> &PluginMetadata {
732 &self.metadata
733 }
734
735 fn initialize(&mut self, _context: &PluginContext) -> SklResult<()> {
736 Ok(())
737 }
738
739 fn shutdown(&mut self) -> SklResult<()> {
740 Ok(())
741 }
742
743 fn capabilities(&self) -> Vec<PluginCapability> {
744 vec![PluginCapability::Transformer]
745 }
746
747 fn create_component(
748 &self,
749 component_type: &str,
750 config: &ComponentConfig,
751 ) -> SklResult<Box<dyn PluginComponent>> {
752 match component_type {
753 "example_scaler" => Ok(Box::new(ExampleScaler::new(config.clone()))),
754 _ => Err(SklearsError::InvalidInput(format!(
755 "Unknown component type: {component_type}"
756 ))),
757 }
758 }
759
760 fn validate_config(&self, _config: &ComponentConfig) -> SklResult<()> {
761 Ok(())
762 }
763
764 fn get_component_schema(&self, component_type: &str) -> Option<ComponentSchema> {
765 match component_type {
766 "example_scaler" => Some(ComponentSchema {
767 name: "ExampleScaler".to_string(),
768 required_parameters: vec![],
769 optional_parameters: vec![ParameterSchema {
770 name: "scale_factor".to_string(),
771 parameter_type: ParameterType::Float {
772 min_value: Some(0.0),
773 max_value: None,
774 },
775 description: "Factor to scale features by".to_string(),
776 default_value: Some(ConfigValue::Float(1.0)),
777 }],
778 constraints: vec![],
779 }),
780 _ => None,
781 }
782 }
783}
784
785#[derive(Debug)]
787struct ExampleTransformerFactory;
788
789impl ExampleTransformerFactory {
790 fn new() -> Self {
791 Self
792 }
793}
794
795impl ComponentFactory for ExampleTransformerFactory {
796 fn create(
797 &self,
798 component_type: &str,
799 config: &ComponentConfig,
800 ) -> SklResult<Box<dyn PluginComponent>> {
801 match component_type {
802 "example_scaler" => Ok(Box::new(ExampleScaler::new(config.clone()))),
803 _ => Err(SklearsError::InvalidInput(format!(
804 "Unknown component type: {component_type}"
805 ))),
806 }
807 }
808
809 fn available_types(&self) -> Vec<String> {
810 vec!["example_scaler".to_string()]
811 }
812
813 fn get_schema(&self, component_type: &str) -> Option<ComponentSchema> {
814 match component_type {
815 "example_scaler" => Some(ComponentSchema {
816 name: "ExampleScaler".to_string(),
817 required_parameters: vec![],
818 optional_parameters: vec![ParameterSchema {
819 name: "scale_factor".to_string(),
820 parameter_type: ParameterType::Float {
821 min_value: Some(0.0),
822 max_value: None,
823 },
824 description: "Factor to scale features by".to_string(),
825 default_value: Some(ConfigValue::Float(1.0)),
826 }],
827 constraints: vec![],
828 }),
829 _ => None,
830 }
831 }
832}
833
834#[derive(Debug, Clone)]
836struct ExampleScaler {
837 config: ComponentConfig,
838 scale_factor: f64,
839 fitted: bool,
840}
841
842impl ExampleScaler {
843 fn new(config: ComponentConfig) -> Self {
844 let scale_factor = config
845 .parameters
846 .get("scale_factor")
847 .and_then(|v| match v {
848 ConfigValue::Float(f) => Some(*f),
849 _ => None,
850 })
851 .unwrap_or(1.0);
852
853 Self {
854 config,
855 scale_factor,
856 fitted: false,
857 }
858 }
859}
860
861impl PluginComponent for ExampleScaler {
862 fn component_type(&self) -> &'static str {
863 "example_scaler"
864 }
865
866 fn config(&self) -> &ComponentConfig {
867 &self.config
868 }
869
870 fn initialize(&mut self, _context: &ComponentContext) -> SklResult<()> {
871 Ok(())
872 }
873
874 fn clone_component(&self) -> Box<dyn PluginComponent> {
875 Box::new(self.clone())
876 }
877
878 fn as_any(&self) -> &dyn Any {
879 self
880 }
881
882 fn as_any_mut(&mut self) -> &mut dyn Any {
883 self
884 }
885}
886
887impl PluginTransformer for ExampleScaler {
888 fn fit(
889 &mut self,
890 _x: &ArrayView2<'_, Float>,
891 _y: Option<&ArrayView1<'_, Float>>,
892 ) -> SklResult<()> {
893 self.fitted = true;
894 Ok(())
895 }
896
897 fn transform(&self, x: &ArrayView2<'_, Float>) -> SklResult<Array2<f64>> {
898 if !self.fitted {
899 return Err(SklearsError::InvalidOperation(
900 "Transformer must be fitted before transform".to_string(),
901 ));
902 }
903
904 Ok(x.mapv(|v| v * self.scale_factor))
905 }
906
907 fn is_fitted(&self) -> bool {
908 self.fitted
909 }
910
911 fn get_feature_names_out(&self, input_features: Option<&[String]>) -> Vec<String> {
912 match input_features {
913 Some(features) => features.iter().map(|f| format!("scaled_{f}")).collect(),
914 None => (0..10) .map(|i| format!("scaled_feature_{i}"))
916 .collect(),
917 }
918 }
919}
920
921#[derive(Debug)]
923struct ExampleEstimatorPlugin {
924 metadata: PluginMetadata,
925}
926
927impl ExampleEstimatorPlugin {
928 fn new() -> Self {
929 Self {
930 metadata: PluginMetadata {
931 name: "Example Estimator Plugin".to_string(),
932 version: "1.0.0".to_string(),
933 description: "Example estimator plugin for demonstration".to_string(),
934 author: "Sklears Team".to_string(),
935 license: "MIT".to_string(),
936 min_api_version: "1.0.0".to_string(),
937 dependencies: vec![],
938 capabilities: vec!["estimator".to_string()],
939 tags: vec!["example".to_string(), "estimator".to_string()],
940 documentation_url: None,
941 source_url: None,
942 },
943 }
944 }
945}
946
947impl Plugin for ExampleEstimatorPlugin {
948 fn metadata(&self) -> &PluginMetadata {
949 &self.metadata
950 }
951
952 fn initialize(&mut self, _context: &PluginContext) -> SklResult<()> {
953 Ok(())
954 }
955
956 fn shutdown(&mut self) -> SklResult<()> {
957 Ok(())
958 }
959
960 fn capabilities(&self) -> Vec<PluginCapability> {
961 vec![PluginCapability::Estimator]
962 }
963
964 fn create_component(
965 &self,
966 component_type: &str,
967 config: &ComponentConfig,
968 ) -> SklResult<Box<dyn PluginComponent>> {
969 match component_type {
970 "example_regressor" => Ok(Box::new(ExampleRegressor::new(config.clone()))),
971 _ => Err(SklearsError::InvalidInput(format!(
972 "Unknown component type: {component_type}"
973 ))),
974 }
975 }
976
977 fn validate_config(&self, _config: &ComponentConfig) -> SklResult<()> {
978 Ok(())
979 }
980
981 fn get_component_schema(&self, component_type: &str) -> Option<ComponentSchema> {
982 match component_type {
983 "example_regressor" => Some(ComponentSchema {
984 name: "ExampleRegressor".to_string(),
985 required_parameters: vec![],
986 optional_parameters: vec![ParameterSchema {
987 name: "learning_rate".to_string(),
988 parameter_type: ParameterType::Float {
989 min_value: Some(0.0),
990 max_value: Some(1.0),
991 },
992 description: "Learning rate for the algorithm".to_string(),
993 default_value: Some(ConfigValue::Float(0.01)),
994 }],
995 constraints: vec![],
996 }),
997 _ => None,
998 }
999 }
1000}
1001
1002#[derive(Debug)]
1004struct ExampleEstimatorFactory;
1005
1006impl ExampleEstimatorFactory {
1007 fn new() -> Self {
1008 Self
1009 }
1010}
1011
1012impl ComponentFactory for ExampleEstimatorFactory {
1013 fn create(
1014 &self,
1015 component_type: &str,
1016 config: &ComponentConfig,
1017 ) -> SklResult<Box<dyn PluginComponent>> {
1018 match component_type {
1019 "example_regressor" => Ok(Box::new(ExampleRegressor::new(config.clone()))),
1020 _ => Err(SklearsError::InvalidInput(format!(
1021 "Unknown component type: {component_type}"
1022 ))),
1023 }
1024 }
1025
1026 fn available_types(&self) -> Vec<String> {
1027 vec!["example_regressor".to_string()]
1028 }
1029
1030 fn get_schema(&self, component_type: &str) -> Option<ComponentSchema> {
1031 match component_type {
1032 "example_regressor" => Some(ComponentSchema {
1033 name: "ExampleRegressor".to_string(),
1034 required_parameters: vec![],
1035 optional_parameters: vec![ParameterSchema {
1036 name: "learning_rate".to_string(),
1037 parameter_type: ParameterType::Float {
1038 min_value: Some(0.0),
1039 max_value: Some(1.0),
1040 },
1041 description: "Learning rate for the algorithm".to_string(),
1042 default_value: Some(ConfigValue::Float(0.01)),
1043 }],
1044 constraints: vec![],
1045 }),
1046 _ => None,
1047 }
1048 }
1049}
1050
1051#[derive(Debug, Clone)]
1053struct ExampleRegressor {
1054 config: ComponentConfig,
1055 learning_rate: f64,
1056 fitted: bool,
1057 coefficients: Option<Array1<f64>>,
1058}
1059
1060impl ExampleRegressor {
1061 fn new(config: ComponentConfig) -> Self {
1062 let learning_rate = config
1063 .parameters
1064 .get("learning_rate")
1065 .and_then(|v| match v {
1066 ConfigValue::Float(f) => Some(*f),
1067 _ => None,
1068 })
1069 .unwrap_or(0.01);
1070
1071 Self {
1072 config,
1073 learning_rate,
1074 fitted: false,
1075 coefficients: None,
1076 }
1077 }
1078}
1079
1080impl PluginComponent for ExampleRegressor {
1081 fn component_type(&self) -> &'static str {
1082 "example_regressor"
1083 }
1084
1085 fn config(&self) -> &ComponentConfig {
1086 &self.config
1087 }
1088
1089 fn initialize(&mut self, _context: &ComponentContext) -> SklResult<()> {
1090 Ok(())
1091 }
1092
1093 fn clone_component(&self) -> Box<dyn PluginComponent> {
1094 Box::new(self.clone())
1095 }
1096
1097 fn as_any(&self) -> &dyn Any {
1098 self
1099 }
1100
1101 fn as_any_mut(&mut self) -> &mut dyn Any {
1102 self
1103 }
1104}
1105
1106impl PluginEstimator for ExampleRegressor {
1107 fn fit(&mut self, x: &ArrayView2<'_, Float>, y: &ArrayView1<'_, Float>) -> SklResult<()> {
1108 let n_features = x.ncols();
1110 let mut coefficients = Array1::zeros(n_features);
1111
1112 let y_f64 = y.mapv(|v| v);
1114 for _ in 0..1000 {
1115 let predictions = x.dot(&coefficients);
1116 let errors = &predictions - &y_f64;
1117 let gradient = x.t().dot(&errors) / x.nrows() as f64;
1118 coefficients = coefficients - self.learning_rate * gradient;
1119 }
1120
1121 self.coefficients = Some(coefficients);
1122 self.fitted = true;
1123 Ok(())
1124 }
1125
1126 fn predict(&self, x: &ArrayView2<'_, Float>) -> SklResult<Array1<f64>> {
1127 if !self.fitted {
1128 return Err(SklearsError::InvalidOperation(
1129 "Estimator must be fitted before predict".to_string(),
1130 ));
1131 }
1132
1133 let coefficients = self.coefficients.as_ref().unwrap();
1134 Ok(x.dot(coefficients))
1135 }
1136
1137 fn score(&self, x: &ArrayView2<'_, Float>, y: &ArrayView1<'_, Float>) -> SklResult<f64> {
1138 let predictions = self.predict(x)?;
1139 let y_f64 = y.mapv(|v| v);
1140
1141 let y_mean = y_f64.mean().unwrap();
1143 let ss_res = (&predictions - &y_f64).mapv(|x| x.powi(2)).sum();
1144 let ss_tot = y_f64.mapv(|x| (x - y_mean).powi(2)).sum();
1145
1146 Ok(1.0 - ss_res / ss_tot)
1147 }
1148
1149 fn is_fitted(&self) -> bool {
1150 self.fitted
1151 }
1152
1153 fn feature_importances(&self) -> Option<Array1<f64>> {
1154 self.coefficients.as_ref().map(|coefs| coefs.mapv(f64::abs))
1155 }
1156}
1157
1158impl Default for PluginConfig {
1159 fn default() -> Self {
1160 Self {
1161 plugin_dirs: vec![PathBuf::from("./plugins")],
1162 auto_load: true,
1163 sandbox: false,
1164 max_execution_time: std::time::Duration::from_secs(300), validate_plugins: true,
1166 }
1167 }
1168}
1169
1170#[allow(non_snake_case)]
1171#[cfg(test)]
1172mod tests {
1173 use super::*;
1174 use scirs2_core::ndarray::array;
1175
1176 #[test]
1177 fn test_plugin_registry_creation() {
1178 let config = PluginConfig::default();
1179 let registry = PluginRegistry::new(config);
1180
1181 assert!(registry.list_plugins().unwrap().is_empty());
1182 }
1183
1184 #[test]
1185 fn test_plugin_registration() {
1186 let config = PluginConfig::default();
1187 let registry = PluginRegistry::new(config);
1188
1189 let plugin = Box::new(ExampleTransformerPlugin::new());
1190 let factory = Box::new(ExampleTransformerFactory::new());
1191
1192 registry
1193 .register_plugin("test_plugin", plugin, factory)
1194 .unwrap();
1195
1196 let plugins = registry.list_plugins().unwrap();
1197 assert_eq!(plugins.len(), 1);
1198 assert!(plugins.contains(&"test_plugin".to_string()));
1199 }
1200
1201 #[test]
1202 fn test_component_creation() {
1203 let config = PluginConfig::default();
1204 let registry = PluginRegistry::new(config);
1205
1206 let plugin = Box::new(ExampleTransformerPlugin::new());
1207 let factory = Box::new(ExampleTransformerFactory::new());
1208
1209 registry
1210 .register_plugin("test_plugin", plugin, factory)
1211 .unwrap();
1212
1213 let component_config = ComponentConfig {
1214 component_type: "example_scaler".to_string(),
1215 parameters: {
1216 let mut params = HashMap::new();
1217 params.insert("scale_factor".to_string(), ConfigValue::Float(2.0));
1218 params
1219 },
1220 metadata: HashMap::new(),
1221 };
1222
1223 let component = registry
1224 .create_component("test_plugin", "example_scaler", &component_config)
1225 .unwrap();
1226
1227 assert_eq!(component.component_type(), "example_scaler");
1228 }
1229
1230 #[test]
1231 fn test_example_scaler() {
1232 let config = ComponentConfig {
1233 component_type: "example_scaler".to_string(),
1234 parameters: {
1235 let mut params = HashMap::new();
1236 params.insert("scale_factor".to_string(), ConfigValue::Float(2.0));
1237 params
1238 },
1239 metadata: HashMap::new(),
1240 };
1241
1242 let mut scaler = ExampleScaler::new(config);
1243
1244 let x = array![[1.0, 2.0], [3.0, 4.0]];
1245
1246 scaler.fit(&x.view(), None).unwrap();
1247 assert!(scaler.is_fitted());
1248
1249 let transformed = scaler.transform(&x.view()).unwrap();
1250 assert_eq!(transformed, array![[2.0, 4.0], [6.0, 8.0]]);
1251 }
1252
1253 #[test]
1254 fn test_example_regressor() {
1255 let config = ComponentConfig {
1256 component_type: "example_regressor".to_string(),
1257 parameters: {
1258 let mut params = HashMap::new();
1259 params.insert("learning_rate".to_string(), ConfigValue::Float(0.001));
1260 params
1261 },
1262 metadata: HashMap::new(),
1263 };
1264
1265 let mut regressor = ExampleRegressor::new(config);
1266
1267 let x = array![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
1268 let y = array![3.0, 7.0, 11.0]; regressor.fit(&x.view(), &y.view()).unwrap();
1271 assert!(regressor.is_fitted());
1272
1273 let predictions = regressor.predict(&x.view()).unwrap();
1274 assert_eq!(predictions.len(), 3);
1275
1276 let score = regressor.score(&x.view(), &y.view()).unwrap();
1277 assert!(score > -1.0); }
1281
1282 #[test]
1283 fn test_plugin_loader() {
1284 let config = PluginConfig::default();
1285 let registry = PluginRegistry::new(config.clone());
1286 let mut loader = PluginLoader::new(config);
1287
1288 loader.load_example_plugins(®istry).unwrap();
1289
1290 let plugins = registry.list_plugins().unwrap();
1291 assert_eq!(plugins.len(), 2);
1292 assert!(plugins.contains(&"example_transformer".to_string()));
1293 assert!(plugins.contains(&"example_estimator".to_string()));
1294 }
1295
1296 #[test]
1297 fn test_component_schema() {
1298 let plugin = ExampleTransformerPlugin::new();
1299 let schema = plugin.get_component_schema("example_scaler").unwrap();
1300
1301 assert_eq!(schema.name, "ExampleScaler");
1302 assert_eq!(schema.required_parameters.len(), 0);
1303 assert_eq!(schema.optional_parameters.len(), 1);
1304 assert_eq!(schema.optional_parameters[0].name, "scale_factor");
1305 }
1306
1307 #[test]
1308 fn test_plugin_dependencies() {
1309 let config = PluginConfig::default();
1310 let registry = PluginRegistry::new(config);
1311
1312 let metadata = PluginMetadata {
1314 name: "Dependent Plugin".to_string(),
1315 version: "1.0.0".to_string(),
1316 description: "Plugin with dependencies".to_string(),
1317 author: "Test".to_string(),
1318 license: "MIT".to_string(),
1319 min_api_version: "1.0.0".to_string(),
1320 dependencies: vec!["nonexistent_plugin".to_string()],
1321 capabilities: vec!["transformer".to_string()],
1322 tags: vec![],
1323 documentation_url: None,
1324 source_url: None,
1325 };
1326
1327 let plugin = ExampleTransformerPlugin::with_metadata(metadata);
1328 let factory = Box::new(ExampleTransformerFactory::new());
1329
1330 let result = registry.register_plugin("dependent_plugin", Box::new(plugin), factory);
1332 assert!(result.is_err());
1333 }
1334}
1335
1336pub mod advanced_plugin_system {
1338 use super::{
1339 Arc, Debug, HashMap, HashSet, PathBuf, PluginConfig, PluginLoader, PluginRegistry, RwLock,
1340 SklResult, SklearsError,
1341 };
1342 use std::sync::atomic::{AtomicBool, Ordering};
1343 use std::thread;
1344 use std::time::{Duration, SystemTime};
1345
1346 pub struct AdvancedPluginManager {
1348 registry: Arc<PluginRegistry>,
1349 loader: PluginLoader,
1350 watcher: Option<PluginWatcher>,
1351 version_manager: VersionManager,
1352 security_manager: SecurityManager,
1353 performance_monitor: PerformanceMonitor,
1354 marketplace: PluginMarketplace,
1355 }
1356
1357 pub struct PluginWatcher {
1359 watched_dirs: Vec<PathBuf>,
1360 running: Arc<AtomicBool>,
1361 poll_interval: Duration,
1362 }
1363
1364 #[derive(Debug)]
1366 pub struct VersionManager {
1367 installed_versions: HashMap<String, Vec<SemanticVersion>>,
1368 active_versions: HashMap<String, SemanticVersion>,
1369 compatibility_matrix: HashMap<String, Vec<VersionConstraint>>,
1370 }
1371
1372 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1374 pub struct SemanticVersion {
1375 pub major: u32,
1376 pub minor: u32,
1377 pub patch: u32,
1378 pub pre_release: Option<String>,
1379 pub build_metadata: Option<String>,
1380 }
1381
1382 #[derive(Debug, Clone)]
1384 pub struct VersionConstraint {
1385 pub plugin_name: String,
1386 pub constraint_type: ConstraintType,
1387 pub version: SemanticVersion,
1388 }
1389
1390 #[derive(Debug, Clone, PartialEq)]
1392 pub enum ConstraintType {
1393 Exact,
1395 GreaterThan,
1397 GreaterOrEqual,
1399 LessThan,
1401 LessOrEqual,
1403 Compatible, Tilde, }
1408
1409 #[derive(Debug)]
1411 pub struct SecurityManager {
1412 sandbox_enabled: bool,
1413 allowed_capabilities: HashSet<String>,
1414 security_policies: HashMap<String, SecurityPolicy>,
1415 threat_detection: ThreatDetector,
1416 }
1417
1418 #[derive(Debug, Clone)]
1420 pub struct SecurityPolicy {
1421 pub plugin_name: String,
1422 pub allowed_operations: HashSet<PluginOperation>,
1423 pub resource_limits: SecurityResourceLimits,
1424 pub network_access: NetworkAccess,
1425 pub file_system_access: FileSystemAccess,
1426 }
1427
1428 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
1430 pub enum PluginOperation {
1431 ReadData,
1433 WriteData,
1435 NetworkRequest,
1437 FileRead,
1439 FileWrite,
1441 ProcessSpawn,
1443 SystemCall,
1445 DatabaseAccess,
1447 EnvironmentAccess,
1449 }
1450
1451 #[derive(Debug, Clone)]
1453 pub struct SecurityResourceLimits {
1454 pub max_memory: Option<usize>,
1455 pub max_cpu_time: Option<Duration>,
1456 pub max_network_bandwidth: Option<usize>,
1457 pub max_file_descriptors: Option<usize>,
1458 }
1459
1460 #[derive(Debug, Clone)]
1462 pub enum NetworkAccess {
1463 None,
1464 Limited(Vec<String>), Full,
1468 }
1469
1470 #[derive(Debug, Clone)]
1472 pub enum FileSystemAccess {
1473 None,
1474 ReadOnly(Vec<PathBuf>),
1476 Limited(Vec<PathBuf>), Full,
1480 }
1481
1482 #[derive(Debug)]
1484 pub struct ThreatDetector {
1485 suspicious_patterns: Vec<ThreatPattern>,
1486 monitoring_enabled: bool,
1487 alert_callback: Option<fn(&ThreatAlert)>,
1488 }
1489
1490 #[derive(Debug, Clone)]
1492 pub struct ThreatPattern {
1493 pub pattern_type: ThreatType,
1494 pub pattern: String,
1495 pub severity: ThreatSeverity,
1496 pub description: String,
1497 }
1498
1499 #[derive(Debug, Clone, PartialEq)]
1501 pub enum ThreatType {
1502 SuspiciousCode,
1504 UnauthorizedAccess,
1506 ResourceAbuse,
1508 DataExfiltration,
1510 MaliciousPayload,
1512 }
1513
1514 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1516 pub enum ThreatSeverity {
1517 Low,
1518 Medium,
1519 High,
1520 Critical,
1521 }
1522
1523 #[derive(Debug)]
1525 pub struct ThreatAlert {
1526 pub plugin_name: String,
1527 pub threat_type: ThreatType,
1528 pub severity: ThreatSeverity,
1529 pub description: String,
1530 pub timestamp: SystemTime,
1531 pub details: HashMap<String, String>,
1532 }
1533
1534 #[derive(Debug)]
1536 pub struct PerformanceMonitor {
1537 metrics: Arc<RwLock<HashMap<String, PluginMetrics>>>,
1538 monitoring_enabled: bool,
1539 collection_interval: Duration,
1540 }
1541
1542 #[derive(Debug, Clone)]
1544 pub struct PluginMetrics {
1545 pub plugin_name: String,
1546 pub execution_count: u64,
1547 pub total_execution_time: Duration,
1548 pub average_execution_time: Duration,
1549 pub memory_usage: MemoryUsageStats,
1550 pub error_rate: f64,
1551 pub last_execution: Option<SystemTime>,
1552 }
1553
1554 #[derive(Debug, Clone)]
1556 pub struct MemoryUsageStats {
1557 pub current_usage: usize,
1558 pub peak_usage: usize,
1559 pub average_usage: usize,
1560 pub allocation_count: u64,
1561 }
1562
1563 #[derive(Debug)]
1565 pub struct PluginMarketplace {
1566 repositories: Vec<PluginRepository>,
1567 cache: Arc<RwLock<HashMap<String, MarketplaceEntry>>>,
1568 update_interval: Duration,
1569 last_update: Option<SystemTime>,
1570 }
1571
1572 #[derive(Debug, Clone)]
1574 pub struct PluginRepository {
1575 pub url: String,
1576 pub name: String,
1577 pub auth_token: Option<String>,
1578 pub trusted: bool,
1579 pub priority: u32,
1580 }
1581
1582 #[derive(Debug, Clone)]
1584 pub struct MarketplaceEntry {
1585 pub plugin_name: String,
1586 pub versions: Vec<PluginVersion>,
1587 pub description: String,
1588 pub tags: Vec<String>,
1589 pub downloads: u64,
1590 pub rating: f64,
1591 pub last_updated: SystemTime,
1592 }
1593
1594 #[derive(Debug, Clone)]
1596 pub struct PluginVersion {
1597 pub version: SemanticVersion,
1598 pub download_url: String,
1599 pub checksum: String,
1600 pub size: usize,
1601 pub release_notes: String,
1602 pub compatibility: Vec<String>,
1603 }
1604
1605 impl AdvancedPluginManager {
1606 pub fn new(config: PluginConfig) -> SklResult<Self> {
1608 let registry = Arc::new(PluginRegistry::new(config.clone()));
1609 let loader = PluginLoader::new(config.clone());
1610 let version_manager = VersionManager::new();
1611 let security_manager = SecurityManager::new(config.sandbox);
1612 let performance_monitor = PerformanceMonitor::new();
1613 let marketplace = PluginMarketplace::new();
1614
1615 let watcher = if config.auto_load {
1616 Some(PluginWatcher::new(config.plugin_dirs))
1617 } else {
1618 None
1619 };
1620
1621 Ok(Self {
1622 registry,
1623 loader,
1624 watcher,
1625 version_manager,
1626 security_manager,
1627 performance_monitor,
1628 marketplace,
1629 })
1630 }
1631
1632 pub fn start(&mut self) -> SklResult<()> {
1634 self.loader.load_plugins(&self.registry)?;
1636 self.registry.initialize_all()?;
1637
1638 if let Some(ref mut watcher) = self.watcher {
1640 watcher.start(Arc::clone(&self.registry))?;
1641 }
1642
1643 self.performance_monitor.start_monitoring()?;
1645
1646 self.marketplace.update_cache()?;
1648
1649 Ok(())
1650 }
1651
1652 pub fn stop(&mut self) -> SklResult<()> {
1654 if let Some(ref mut watcher) = self.watcher {
1656 watcher.stop();
1657 }
1658
1659 self.performance_monitor.stop_monitoring()?;
1661
1662 self.registry.shutdown_all()?;
1664
1665 Ok(())
1666 }
1667
1668 pub fn install_from_marketplace(
1670 &mut self,
1671 plugin_name: &str,
1672 version: Option<&SemanticVersion>,
1673 ) -> SklResult<()> {
1674 let entry = self.marketplace.find_plugin(plugin_name)?;
1675 let target_version = version.unwrap_or(&entry.versions[0].version);
1676
1677 self.security_manager
1679 .validate_plugin_security(plugin_name)?;
1680
1681 let plugin_data = self
1683 .marketplace
1684 .download_plugin(plugin_name, target_version)?;
1685 self.security_manager.scan_plugin(&plugin_data)?;
1686
1687 self.version_manager
1689 .install_version(plugin_name, target_version.clone())?;
1690
1691 Ok(())
1692 }
1693
1694 pub fn upgrade_plugin(
1696 &mut self,
1697 plugin_name: &str,
1698 target_version: &SemanticVersion,
1699 ) -> SklResult<()> {
1700 self.version_manager
1702 .check_upgrade_compatibility(plugin_name, target_version)?;
1703
1704 self.registry.unregister_plugin(plugin_name)?;
1706
1707 self.install_from_marketplace(plugin_name, Some(target_version))?;
1709
1710 Ok(())
1711 }
1712
1713 #[must_use]
1715 pub fn get_plugin_metrics(&self, plugin_name: &str) -> Option<PluginMetrics> {
1716 self.performance_monitor.get_metrics(plugin_name)
1717 }
1718
1719 #[must_use]
1721 pub fn get_security_report(&self, plugin_name: &str) -> SecurityReport {
1722 self.security_manager.generate_report(plugin_name)
1723 }
1724
1725 #[must_use]
1727 pub fn search_marketplace(&self, query: &str, tags: &[String]) -> Vec<MarketplaceEntry> {
1728 self.marketplace.search(query, tags)
1729 }
1730 }
1731
1732 #[derive(Debug)]
1734 pub struct SecurityReport {
1735 pub plugin_name: String,
1736 pub security_level: SecurityLevel,
1737 pub violations: Vec<SecurityViolation>,
1738 pub recommendations: Vec<String>,
1739 pub last_scan: Option<SystemTime>,
1740 }
1741
1742 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
1744 pub enum SecurityLevel {
1745 Safe,
1747 LowRisk,
1749 MediumRisk,
1751 HighRisk,
1753 Critical,
1755 }
1756
1757 #[derive(Debug)]
1759 pub struct SecurityViolation {
1760 pub violation_type: ViolationType,
1761 pub description: String,
1762 pub severity: ThreatSeverity,
1763 pub detected_at: SystemTime,
1764 }
1765
1766 #[derive(Debug)]
1768 pub enum ViolationType {
1769 UnauthorizedFileAccess,
1771 SuspiciousNetworkActivity,
1773 ExcessiveResourceUsage,
1775 PolicyViolation,
1777 MaliciousCode,
1779 }
1780
1781 impl PluginWatcher {
1782 #[must_use]
1783 pub fn new(dirs: Vec<PathBuf>) -> Self {
1784 Self {
1785 watched_dirs: dirs,
1786 running: Arc::new(AtomicBool::new(false)),
1787 poll_interval: Duration::from_secs(5),
1788 }
1789 }
1790
1791 pub fn start(&mut self, registry: Arc<PluginRegistry>) -> SklResult<()> {
1792 self.running.store(true, Ordering::SeqCst);
1793 let running = Arc::clone(&self.running);
1794 let dirs = self.watched_dirs.clone();
1795 let interval = self.poll_interval;
1796
1797 thread::spawn(move || {
1798 while running.load(Ordering::SeqCst) {
1799 for dir in &dirs {
1800 if dir.exists() {
1802 }
1805 }
1806 thread::sleep(interval);
1807 }
1808 });
1809
1810 Ok(())
1811 }
1812
1813 pub fn stop(&mut self) {
1814 self.running.store(false, Ordering::SeqCst);
1815 }
1816 }
1817
1818 impl Default for VersionManager {
1819 fn default() -> Self {
1820 Self::new()
1821 }
1822 }
1823
1824 impl VersionManager {
1825 #[must_use]
1826 pub fn new() -> Self {
1827 Self {
1828 installed_versions: HashMap::new(),
1829 active_versions: HashMap::new(),
1830 compatibility_matrix: HashMap::new(),
1831 }
1832 }
1833
1834 pub fn install_version(
1835 &mut self,
1836 plugin_name: &str,
1837 version: SemanticVersion,
1838 ) -> SklResult<()> {
1839 self.installed_versions
1840 .entry(plugin_name.to_string())
1841 .or_default()
1842 .push(version.clone());
1843
1844 self.active_versions
1845 .insert(plugin_name.to_string(), version);
1846 Ok(())
1847 }
1848
1849 pub fn check_upgrade_compatibility(
1850 &self,
1851 plugin_name: &str,
1852 target_version: &SemanticVersion,
1853 ) -> SklResult<()> {
1854 if let Some(constraints) = self.compatibility_matrix.get(plugin_name) {
1855 for constraint in constraints {
1856 if !self.version_satisfies_constraint(target_version, constraint) {
1857 return Err(SklearsError::InvalidInput(format!(
1858 "Version {} does not satisfy constraint {:?}",
1859 self.version_to_string(target_version),
1860 constraint
1861 )));
1862 }
1863 }
1864 }
1865 Ok(())
1866 }
1867
1868 fn version_satisfies_constraint(
1869 &self,
1870 version: &SemanticVersion,
1871 constraint: &VersionConstraint,
1872 ) -> bool {
1873 match constraint.constraint_type {
1874 ConstraintType::Exact => version == &constraint.version,
1875 ConstraintType::GreaterThan => version > &constraint.version,
1876 ConstraintType::GreaterOrEqual => version >= &constraint.version,
1877 ConstraintType::LessThan => version < &constraint.version,
1878 ConstraintType::LessOrEqual => version <= &constraint.version,
1879 ConstraintType::Compatible => {
1880 version.major == constraint.version.major && version >= &constraint.version
1881 }
1882 ConstraintType::Tilde => {
1883 version.major == constraint.version.major
1884 && version.minor == constraint.version.minor
1885 && version >= &constraint.version
1886 }
1887 }
1888 }
1889
1890 fn version_to_string(&self, version: &SemanticVersion) -> String {
1891 format!("{}.{}.{}", version.major, version.minor, version.patch)
1892 }
1893 }
1894
1895 impl SecurityManager {
1896 #[must_use]
1897 pub fn new(sandbox_enabled: bool) -> Self {
1898 Self {
1899 sandbox_enabled,
1900 allowed_capabilities: HashSet::new(),
1901 security_policies: HashMap::new(),
1902 threat_detection: ThreatDetector::new(),
1903 }
1904 }
1905
1906 pub fn validate_plugin_security(&self, plugin_name: &str) -> SklResult<()> {
1907 if let Some(policy) = self.security_policies.get(plugin_name) {
1908 Ok(())
1910 } else {
1911 Ok(())
1913 }
1914 }
1915
1916 pub fn scan_plugin(&self, plugin_data: &[u8]) -> SklResult<()> {
1917 self.threat_detection.scan_data(plugin_data)
1918 }
1919
1920 #[must_use]
1921 pub fn generate_report(&self, plugin_name: &str) -> SecurityReport {
1922 SecurityReport {
1924 plugin_name: plugin_name.to_string(),
1925 security_level: SecurityLevel::Safe,
1926 violations: Vec::new(),
1927 recommendations: Vec::new(),
1928 last_scan: Some(SystemTime::now()),
1929 }
1930 }
1931 }
1932
1933 impl Default for ThreatDetector {
1934 fn default() -> Self {
1935 Self::new()
1936 }
1937 }
1938
1939 impl ThreatDetector {
1940 #[must_use]
1941 pub fn new() -> Self {
1942 Self {
1943 suspicious_patterns: Vec::new(),
1944 monitoring_enabled: true,
1945 alert_callback: None,
1946 }
1947 }
1948
1949 pub fn scan_data(&self, data: &[u8]) -> SklResult<()> {
1950 let data_str = String::from_utf8_lossy(data);
1952
1953 for pattern in &self.suspicious_patterns {
1954 if data_str.contains(&pattern.pattern) {
1955 let alert = ThreatAlert {
1956 plugin_name: "unknown".to_string(),
1957 threat_type: pattern.pattern_type.clone(),
1958 severity: pattern.severity.clone(),
1959 description: pattern.description.clone(),
1960 timestamp: SystemTime::now(),
1961 details: HashMap::new(),
1962 };
1963
1964 if let Some(callback) = self.alert_callback {
1965 callback(&alert);
1966 }
1967
1968 if pattern.severity >= ThreatSeverity::High {
1969 return Err(SklearsError::InvalidInput(format!(
1970 "Security threat detected: {}",
1971 pattern.description
1972 )));
1973 }
1974 }
1975 }
1976
1977 Ok(())
1978 }
1979 }
1980
1981 impl Default for PerformanceMonitor {
1982 fn default() -> Self {
1983 Self::new()
1984 }
1985 }
1986
1987 impl PerformanceMonitor {
1988 #[must_use]
1989 pub fn new() -> Self {
1990 Self {
1991 metrics: Arc::new(RwLock::new(HashMap::new())),
1992 monitoring_enabled: false,
1993 collection_interval: Duration::from_secs(60),
1994 }
1995 }
1996
1997 pub fn start_monitoring(&mut self) -> SklResult<()> {
1998 self.monitoring_enabled = true;
1999 Ok(())
2001 }
2002
2003 pub fn stop_monitoring(&mut self) -> SklResult<()> {
2004 self.monitoring_enabled = false;
2005 Ok(())
2006 }
2007
2008 #[must_use]
2009 pub fn get_metrics(&self, plugin_name: &str) -> Option<PluginMetrics> {
2010 self.metrics.read().ok()?.get(plugin_name).cloned()
2011 }
2012
2013 pub fn record_execution(&self, plugin_name: &str, execution_time: Duration) {
2014 if let Ok(mut metrics) = self.metrics.write() {
2015 let plugin_metrics =
2016 metrics
2017 .entry(plugin_name.to_string())
2018 .or_insert_with(|| PluginMetrics {
2019 plugin_name: plugin_name.to_string(),
2020 execution_count: 0,
2021 total_execution_time: Duration::from_secs(0),
2022 average_execution_time: Duration::from_secs(0),
2023 memory_usage: MemoryUsageStats {
2024 current_usage: 0,
2025 peak_usage: 0,
2026 average_usage: 0,
2027 allocation_count: 0,
2028 },
2029 error_rate: 0.0,
2030 last_execution: None,
2031 });
2032
2033 plugin_metrics.execution_count += 1;
2034 plugin_metrics.total_execution_time += execution_time;
2035 plugin_metrics.average_execution_time =
2036 plugin_metrics.total_execution_time / plugin_metrics.execution_count as u32;
2037 plugin_metrics.last_execution = Some(SystemTime::now());
2038 }
2039 }
2040 }
2041
2042 impl Default for PluginMarketplace {
2043 fn default() -> Self {
2044 Self::new()
2045 }
2046 }
2047
2048 impl PluginMarketplace {
2049 #[must_use]
2050 pub fn new() -> Self {
2051 Self {
2052 repositories: Vec::new(),
2053 cache: Arc::new(RwLock::new(HashMap::new())),
2054 update_interval: Duration::from_secs(3600), last_update: None,
2056 }
2057 }
2058
2059 pub fn add_repository(&mut self, repository: PluginRepository) {
2060 self.repositories.push(repository);
2061 }
2062
2063 pub fn update_cache(&mut self) -> SklResult<()> {
2064 self.last_update = Some(SystemTime::now());
2066 Ok(())
2067 }
2068
2069 pub fn find_plugin(&self, plugin_name: &str) -> SklResult<MarketplaceEntry> {
2070 if let Ok(cache) = self.cache.read() {
2071 cache.get(plugin_name).cloned().ok_or_else(|| {
2072 SklearsError::InvalidInput(format!(
2073 "Plugin {plugin_name} not found in marketplace"
2074 ))
2075 })
2076 } else {
2077 Err(SklearsError::InvalidOperation(
2078 "Failed to read marketplace cache".to_string(),
2079 ))
2080 }
2081 }
2082
2083 pub fn download_plugin(
2084 &self,
2085 _plugin_name: &str,
2086 _version: &SemanticVersion,
2087 ) -> SklResult<Vec<u8>> {
2088 Ok(vec![])
2090 }
2091
2092 #[must_use]
2093 pub fn search(&self, query: &str, tags: &[String]) -> Vec<MarketplaceEntry> {
2094 if let Ok(cache) = self.cache.read() {
2095 cache
2096 .values()
2097 .filter(|entry| {
2098 entry.plugin_name.contains(query)
2099 || entry.description.contains(query)
2100 || tags.iter().any(|tag| entry.tags.contains(tag))
2101 })
2102 .cloned()
2103 .collect()
2104 } else {
2105 Vec::new()
2106 }
2107 }
2108 }
2109
2110 impl SemanticVersion {
2111 #[must_use]
2112 pub fn new(major: u32, minor: u32, patch: u32) -> Self {
2113 Self {
2114 major,
2115 minor,
2116 patch,
2117 pre_release: None,
2118 build_metadata: None,
2119 }
2120 }
2121
2122 pub fn parse(version_str: &str) -> SklResult<Self> {
2123 let parts: Vec<&str> = version_str.split('.').collect();
2124 if parts.len() < 3 {
2125 return Err(SklearsError::InvalidInput(
2126 "Invalid version format".to_string(),
2127 ));
2128 }
2129
2130 let major = parts[0]
2131 .parse()
2132 .map_err(|_| SklearsError::InvalidInput("Invalid major version".to_string()))?;
2133 let minor = parts[1]
2134 .parse()
2135 .map_err(|_| SklearsError::InvalidInput("Invalid minor version".to_string()))?;
2136 let patch = parts[2]
2137 .parse()
2138 .map_err(|_| SklearsError::InvalidInput("Invalid patch version".to_string()))?;
2139
2140 Ok(Self::new(major, minor, patch))
2141 }
2142 }
2143}