1use super::{Provider, ProviderError, ProviderResult, ProviderMetadata, FeatureMetadata, ProviderContext, FeatureInterface, FeatureOperation, ParameterDefinition, EventRegistry};
6use std::collections::HashMap;
7use std::path::Path;
8use std::sync::Arc;
9use libloading::{Library, Symbol};
10use tokio::sync::RwLock;
11
12pub struct ProviderLoader {
14 libraries: RwLock<Vec<Library>>,
16}
17
18type ProviderFactoryFn = unsafe extern "C" fn() -> *mut std::ffi::c_void;
20
21type ProviderMetadataFn = unsafe extern "C" fn() -> *const std::os::raw::c_char;
23
24impl ProviderLoader {
25 pub fn new() -> Self {
27 Self {
28 libraries: RwLock::new(Vec::new()),
29 }
30 }
31
32 pub async fn load_from_directory<P: AsRef<Path>>(
34 &self,
35 directory: P,
36 context: Arc<dyn ProviderContext>,
37 ) -> ProviderResult<Vec<(Arc<dyn Provider>, ProviderMetadata)>> {
38 self.load_from_directory_with_registry(directory, context, None).await
39 }
40
41 pub async fn load_from_directory_with_registry<P: AsRef<Path>>(
43 &self,
44 directory: P,
45 context: Arc<dyn ProviderContext>,
46 event_registry: Option<Arc<EventRegistry>>,
47 ) -> ProviderResult<Vec<(Arc<dyn Provider>, ProviderMetadata)>> {
48 let directory = directory.as_ref();
49
50 if !directory.exists() {
51 tokio::fs::create_dir_all(directory).await?;
52 return Ok(Vec::new());
53 }
54
55 let mut providers = Vec::new();
56 let mut read_dir = tokio::fs::read_dir(directory).await?;
57
58 while let Some(entry) = read_dir.next_entry().await? {
59 let path = entry.path();
60
61 if self.is_provider_library(&path) {
63 match self.load_provider_from_file_with_registry(&path, Arc::clone(&context), event_registry.clone()).await {
64 Ok((provider, metadata)) => {
65 providers.push((provider, metadata));
66 }
67 Err(e) => {
68 eprintln!("Failed to load provider from {:?}: {}", path, e);
69 }
70 }
71 }
72 }
73
74 Ok(providers)
75 }
76
77 pub async fn load_features_from_directory<P: AsRef<Path>>(
79 &self,
80 directory: P,
81 ) -> ProviderResult<Vec<FeatureInterface>> {
82 let directory = directory.as_ref();
83
84 if !directory.exists() {
85 tokio::fs::create_dir_all(directory).await?;
86 return Ok(Vec::new());
87 }
88
89 let mut features = Vec::new();
90 let mut read_dir = tokio::fs::read_dir(directory).await?;
91
92 while let Some(entry) = read_dir.next_entry().await? {
93 let path = entry.path();
94
95 if self.is_provider_library(&path) {
97 match self.load_feature_interface_from_file(&path).await {
98 Ok(feature) => {
99 features.push(feature);
100 }
101 Err(e) => {
102 eprintln!("Failed to load feature interface from {:?}: {}", path, e);
103 }
104 }
105 }
106 }
107
108 Ok(features)
109 }
110
111 fn is_provider_library(&self, path: &Path) -> bool {
113 if let Some(extension) = path.extension().and_then(|s| s.to_str()) {
114 match extension {
115 #[cfg(target_os = "windows")]
116 "dll" => true,
117 #[cfg(target_os = "linux")]
118 "so" => true,
119 #[cfg(target_os = "macos")]
120 "dylib" => true,
121 _ => false,
122 }
123 } else {
124 false
125 }
126 }
127
128 pub async fn load_provider_from_file<P: AsRef<Path>>(
130 &self,
131 library_path: P,
132 context: Arc<dyn ProviderContext>,
133 ) -> ProviderResult<(Arc<dyn Provider>, ProviderMetadata)> {
134 self.load_provider_from_file_with_registry(library_path, context, None).await
135 }
136
137 pub async fn load_provider_from_file_with_registry<P: AsRef<Path>>(
139 &self,
140 library_path: P,
141 context: Arc<dyn ProviderContext>,
142 event_registry: Option<Arc<EventRegistry>>,
143 ) -> ProviderResult<(Arc<dyn Provider>, ProviderMetadata)> {
144 let library_path = library_path.as_ref();
145
146 println!("Loading provider from file: {:?}", library_path);
147
148 let lib = unsafe {
150 Library::new(library_path).map_err(|e| {
151 ProviderError::LoadingFailed(format!(
152 "Failed to load library {:?}: {}",
153 library_path, e
154 ))
155 })?
156 };
157
158 println!("Successfully loaded library: {:?}", library_path);
159
160 let provider_type = self.detect_provider_type(&lib)?;
162
163 match provider_type {
164 ProviderType::LegacyCpi => {
165 self.load_legacy_cpi(&lib, library_path, context, event_registry).await
166 }
167 ProviderType::ModernProvider => {
168 self.load_modern_provider(&lib, library_path, context, event_registry).await
169 }
170 ProviderType::Feature => {
171 Err(ProviderError::LoadingFailed(
173 "Feature interfaces should be loaded separately, not as providers".to_string()
174 ))
175 }
176 }
177 }
178
179 fn detect_provider_type(&self, lib: &Library) -> ProviderResult<ProviderType> {
181 if unsafe { lib.get::<Symbol<ProviderFactoryFn>>(b"create_provider").is_ok() } {
183 return Ok(ProviderType::ModernProvider);
184 }
185
186 if unsafe { lib.get::<Symbol<ProviderFactoryFn>>(b"create_plugin").is_ok() } {
188 return Ok(ProviderType::LegacyCpi);
189 }
190
191 if unsafe { lib.get::<Symbol<ProviderMetadataFn>>(b"get_feature_name").is_ok() } {
193 return Ok(ProviderType::Feature);
194 }
195
196 Err(ProviderError::LoadingFailed(
197 "Library does not contain recognized provider interface".to_string()
198 ))
199 }
200
201 pub async fn load_feature_interface_from_file<P: AsRef<Path>>(
203 &self,
204 library_path: P,
205 ) -> ProviderResult<FeatureInterface> {
206 let library_path = library_path.as_ref();
207
208 println!("Loading feature interface from file: {:?}", library_path);
209
210 let lib = unsafe {
212 Library::new(library_path).map_err(|e| {
213 ProviderError::LoadingFailed(format!(
214 "Failed to load library {:?}: {}",
215 library_path, e
216 ))
217 })?
218 };
219
220 let provider_type = self.detect_provider_type(&lib)?;
222 if !matches!(provider_type, ProviderType::Feature) {
223 return Err(ProviderError::LoadingFailed(
224 "Library is not a feature interface".to_string()
225 ));
226 }
227
228 let get_feature_name: Symbol<unsafe extern "C" fn() -> *const std::os::raw::c_char> = unsafe {
230 lib.get(b"get_feature_name").map_err(|e| {
231 ProviderError::LoadingFailed(format!(
232 "Failed to find get_feature_name function: {}",
233 e
234 ))
235 })?
236 };
237
238 let name_ptr = unsafe { get_feature_name() };
239 let feature_name = if !name_ptr.is_null() {
240 unsafe {
241 std::ffi::CStr::from_ptr(name_ptr)
242 .to_str()
243 .unwrap_or("unknown")
244 .to_string()
245 }
246 } else {
247 "unknown".to_string()
248 };
249
250 let get_feature_metadata: Symbol<unsafe extern "C" fn() -> *const std::os::raw::c_char> = unsafe {
254 lib.get(b"get_feature_metadata").map_err(|e| {
255 ProviderError::LoadingFailed(format!(
256 "Failed to find get_feature_metadata function: {}",
257 e
258 ))
259 })?
260 };
261
262 let metadata_ptr = unsafe { get_feature_metadata() };
263 let metadata_str = if !metadata_ptr.is_null() {
264 unsafe { std::ffi::CStr::from_ptr(metadata_ptr).to_str().unwrap_or("{}") }
265 } else {
266 "{}"
267 };
268
269 let metadata_json: serde_json::Value = serde_json::from_str(metadata_str)
270 .map_err(|e| ProviderError::LoadingFailed(format!("Invalid feature metadata JSON: {}", e)))?;
271
272 let operations: Vec<FeatureOperation> = metadata_json.get("operations")
274 .and_then(|v| v.as_array())
275 .map(|arr| {
276 arr.iter()
277 .filter_map(|v| v.as_str())
278 .map(|op_name| {
279 let spec_function_name = format!("{}_operation_spec", op_name);
281 let spec_function_bytes = spec_function_name.as_bytes();
282
283 let operation_spec: Option<serde_json::Value> = unsafe {
285 lib.get::<unsafe extern "C" fn() -> *const std::os::raw::c_char>(spec_function_bytes)
286 .ok()
287 .and_then(|get_spec| {
288 let spec_ptr = get_spec();
289 if !spec_ptr.is_null() {
290 std::ffi::CStr::from_ptr(spec_ptr)
291 .to_str()
292 .ok()
293 .and_then(|spec_str| serde_json::from_str::<serde_json::Value>(spec_str).ok())
294 } else {
295 None
296 }
297 })
298 };
299
300 let (description, parameters, returns) = if let Some(spec) = operation_spec {
302 let desc = spec.get("description")
303 .and_then(|v| v.as_str())
304 .map(|s| s.to_string())
305 .unwrap_or_else(|| format!("{} operation", op_name));
306
307 let params = spec.get("parameters")
308 .and_then(|v| v.as_object())
309 .map(|obj| {
310 obj.iter().map(|(name, param_spec)| {
311 let param_def = ParameterDefinition {
312 name: name.clone(),
313 param_type: param_spec.get("type")
314 .and_then(|v| v.as_str())
315 .unwrap_or("string")
316 .to_string(),
317 required: param_spec.get("required")
318 .and_then(|v| v.as_bool())
319 .unwrap_or(false),
320 description: param_spec.get("description")
321 .and_then(|v| v.as_str())
322 .map(|s| s.to_string()),
323 };
324 (name.clone(), param_def)
325 }).collect()
326 })
327 .unwrap_or_default();
328
329 let ret_type = spec.get("returns")
330 .and_then(|v| v.get("type"))
331 .and_then(|v| v.as_str())
332 .map(|s| s.to_string());
333
334 (desc, params, ret_type)
335 } else {
336 (
338 format!("{} operation", op_name),
339 HashMap::new(),
340 Some("Value".to_string())
341 )
342 };
343
344 FeatureOperation {
345 name: op_name.to_string(),
346 description,
347 parameters,
348 returns,
349 }
350 })
351 .collect()
352 })
353 .unwrap_or_default();
354
355 if operations.is_empty() {
356 return Err(ProviderError::LoadingFailed(
357 format!("Feature '{}' has no operations defined", feature_name)
358 ));
359 }
360
361 let feature_interface = FeatureInterface {
362 name: feature_name.clone(),
363 description: metadata_json.get("description")
364 .and_then(|v| v.as_str())
365 .map(|s| s.to_string())
366 .unwrap_or_else(|| format!("{} feature interface", feature_name)),
367 operations,
368 };
369
370 println!("Successfully loaded feature interface: {}", feature_interface.name);
371
372 Ok(feature_interface)
373 }
374
375 async fn load_legacy_cpi(
377 &self,
378 lib: &Library,
379 library_path: &Path,
380 context: Arc<dyn ProviderContext>,
381 event_registry: Option<Arc<EventRegistry>>,
382 ) -> ProviderResult<(Arc<dyn Provider>, ProviderMetadata)> {
383 println!("Detected legacy CPI plugin");
384
385 let provider = Arc::new(LegacyCpiAdapter::new(
387 library_path.to_string_lossy().to_string()
388 ));
389
390 let metadata = ProviderMetadata {
391 name: "legacy-cpi".to_string(),
392 version: "1.0.0".to_string(),
393 description: "Legacy CPI adapter".to_string(),
394 author: None,
395 license: None,
396 features: vec![], settings_schema: None,
398 file_path: Some(library_path.to_string_lossy().to_string()),
399 metadata: None, };
401
402 {
404 let mut libraries = self.libraries.write().await;
405 let owned_lib = unsafe { Library::new(library_path)? };
407 libraries.push(owned_lib);
408 }
409
410 Ok((provider, metadata))
411 }
412
413 async fn load_modern_provider(
415 &self,
416 lib: &Library,
417 library_path: &Path,
418 context: Arc<dyn ProviderContext>,
419 event_registry: Option<Arc<EventRegistry>>,
420 ) -> ProviderResult<(Arc<dyn Provider>, ProviderMetadata)> {
421 println!("Detected modern provider");
422
423 let create_provider: Symbol<unsafe extern "C" fn() -> *mut std::ffi::c_void> = unsafe {
425 lib.get(b"create_provider").map_err(|e| {
426 ProviderError::LoadingFailed(format!(
427 "Failed to find create_provider function: {}",
428 e
429 ))
430 })?
431 };
432
433 let get_metadata: Symbol<unsafe extern "C" fn() -> *const std::os::raw::c_char> = unsafe {
435 lib.get(b"get_provider_metadata").map_err(|e| {
436 ProviderError::LoadingFailed(format!(
437 "Failed to find get_provider_metadata function: {}",
438 e
439 ))
440 })?
441 };
442
443 let initialize_provider: Symbol<unsafe extern "C" fn(*mut std::ffi::c_void, *mut std::ffi::c_void) -> bool> = unsafe {
445 lib.get(b"initialize_provider").map_err(|e| {
446 ProviderError::LoadingFailed(format!(
447 "Failed to find initialize_provider function: {}",
448 e
449 ))
450 })?
451 };
452
453 let provider_ptr = unsafe { create_provider() };
455 if provider_ptr.is_null() {
456 return Err(ProviderError::LoadingFailed(
457 "create_provider returned null".to_string()
458 ));
459 }
460
461 let metadata_ptr = unsafe { get_metadata() };
463 let metadata_str = if !metadata_ptr.is_null() {
464 unsafe { std::ffi::CStr::from_ptr(metadata_ptr).to_str().unwrap_or("{}") }
465 } else {
466 "{}"
467 };
468
469 let metadata_json: serde_json::Value = serde_json::from_str(metadata_str)
470 .map_err(|e| ProviderError::LoadingFailed(format!("Invalid metadata JSON: {}", e)))?;
471
472 if let Some(registry) = event_registry {
474 let mut registry_adapter = Box::new(RegistryAdapter::new());
476 registry_adapter.set_registry(Arc::clone(®istry));
477 let registry_ptr = Box::into_raw(registry_adapter) as *mut std::ffi::c_void;
478
479 let set_registry_interface: Symbol<unsafe extern "C" fn(*mut std::ffi::c_void, *const FFIRegistryInterface) -> bool> = unsafe {
481 lib.get(b"set_registry_interface").map_err(|e| {
482 ProviderError::LoadingFailed(format!(
483 "Provider must implement set_registry_interface function: {}",
484 e
485 ))
486 })?
487 };
488
489 let ffi_interface = FFIRegistryInterface {
491 register_fn: ffi_register_event,
492 };
493
494 let interface_success = unsafe { set_registry_interface(provider_ptr, &ffi_interface) };
495 if !interface_success {
496 return Err(ProviderError::InitializationFailed(
497 "Failed to set registry interface on provider".to_string()
498 ));
499 }
500
501 let init_success = unsafe { initialize_provider(provider_ptr, registry_ptr) };
502 if !init_success {
503 return Err(ProviderError::InitializationFailed(
504 "Provider initialization failed".to_string()
505 ));
506 }
507 } else {
508 println!("Warning: No event registry provided for modern provider initialization");
510 }
511
512 let provider = Arc::new(ModernProviderWrapper::new(
514 provider_ptr,
515 metadata_json.clone(),
516 library_path.to_path_buf(),
517 ));
518
519 let metadata = ProviderMetadata {
521 name: metadata_json.get("name")
522 .and_then(|v| v.as_str())
523 .unwrap_or("unknown")
524 .to_string(),
525 version: metadata_json.get("version")
526 .and_then(|v| v.as_str())
527 .unwrap_or("0.0.0")
528 .to_string(),
529 description: metadata_json.get("description")
530 .and_then(|v| v.as_str())
531 .unwrap_or("")
532 .to_string(),
533 author: None,
534 license: None,
535 features: vec![], settings_schema: None,
537 file_path: Some(library_path.to_string_lossy().to_string()),
538 metadata: Some(metadata_json), };
540
541 {
543 let mut libraries = self.libraries.write().await;
544 let owned_lib = unsafe { Library::new(library_path)? };
545 libraries.push(owned_lib);
546 }
547
548 Ok((provider, metadata))
549 }
550
551 async fn load_feature_as_provider(
553 &self,
554 lib: &Library,
555 library_path: &Path,
556 context: Arc<dyn ProviderContext>,
557 ) -> ProviderResult<(Arc<dyn Provider>, ProviderMetadata)> {
558 println!("Detected feature plugin");
559
560 let get_feature_name: Symbol<unsafe extern "C" fn() -> *const std::os::raw::c_char> = unsafe {
562 lib.get(b"get_feature_name").map_err(|e| {
563 ProviderError::LoadingFailed(format!(
564 "Failed to find get_feature_name function: {}",
565 e
566 ))
567 })?
568 };
569
570 let name_ptr = unsafe { get_feature_name() };
571 let feature_name = if !name_ptr.is_null() {
572 unsafe {
573 std::ffi::CStr::from_ptr(name_ptr)
574 .to_str()
575 .unwrap_or("unknown")
576 .to_string()
577 }
578 } else {
579 "unknown".to_string()
580 };
581
582 let register_operations: Symbol<unsafe extern "C" fn() -> *const std::os::raw::c_char> = unsafe {
584 lib.get(b"register_operations").map_err(|e| {
585 ProviderError::LoadingFailed(format!(
586 "Failed to find register_operations function: {}",
587 e
588 ))
589 })?
590 };
591
592 let operations_ptr = unsafe { register_operations() };
593 let operations_json = if !operations_ptr.is_null() {
594 unsafe {
595 std::ffi::CStr::from_ptr(operations_ptr)
596 .to_str()
597 .unwrap_or("[]")
598 .to_string()
599 }
600 } else {
601 "[]".to_string()
602 };
603
604 let operations: Vec<String> = serde_json::from_str(&operations_json)
605 .unwrap_or_else(|_| vec![]);
606
607 println!("Feature loaded: {} with operations: {:?}", feature_name, operations);
608
609 let provider = Arc::new(FeatureAdapter::new(
611 feature_name.clone(),
612 operations.clone(),
613 library_path.to_string_lossy().to_string(),
614 ));
615
616 let feature_metadata = FeatureMetadata::new(
618 feature_name.clone(),
619 format!("{} feature", feature_name),
620 "1.0.0".to_string(),
621 );
622
623 let metadata = ProviderMetadata {
624 name: format!("feature-{}", feature_name),
625 version: "1.0.0".to_string(),
626 description: format!("Feature provider for {}", feature_name),
627 author: None,
628 license: None,
629 features: vec![feature_metadata],
630 settings_schema: None,
631 file_path: Some(library_path.to_string_lossy().to_string()),
632 metadata: None, };
634
635 {
637 let mut libraries = self.libraries.write().await;
638 let owned_lib = unsafe { Library::new(library_path)? };
639 libraries.push(owned_lib);
640 }
641
642 Ok((provider, metadata))
643 }
644}
645
646#[derive(Debug, Clone, Copy)]
648enum ProviderType {
649 LegacyCpi,
650 ModernProvider,
651 Feature,
652}
653
654struct RegistryAdapter {
656 registry: Option<Arc<EventRegistry>>,
658}
659
660unsafe extern "C" fn ffi_register_event(
662 registry: *mut std::ffi::c_void,
663 event_name: *const std::os::raw::c_char,
664 handler: unsafe extern "C" fn(data: *const std::os::raw::c_char) -> *const std::os::raw::c_char,
665) {
666 if registry.is_null() || event_name.is_null() {
667 eprintln!("FFI: Invalid parameters for event registration");
668 return;
669 }
670
671 let adapter = registry as *mut RegistryAdapter;
672 let adapter_ref = &*adapter;
673
674 if let Some(event_registry) = &adapter_ref.registry {
675 let event_name_str = match std::ffi::CStr::from_ptr(event_name).to_str() {
676 Ok(s) => s,
677 Err(_) => {
678 eprintln!("FFI: Invalid event name string");
679 return;
680 }
681 };
682
683 println!("🔍 DEBUG: FFI registering event: {}", event_name_str);
684
685 let event_handler = Box::new(move |data: serde_json::Value| -> Result<serde_json::Value, String> {
687 let data_str = data.to_string();
688 let data_cstr = std::ffi::CString::new(data_str).map_err(|_| "Failed to create C string")?;
689
690 unsafe {
691 let result_ptr = handler(data_cstr.as_ptr());
692 if result_ptr.is_null() {
693 return Err("Handler returned null".to_string());
694 }
695
696 let result_str = std::ffi::CStr::from_ptr(result_ptr).to_str()
697 .map_err(|_| "Invalid result string")?;
698
699 serde_json::from_str(result_str)
700 .map_err(|e| format!("Invalid JSON result: {}", e))
701 }
702 });
703
704 if let Ok(handle) = tokio::runtime::Handle::try_current() {
706 let registry_clone = Arc::clone(event_registry);
707 let event_name_owned = event_name_str.to_string();
708
709 handle.spawn(async move {
710 registry_clone.register(&event_name_owned, event_handler).await;
711 });
712 } else {
713 eprintln!("FFI: No tokio runtime available for event registration");
714 }
715 } else {
716 eprintln!("FFI: No event registry available");
717 }
718}
719
720impl RegistryAdapter {
721 fn new() -> Self {
722 Self { registry: None }
723 }
724
725 fn set_registry(&mut self, registry: Arc<EventRegistry>) {
726 self.registry = Some(registry);
727 }
728}
729
730#[repr(C)]
732pub struct FFIRegistryInterface {
733 pub register_fn: unsafe extern "C" fn(
734 registry: *mut std::ffi::c_void,
735 event_name: *const std::os::raw::c_char,
736 handler: unsafe extern "C" fn(data: *const std::os::raw::c_char) -> *const std::os::raw::c_char,
737 ),
738}
739
740struct LegacyCpiAdapter {
742 name: String,
743 file_path: String,
744}
745
746impl LegacyCpiAdapter {
747 fn new(file_path: String) -> Self {
748 let name = Path::new(&file_path)
750 .file_stem()
751 .and_then(|s| s.to_str())
752 .unwrap_or("unknown")
753 .to_string();
754
755 Self { name, file_path }
756 }
757}
758
759impl Provider for LegacyCpiAdapter {
760 fn name(&self) -> &str {
761 &self.name
762 }
763
764 fn version(&self) -> &str {
765 "1.0.0"
766 }
767
768 fn features(&self) -> Vec<String> {
769 vec![]
772 }
773
774 fn feature_operations(&self, feature: &str) -> ProviderResult<Vec<String>> {
775 match feature {
777 "vm-management" => Ok(vec!["start".to_string(), "stop".to_string(), "create".to_string()]),
778 "vm-control" => Ok(vec!["reset".to_string(), "pause".to_string()]),
779 _ => Err(ProviderError::FeatureNotSupported {
780 provider: self.name.clone(),
781 feature: feature.to_string(),
782 }),
783 }
784 }
785
786 fn execute_operation(
787 &self,
788 feature: &str,
789 operation: &str,
790 args: HashMap<String, serde_json::Value>,
791 context: &dyn ProviderContext,
792 ) -> ProviderResult<serde_json::Value> {
793 Ok(serde_json::json!({
795 "success": true,
796 "provider": self.name,
797 "feature": feature,
798 "operation": operation,
799 "message": "Legacy CPI operation executed"
800 }))
801 }
802
803 fn initialize(&mut self, context: &dyn ProviderContext) -> ProviderResult<()> {
804 Ok(())
805 }
806
807 fn shutdown(&mut self, context: &dyn ProviderContext) -> ProviderResult<()> {
808 Ok(())
809 }
810}
811
812struct ModernProviderWrapper {
814 provider_ptr: *mut std::ffi::c_void,
815 metadata: serde_json::Value,
816 file_path: std::path::PathBuf,
817}
818
819impl ModernProviderWrapper {
820 fn new(provider_ptr: *mut std::ffi::c_void, metadata: serde_json::Value, file_path: std::path::PathBuf) -> Self {
821 Self {
822 provider_ptr,
823 metadata,
824 file_path,
825 }
826 }
827}
828
829unsafe impl Send for ModernProviderWrapper {}
830unsafe impl Sync for ModernProviderWrapper {}
831
832impl Provider for ModernProviderWrapper {
833 fn name(&self) -> &str {
834 self.metadata.get("name")
835 .and_then(|v| v.as_str())
836 .unwrap_or("unknown")
837 }
838
839 fn version(&self) -> &str {
840 self.metadata.get("version")
841 .and_then(|v| v.as_str())
842 .unwrap_or("0.0.0")
843 }
844
845 fn features(&self) -> Vec<String> {
846 vec![]
849 }
850
851 fn feature_operations(&self, feature: &str) -> ProviderResult<Vec<String>> {
852 Ok(vec![])
855 }
856
857 fn execute_operation(
858 &self,
859 feature: &str,
860 operation: &str,
861 args: HashMap<String, serde_json::Value>,
862 context: &dyn ProviderContext,
863 ) -> ProviderResult<serde_json::Value> {
864 Err(ProviderError::ExecutionFailed(
866 "Modern providers should be executed through event registry".to_string()
867 ))
868 }
869
870 fn initialize(&mut self, context: &dyn ProviderContext) -> ProviderResult<()> {
871 Ok(())
873 }
874
875 fn shutdown(&mut self, context: &dyn ProviderContext) -> ProviderResult<()> {
876 Ok(())
878 }
879}
880
881struct FeatureAdapter {
883 name: String,
884 operations: Vec<String>,
885 file_path: String,
886}
887
888impl FeatureAdapter {
889 fn new(name: String, operations: Vec<String>, file_path: String) -> Self {
890 Self { name, operations, file_path }
891 }
892}
893
894impl Provider for FeatureAdapter {
895 fn name(&self) -> &str {
896 &self.name
897 }
898
899 fn version(&self) -> &str {
900 "1.0.0"
901 }
902
903 fn features(&self) -> Vec<String> {
904 vec![self.name.clone()]
905 }
906
907 fn feature_operations(&self, feature: &str) -> ProviderResult<Vec<String>> {
908 if feature == self.name {
909 Ok(self.operations.clone())
910 } else {
911 Err(ProviderError::FeatureNotSupported {
912 provider: self.name.clone(),
913 feature: feature.to_string(),
914 })
915 }
916 }
917
918 fn execute_operation(
919 &self,
920 feature: &str,
921 operation: &str,
922 args: HashMap<String, serde_json::Value>,
923 context: &dyn ProviderContext,
924 ) -> ProviderResult<serde_json::Value> {
925 if feature != self.name {
926 return Err(ProviderError::FeatureNotSupported {
927 provider: self.name.clone(),
928 feature: feature.to_string(),
929 });
930 }
931
932 if !self.operations.contains(&operation.to_string()) {
933 return Err(ProviderError::OperationNotSupported {
934 provider: self.name.clone(),
935 feature: feature.to_string(),
936 operation: operation.to_string(),
937 });
938 }
939
940 Ok(serde_json::json!({
942 "success": true,
943 "provider": self.name,
944 "feature": feature,
945 "operation": operation,
946 "args": args,
947 "message": "Feature operation executed"
948 }))
949 }
950
951 fn initialize(&mut self, context: &dyn ProviderContext) -> ProviderResult<()> {
952 Ok(())
953 }
954
955 fn shutdown(&mut self, context: &dyn ProviderContext) -> ProviderResult<()> {
956 Ok(())
957 }
958}