dmsc/device/discovery/
mod.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of DMSC.
4//! The DMSC project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! # Device Discovery Module
19//!
20//! This module provides a comprehensive cross-platform device discovery system
21//! that can detect and enumerate hardware devices on any platform.
22//!
23//! ## Architecture
24//!
25//! - **DMSCDeviceDiscovery**: Main discovery engine combining providers and plugins
26//! - **DMSCHardwareProvider**: Trait for built-in hardware providers
27//! - **DMSCHardwareDiscoveryPlugin**: Trait for custom discovery plugins
28//! - **PlatformInfo**: Cross-platform detection and compatibility info
29//!
30//! ## Features
31//!
32//! - **Universal Hardware Support**: CPU, Memory, Storage, Network, GPU, USB
33//! - **Cross-Platform**: Linux, macOS, Windows, WebAssembly
34//! - **Extensible Plugin System**: Custom discovery implementations
35//! - **Async-First**: All operations are asynchronous
36//! - **Fallback Strategies**: Graceful degradation when platforms lack support
37//!
38//! ## Usage
39//!
40//! ```rust,ignore
41//! use dmsc::device::discovery::{DMSCDeviceDiscovery, DiscoveryConfig};
42//!
43//! #[tokio::main]
44//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
45//!     let config = DiscoveryConfig::default();
46//!     let discovery = DMSCDeviceDiscovery::new(config).await?;
47//!
48//!     // Discover all devices
49//!     let devices = discovery.discover_all().await?;
50//!     println!("Discovered {} devices", devices.len());
51//!
52//!     // Discover specific category
53//!     let cpus = discovery.discover_category(dmsc::device::HardwareCategory::CPU).await?;
54//!     println!("Found {} CPUs", cpus.len());
55//!
56//!     Ok(())
57//! }
58//! ```
59
60pub mod platform;
61pub mod providers;
62pub mod plugins;
63
64pub use platform::{
65    PlatformInfo,
66    PlatformType,
67    Architecture,
68    DiscoveryStrategy,
69    HardwareCategory,
70    PlatformCompatibility,
71};
72
73pub use providers::{
74    DMSCHardwareProvider,
75    ProviderRegistry,
76    DiscoveryResult,
77    CPUProvider,
78    MemoryProvider,
79    StorageProvider,
80    NetworkProvider,
81    GPUProvider,
82    USBProvider,
83};
84
85pub use plugins::{
86    DMSCHardwareDiscoveryPlugin,
87    PluginRegistry,
88    PluginMetadata,
89    PluginStatus,
90    PluginError,
91    PluginResult,
92    PluginLoader,
93    create_custom_plugin,
94};
95
96use std::sync::Arc;
97use tokio::sync::RwLock;
98use serde::{Serialize, Deserialize};
99
100use super::core::{DMSCDevice, DMSCDeviceType, DMSCDeviceCapabilities};
101use super::DMSCResult;
102
103/// Discovery configuration
104#[derive(Debug, Clone, Serialize, Deserialize)]
105#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
106pub struct DiscoveryConfig {
107    /// Enable CPU discovery
108    pub enable_cpu_discovery: bool,
109    /// Enable memory discovery
110    pub enable_memory_discovery: bool,
111    /// Enable storage discovery
112    pub enable_storage_discovery: bool,
113    /// Enable network discovery
114    pub enable_network_discovery: bool,
115    /// Enable GPU discovery
116    pub enable_gpu_discovery: bool,
117    /// Enable USB discovery
118    pub enable_usb_discovery: bool,
119    /// Enable custom plugins
120    pub enable_plugins: bool,
121    /// Enable fallback to mock devices
122    pub enable_mock_fallback: bool,
123    /// Discovery timeout in seconds
124    pub timeout_secs: u64,
125    /// Maximum retry attempts
126    pub max_retries: u32,
127    /// Retry delay in milliseconds
128    pub retry_delay_ms: u64,
129}
130
131impl Default for DiscoveryConfig {
132    fn default() -> Self {
133        Self {
134            enable_cpu_discovery: true,
135            enable_memory_discovery: true,
136            enable_storage_discovery: true,
137            enable_network_discovery: true,
138            enable_gpu_discovery: true,
139            enable_usb_discovery: true,
140            enable_plugins: true,
141            enable_mock_fallback: true,
142            timeout_secs: 30,
143            max_retries: 3,
144            retry_delay_ms: 1000,
145        }
146    }
147}
148
149/// Discovery statistics
150#[derive(Debug, Clone, Serialize, Deserialize, Default)]
151#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
152pub struct DiscoveryStats {
153    /// Total discovery operations
154    pub total_operations: u64,
155    /// Successful discoveries
156    pub successful_discoveries: u64,
157    /// Failed discoveries
158    pub failed_discoveries: u64,
159    /// Total devices discovered
160    pub total_devices_discovered: u64,
161    /// Discovery time in milliseconds
162    pub last_discovery_time_ms: u128,
163    /// Average discovery time in milliseconds
164    pub avg_discovery_time_ms: f64,
165    /// Number of providers used
166    pub providers_used: usize,
167    /// Number of plugins used
168    pub plugins_used: usize,
169}
170
171/// Main device discovery engine
172#[derive(Clone)]
173pub struct DMSCDeviceDiscovery {
174    config: Arc<DiscoveryConfig>,
175    platform: Arc<PlatformInfo>,
176    provider_registry: Arc<ProviderRegistry>,
177    plugin_registry: Arc<RwLock<PluginRegistry>>,
178    stats: Arc<RwLock<DiscoveryStats>>,
179    discovered_devices: Arc<RwLock<HashMap<String, DMSCDevice>>>,
180}
181
182impl DMSCDeviceDiscovery {
183    /// Creates a new device discovery engine
184    pub async fn new(config: DiscoveryConfig) -> DMSCResult<Self> {
185        let platform = Arc::new(PlatformInfo::new());
186        let provider_registry = Arc::new(ProviderRegistry::new());
187        let plugin_registry = PluginRegistry::new();
188
189        // Register default providers
190        provider_registry.register_defaults().await;
191
192        // Register built-in plugins if enabled
193        if config.enable_plugins {
194            // Custom plugins can be registered here
195        }
196
197        let stats = Arc::new(RwLock::new(DiscoveryStats::default()));
198        let discovered_devices = Arc::new(RwLock::new(HashMap::new()));
199
200        Ok(Self {
201            config: Arc::new(config),
202            platform,
203            provider_registry,
204            plugin_registry: Arc::new(RwLock::new(plugin_registry)),
205            stats,
206            discovered_devices,
207        })
208    }
209
210    /// Creates a discovery engine with default configuration
211    pub async fn with_defaults() -> DMSCResult<Self> {
212        Self::new(DiscoveryConfig::default()).await
213    }
214
215    /// Discovers all enabled device categories
216    pub async fn discover_all(&self) -> DMSCResult<Vec<DMSCDevice>> {
217        let start_time = std::time::Instant::now();
218        let mut all_devices = Vec::new();
219        let mut providers_used = 0;
220        let mut plugins_used = 0;
221
222        // Discover using providers
223        if self.config.enable_cpu_discovery {
224            match self.discover_category(HardwareCategory::CPU).await {
225                Ok(devices) => {
226                    all_devices.extend(devices);
227                    providers_used += 1;
228                }
229                Err(e) => tracing::warn!("CPU discovery failed: {}", e),
230            }
231        }
232
233        if self.config.enable_memory_discovery {
234            match self.discover_category(HardwareCategory::Memory).await {
235                Ok(devices) => {
236                    all_devices.extend(devices);
237                    providers_used += 1;
238                }
239                Err(e) => tracing::warn!("Memory discovery failed: {}", e),
240            }
241        }
242
243        if self.config.enable_storage_discovery {
244            match self.discover_category(HardwareCategory::Storage).await {
245                Ok(devices) => {
246                    all_devices.extend(devices);
247                    providers_used += 1;
248                }
249                Err(e) => tracing::warn!("Storage discovery failed: {}", e),
250            }
251        }
252
253        if self.config.enable_network_discovery {
254            match self.discover_category(HardwareCategory::Network).await {
255                Ok(devices) => {
256                    all_devices.extend(devices);
257                    providers_used += 1;
258                }
259                Err(e) => tracing::warn!("Network discovery failed: {}", e),
260            }
261        }
262
263        if self.config.enable_gpu_discovery {
264            match self.discover_category(HardwareCategory::GPU).await {
265                Ok(devices) => {
266                    all_devices.extend(devices);
267                    providers_used += 1;
268                }
269                Err(e) => tracing::warn!("GPU discovery failed: {}", e),
270            }
271        }
272
273        if self.config.enable_usb_discovery {
274            match self.discover_category(HardwareCategory::USB).await {
275                Ok(devices) => {
276                    all_devices.extend(devices);
277                    providers_used += 1;
278                }
279                Err(e) => tracing::warn!("USB discovery failed: {}", e),
280            }
281        }
282
283        // Discover using plugins
284        if self.config.enable_plugins {
285            let plugin_devices = self.discover_with_plugins().await?;
286            if !plugin_devices.is_empty() {
287                all_devices.extend(plugin_devices);
288                plugins_used += 1;
289            }
290        }
291
292        // Fallback to mock devices if enabled and no devices found
293        if self.config.enable_mock_fallback && all_devices.is_empty() {
294            tracing::info!("No devices discovered, using mock fallback");
295            let mock_devices = self.create_mock_devices().await?;
296            all_devices.extend(mock_devices);
297        }
298
299        // Update statistics
300        let elapsed = start_time.elapsed();
301        self.update_stats(all_devices.len(), providers_used, plugins_used, elapsed).await;
302
303        // Cache discovered devices
304        let mut cache = self.discovered_devices.write().await;
305        for device in &all_devices {
306            cache.insert(device.id().to_string(), device.clone());
307        }
308
309        Ok(all_devices)
310    }
311
312    /// Discovers devices of a specific category
313    pub async fn discover_category(&self, category: HardwareCategory) -> DMSCResult<Vec<DMSCDevice>> {
314        let start_time = std::time::Instant::now();
315
316        let devices = self.provider_registry.discover_devices(&category, &self.platform).await
317            .map_err(|e| crate::core::DMSCError::Other(format!("Discovery failed: {}", e)))?;
318
319        // Update statistics
320        let elapsed = start_time.elapsed().as_millis();
321        self.stats.write().await.last_discovery_time_ms = elapsed;
322        self.stats.write().await.total_devices_discovered += devices.len() as u64;
323
324        Ok(devices)
325    }
326
327    /// Discovers devices using registered plugins
328    pub async fn discover_with_plugins(&self) -> DMSCResult<Vec<DMSCDevice>> {
329        let devices = self.plugin_registry.read().await.discover_all(&self.platform).await
330            .map_err(|e| crate::core::DMSCError::Other(format!("Plugin discovery failed: {}", e)))?;
331        Ok(devices)
332    }
333
334    /// Discovers CPU devices
335    pub async fn discover_cpus(&self) -> DMSCResult<Vec<DMSCDevice>> {
336        self.discover_category(HardwareCategory::CPU).await
337    }
338
339    /// Discovers memory devices
340    pub async fn discover_memory(&self) -> DMSCResult<Vec<DMSCDevice>> {
341        self.discover_category(HardwareCategory::Memory).await
342    }
343
344    /// Discovers storage devices
345    pub async fn discover_storage(&self) -> DMSCResult<Vec<DMSCDevice>> {
346        self.discover_category(HardwareCategory::Storage).await
347    }
348
349    /// Discovers network devices
350    pub async fn discover_network(&self) -> DMSCResult<Vec<DMSCDevice>> {
351        self.discover_category(HardwareCategory::Network).await
352    }
353
354    /// Discovers GPU devices
355    pub async fn discover_gpus(&self) -> DMSCResult<Vec<DMSCDevice>> {
356        self.discover_category(HardwareCategory::GPU).await
357    }
358
359    /// Discovers USB devices
360    pub async fn discover_usb(&self) -> DMSCResult<Vec<DMSCDevice>> {
361        self.discover_category(HardwareCategory::USB).await
362    }
363
364    /// Returns platform information
365    pub fn platform_info(&self) -> &PlatformInfo {
366        &self.platform
367    }
368
369    /// Returns discovery statistics
370    pub async fn stats(&self) -> DiscoveryStats {
371        self.stats.read().await.clone()
372    }
373
374    /// Returns all discovered devices
375    pub async fn get_discovered_devices(&self) -> Vec<DMSCDevice> {
376        self.discovered_devices.read().await.values().cloned().collect()
377    }
378
379    /// Returns a device by ID
380    pub async fn get_device(&self, id: &str) -> Option<DMSCDevice> {
381        self.discovered_devices.read().await.get(id).cloned()
382    }
383
384    /// Clears all discovered devices
385    pub async fn clear_cache(&self) {
386        self.discovered_devices.write().await.clear();
387    }
388
389    /// Registers a custom hardware provider
390    pub async fn register_provider<P: DMSCHardwareProvider + 'static>(&self, provider: P) {
391        self.provider_registry.register(Box::new(provider)).await;
392    }
393
394    /// Registers a custom discovery plugin
395    pub async fn register_plugin(&mut self, plugin: Box<dyn DMSCHardwareDiscoveryPlugin>) {
396        self.plugin_registry.write().await.register(plugin).await.ok();
397    }
398
399    /// Enables a plugin by name
400    pub async fn enable_plugin(&self, name: &str) {
401        self.plugin_registry.read().await.enable(name).await.ok();
402    }
403
404    /// Disables a plugin by name
405    pub async fn disable_plugin(&self, name: &str) {
406        self.plugin_registry.read().await.disable(name).await.ok();
407    }
408
409    /// Returns the number of registered providers
410    pub async fn provider_count(&self) -> usize {
411        self.provider_registry.provider_count().await
412    }
413
414    /// Returns the number of registered plugins
415    pub async fn plugin_count(&self) -> usize {
416        self.plugin_registry.read().await.count().await
417    }
418
419    /// Returns platform compatibility information
420    pub fn platform_compatibility(&self) -> PlatformCompatibility {
421        PlatformCompatibility::from_platform(&self.platform)
422    }
423
424    /// Updates discovery statistics
425    async fn update_stats(&self, device_count: usize, providers_used: usize, plugins_used: usize, elapsed: std::time::Duration) {
426        let mut stats = self.stats.write().await;
427        stats.total_operations += 1;
428        stats.successful_discoveries += 1;
429        stats.total_devices_discovered += device_count as u64;
430        stats.last_discovery_time_ms = elapsed.as_millis();
431
432        // Update average
433        let total_time = stats.avg_discovery_time_ms * (stats.successful_discoveries as f64 - 1.0);
434        stats.avg_discovery_time_ms = (total_time + elapsed.as_millis() as f64) / stats.successful_discoveries as f64;
435
436        stats.providers_used = providers_used;
437        stats.plugins_used = plugins_used;
438    }
439
440    /// Creates mock devices for testing/fallback
441    async fn create_mock_devices(&self) -> DMSCResult<Vec<DMSCDevice>> {
442        let mut devices = Vec::new();
443
444        // Create a mock CPU
445        if self.config.enable_cpu_discovery {
446            let cpu_capabilities = DMSCDeviceCapabilities::new()
447                .with_compute_units(self.platform.cpu_cores)
448                .with_memory_gb(self.platform.total_memory as f64 / (1024.0 * 1024.0 * 1024.0));
449
450            let cpu = DMSCDevice::new(
451                format!("Mock CPU ({} cores)", self.platform.cpu_cores),
452                DMSCDeviceType::CPU,
453            ).with_capabilities(cpu_capabilities);
454            devices.push(cpu);
455        }
456
457        // Create a mock memory
458        if self.config.enable_memory_discovery {
459            let mem_capabilities = DMSCDeviceCapabilities::new()
460                .with_compute_units(0)
461                .with_memory_gb(self.platform.total_memory as f64 / (1024.0 * 1024.0 * 1024.0));
462
463            let memory = DMSCDevice::new(
464                format!("Mock Memory ({:.2} GB)", self.platform.total_memory as f64 / (1024.0 * 1024.0 * 1024.0)),
465                DMSCDeviceType::Memory,
466            ).with_capabilities(mem_capabilities);
467            devices.push(memory);
468        }
469
470        // Create a mock network adapter
471        if self.config.enable_network_discovery {
472            let net_capabilities = DMSCDeviceCapabilities::new()
473                .with_bandwidth_gbps(1.0);
474
475            let network = DMSCDevice::new(
476                "Mock Loopback Interface".to_string(),
477                DMSCDeviceType::Network,
478            ).with_capabilities(net_capabilities);
479            devices.push(network);
480        }
481
482        Ok(devices)
483    }
484}
485
486/// Async discovery operation with progress tracking
487pub struct AsyncDiscovery {
488    discovery: Arc<DMSCDeviceDiscovery>,
489    current_progress: Arc<RwLock<f32>>,
490    is_cancelled: Arc<RwLock<bool>>,
491}
492
493impl AsyncDiscovery {
494    /// Creates a new async discovery operation
495    pub fn new(discovery: Arc<DMSCDeviceDiscovery>) -> Self {
496        Self {
497            discovery,
498            current_progress: Arc::new(RwLock::new(0.0)),
499            is_cancelled: Arc::new(RwLock::new(false)),
500        }
501    }
502
503    /// Discovers all devices with progress tracking
504    pub async fn discover_all(&self) -> DMSCResult<Vec<DMSCDevice>> {
505        *self.current_progress.write().await = 0.0;
506
507        *self.current_progress.write().await = 0.1; // 10% - Starting
508        if *self.is_cancelled.read().await {
509            return Err(crate::core::DMSCError::Other("Discovery cancelled".to_string()));
510        }
511
512        let result = self.discovery.discover_all().await;
513
514        *self.current_progress.write().await = 1.0; // 100% - Complete
515
516        result
517    }
518
519    /// Returns current progress (0.0 to 1.0)
520    pub async fn progress(&self) -> f32 {
521        *self.current_progress.read().await
522    }
523
524    /// Cancels the discovery operation
525    pub async fn cancel(&self) {
526        *self.is_cancelled.write().await = true;
527    }
528}
529
530/// Extension trait for DMSCDeviceController to integrate discovery
531#[async_trait::async_trait]
532pub trait DeviceDiscoveryExtension {
533    /// Performs device discovery and returns discovered devices
534    async fn perform_discovery(&mut self) -> DMSCResult<Vec<DMSCDevice>>;
535
536    /// Returns the discovery engine
537    fn discovery_engine(&self) -> Option<&DMSCDeviceDiscovery>;
538}
539
540use std::collections::HashMap;