dmsc/device/discovery/
providers.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//! # Hardware Discovery Providers
19//!
20//! This module provides hardware discovery providers for different device types.
21//! Each provider implements a common interface to detect and enumerate hardware
22//! on the current platform.
23//!
24//! ## Architecture
25//!
26//! - **DMSCHardwareProvider**: Trait defining the provider interface
27//! - **CPUProvider**: Discovers CPU devices
28//! - **MemoryProvider**: Discovers memory devices
29//! - **StorageProvider**: Discovers storage devices
30//! - **NetworkProvider**: Discovers network devices
31//! - **GPUProvider**: Discovers GPU devices
32//! - **USBProvider**: Discovers USB devices
33//! - **ProviderRegistry**: Manages all available providers
34//!
35//! ## Usage
36//!
37//! ```rust,ignore
38//! use dmsc::device::discovery::providers::{ProviderRegistry, CPUProvider};
39//!
40//! let mut registry = ProviderRegistry::new();
41//! registry.register(Box::new(CPUProvider::new()));
42//!
43//! // Discover all CPU devices
44//! let cpus = registry.discover_devices("cpu").await;
45//! ```
46
47use async_trait::async_trait;
48use std::sync::Arc;
49use tokio::sync::RwLock;
50use super::super::core::{DMSCDevice, DMSCDeviceType, DMSCDeviceCapabilities};
51use super::platform::{PlatformInfo, HardwareCategory};
52
53/// Result type for hardware discovery
54pub type DiscoveryResult<T> = Result<T, String>;
55
56/// Trait for hardware discovery providers
57#[async_trait]
58pub trait DMSCHardwareProvider: Send + Sync {
59    /// Returns the provider name
60    fn name(&self) -> &str;
61
62    /// Returns the hardware categories this provider handles
63    fn categories(&self) -> Vec<HardwareCategory>;
64
65    /// Discovers devices of this type
66    async fn discover(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>>;
67
68    /// Returns the priority of this provider (lower = higher priority)
69    fn priority(&self) -> u32;
70
71    /// Checks if this provider is available on the current platform
72    fn is_available(&self, platform: &PlatformInfo) -> bool;
73}
74
75/// CPU Discovery Provider
76pub struct CPUProvider {
77    priority: u32,
78}
79
80impl CPUProvider {
81    /// Creates a new CPU provider
82    pub fn new() -> Self {
83        Self { priority: 10 }
84    }
85}
86
87impl Default for CPUProvider {
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93#[async_trait]
94impl DMSCHardwareProvider for CPUProvider {
95    fn name(&self) -> &str {
96        "CPUProvider"
97    }
98
99    fn categories(&self) -> Vec<HardwareCategory> {
100        vec![HardwareCategory::CPU]
101    }
102
103    async fn discover(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
104        let mut devices = Vec::new();
105
106        // Get CPU information based on platform
107        match platform.platform_type {
108            super::platform::PlatformType::Linux => {
109                devices.extend(discover_linux_cpus(platform).await?);
110            }
111            super::platform::PlatformType::MacOS => {
112                devices.extend(discover_macos_cpus(platform).await?);
113            }
114            super::platform::PlatformType::Windows => {
115                devices.extend(discover_windows_cpus(platform).await?);
116            }
117            _ => {
118                // Generic fallback for other platforms
119                devices.extend(discover_generic_cpus(platform).await?);
120            }
121        }
122
123        Ok(devices)
124    }
125
126    fn priority(&self) -> u32 {
127        self.priority
128    }
129
130    fn is_available(&self, _platform: &PlatformInfo) -> bool {
131        true
132    }
133}
134
135/// Memory Discovery Provider
136pub struct MemoryProvider {
137    priority: u32,
138}
139
140impl MemoryProvider {
141    pub fn new() -> Self {
142        Self { priority: 20 }
143    }
144}
145
146impl Default for MemoryProvider {
147    fn default() -> Self {
148        Self::new()
149    }
150}
151
152#[async_trait]
153impl DMSCHardwareProvider for MemoryProvider {
154    fn name(&self) -> &str {
155        "MemoryProvider"
156    }
157
158    fn categories(&self) -> Vec<HardwareCategory> {
159        vec![HardwareCategory::Memory]
160    }
161
162    async fn discover(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
163        let mut devices = Vec::new();
164
165        match platform.platform_type {
166            super::platform::PlatformType::Linux => {
167                devices.extend(discover_linux_memory(platform).await?);
168            }
169            super::platform::PlatformType::MacOS => {
170                devices.extend(discover_macos_memory(platform).await?);
171            }
172            super::platform::PlatformType::Windows => {
173                devices.extend(discover_windows_memory(platform).await?);
174            }
175            _ => {
176                devices.extend(discover_generic_memory(platform).await?);
177            }
178        }
179
180        Ok(devices)
181    }
182
183    fn priority(&self) -> u32 {
184        self.priority
185    }
186
187    fn is_available(&self, _platform: &PlatformInfo) -> bool {
188        true
189    }
190}
191
192/// Storage Discovery Provider
193pub struct StorageProvider {
194    priority: u32,
195}
196
197impl StorageProvider {
198    pub fn new() -> Self {
199        Self { priority: 30 }
200    }
201}
202
203impl Default for StorageProvider {
204    fn default() -> Self {
205        Self::new()
206    }
207}
208
209#[async_trait]
210impl DMSCHardwareProvider for StorageProvider {
211    fn name(&self) -> &str {
212        "StorageProvider"
213    }
214
215    fn categories(&self) -> Vec<HardwareCategory> {
216        vec![HardwareCategory::Storage]
217    }
218
219    async fn discover(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
220        let mut devices = Vec::new();
221
222        match platform.platform_type {
223            super::platform::PlatformType::Linux => {
224                devices.extend(discover_linux_storage(platform).await?);
225            }
226            super::platform::PlatformType::MacOS => {
227                devices.extend(discover_macos_storage(platform).await?);
228            }
229            super::platform::PlatformType::Windows => {
230                devices.extend(discover_windows_storage(platform).await?);
231            }
232            _ => {
233                devices.extend(discover_generic_storage(platform).await?);
234            }
235        }
236
237        Ok(devices)
238    }
239
240    fn priority(&self) -> u32 {
241        self.priority
242    }
243
244    fn is_available(&self, _platform: &PlatformInfo) -> bool {
245        true
246    }
247}
248
249/// Network Discovery Provider
250pub struct NetworkProvider {
251    priority: u32,
252}
253
254impl NetworkProvider {
255    pub fn new() -> Self {
256        Self { priority: 40 }
257    }
258}
259
260impl Default for NetworkProvider {
261    fn default() -> Self {
262        Self::new()
263    }
264}
265
266#[async_trait]
267impl DMSCHardwareProvider for NetworkProvider {
268    fn name(&self) -> &str {
269        "NetworkProvider"
270    }
271
272    fn categories(&self) -> Vec<HardwareCategory> {
273        vec![HardwareCategory::Network]
274    }
275
276    async fn discover(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
277        let mut devices = Vec::new();
278
279        match platform.platform_type {
280            super::platform::PlatformType::Linux => {
281                devices.extend(discover_linux_network(platform).await?);
282            }
283            super::platform::PlatformType::MacOS => {
284                devices.extend(discover_macos_network(platform).await?);
285            }
286            super::platform::PlatformType::Windows => {
287                devices.extend(discover_windows_network(platform).await?);
288            }
289            _ => {
290                devices.extend(discover_generic_network(platform).await?);
291            }
292        }
293
294        Ok(devices)
295    }
296
297    fn priority(&self) -> u32 {
298        self.priority
299    }
300
301    fn is_available(&self, _platform: &PlatformInfo) -> bool {
302        true
303    }
304}
305
306/// GPU Discovery Provider
307pub struct GPUProvider {
308    priority: u32,
309}
310
311impl GPUProvider {
312    pub fn new() -> Self {
313        Self { priority: 25 }
314    }
315}
316
317impl Default for GPUProvider {
318    fn default() -> Self {
319        Self::new()
320    }
321}
322
323#[async_trait]
324impl DMSCHardwareProvider for GPUProvider {
325    fn name(&self) -> &str {
326        "GPUProvider"
327    }
328
329    fn categories(&self) -> Vec<HardwareCategory> {
330        vec![HardwareCategory::GPU]
331    }
332
333    async fn discover(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
334        let mut devices = Vec::new();
335
336        match platform.platform_type {
337            super::platform::PlatformType::Linux => {
338                devices.extend(discover_linux_gpus(platform).await?);
339            }
340            super::platform::PlatformType::MacOS => {
341                devices.extend(discover_macos_gpus(platform).await?);
342            }
343            super::platform::PlatformType::Windows => {
344                devices.extend(discover_windows_gpus(platform).await?);
345            }
346            _ => {
347                devices.extend(discover_generic_gpus(platform).await?);
348            }
349        }
350
351        Ok(devices)
352    }
353
354    fn priority(&self) -> u32 {
355        self.priority
356    }
357
358    fn is_available(&self, platform: &PlatformInfo) -> bool {
359        // GPUs are not available in WebAssembly
360        platform.platform_type != super::platform::PlatformType::WebAssembly
361    }
362}
363
364/// USB Discovery Provider
365pub struct USBProvider {
366    priority: u32,
367}
368
369impl USBProvider {
370    pub fn new() -> Self {
371        Self { priority: 50 }
372    }
373}
374
375impl Default for USBProvider {
376    fn default() -> Self {
377        Self::new()
378    }
379}
380
381#[async_trait]
382impl DMSCHardwareProvider for USBProvider {
383    fn name(&self) -> &str {
384        "USBProvider"
385    }
386
387    fn categories(&self) -> Vec<HardwareCategory> {
388        vec![HardwareCategory::USB]
389    }
390
391    async fn discover(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
392        let mut devices = Vec::new();
393
394        match platform.platform_type {
395            super::platform::PlatformType::Linux => {
396                devices.extend(discover_linux_usb(platform).await?);
397            }
398            super::platform::PlatformType::MacOS => {
399                devices.extend(discover_macos_usb(platform).await?);
400            }
401            super::platform::PlatformType::Windows => {
402                devices.extend(discover_windows_usb(platform).await?);
403            }
404            _ => {
405                // No USB support on other platforms
406            }
407        }
408
409        Ok(devices)
410    }
411
412    fn priority(&self) -> u32 {
413        self.priority
414    }
415
416    fn is_available(&self, platform: &PlatformInfo) -> bool {
417        platform.platform_type != super::platform::PlatformType::WebAssembly
418    }
419}
420
421/// Provider Registry - manages all hardware discovery providers
422#[derive(Default)]
423pub struct ProviderRegistry {
424    providers: Arc<RwLock<Vec<Arc<dyn DMSCHardwareProvider>>>>,
425}
426
427impl ProviderRegistry {
428    /// Creates a new provider registry
429    pub fn new() -> Self {
430        Self {
431            providers: Arc::new(RwLock::new(Vec::new())),
432        }
433    }
434
435    /// Registers a provider
436    pub async fn register(&self, provider: Box<dyn DMSCHardwareProvider>) {
437        let mut providers = self.providers.write().await;
438        providers.push(Arc::from(provider));
439        // Sort by priority
440        providers.sort_by_key(|p| p.priority());
441    }
442
443    /// Registers the default set of providers
444    pub async fn register_defaults(&self) {
445        self.register(Box::new(CPUProvider::new())).await;
446        self.register(Box::new(MemoryProvider::new())).await;
447        self.register(Box::new(StorageProvider::new())).await;
448        self.register(Box::new(NetworkProvider::new())).await;
449        self.register(Box::new(GPUProvider::new())).await;
450        self.register(Box::new(USBProvider::new())).await;
451    }
452
453    /// Discovers devices of a specific type
454    pub async fn discover_devices(
455        &self,
456        category: &HardwareCategory,
457        platform: &PlatformInfo,
458    ) -> DiscoveryResult<Vec<DMSCDevice>> {
459        let providers = self.providers.read().await;
460        let mut all_devices = Vec::new();
461
462        for provider in providers.iter() {
463            if provider.categories().contains(category) && provider.is_available(platform) {
464                match provider.discover(platform).await {
465                    Ok(devices) => all_devices.extend(devices),
466                    Err(e) => tracing::warn!("Provider {} failed: {}", provider.name(), e),
467                }
468            }
469        }
470
471        Ok(all_devices)
472    }
473
474    /// Discovers all available devices
475    pub async fn discover_all(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
476        let providers = self.providers.read().await;
477        let mut all_devices = Vec::new();
478
479        for provider in providers.iter() {
480            if provider.is_available(platform) {
481                match provider.discover(platform).await {
482                    Ok(devices) => all_devices.extend(devices),
483                    Err(e) => tracing::warn!("Provider {} failed: {}", provider.name(), e),
484                }
485            }
486        }
487
488        Ok(all_devices)
489    }
490
491    /// Returns the number of registered providers
492    pub async fn provider_count(&self) -> usize {
493        self.providers.read().await.len()
494    }
495}
496
497/// Creates a default device with basic capabilities
498fn create_device(
499    name: String,
500    device_type: DMSCDeviceType,
501    capabilities: DMSCDeviceCapabilities,
502) -> DMSCDevice {
503    DMSCDevice::new(name, device_type)
504        .with_capabilities(capabilities)
505}
506
507// Platform-specific discovery implementations
508
509async fn discover_linux_cpus(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
510    let mut devices = Vec::new();
511
512    // Read CPU info from /proc/cpuinfo
513    if let Ok(content) = std::fs::read_to_string("/proc/cpuinfo") {
514        let mut core_count = 0;
515        let mut model_name = String::new();
516
517        for line in content.lines() {
518            if line.starts_with("processor") {
519                core_count += 1;
520            }
521            if line.starts_with("model name") || line.starts_with("Model name") {
522                if let Some(pos) = line.find(':') {
523                    model_name = line[pos + 1..].trim().to_string();
524                }
525            }
526        }
527
528        if core_count > 0 {
529            let capabilities = DMSCDeviceCapabilities::new()
530                .with_compute_units(core_count)
531                .with_memory_gb(0.0); // Memory will be set by memory provider
532
533            let device = create_device(
534                format!("CPU: {}", model_name),
535                DMSCDeviceType::CPU,
536                capabilities,
537            );
538            devices.push(device);
539        }
540    }
541
542    Ok(devices)
543}
544
545async fn discover_macos_cpus(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
546    let mut devices = Vec::new();
547
548    // Use sysctl for CPU info
549    let output = std::process::Command::new("sysctl")
550        .args(&["-n", "machdep.cpu.brand_string"])
551        .output();
552
553    let model_name = match output {
554        Ok(output) => {
555            if output.status.success() {
556                String::from_utf8_lossy(&output.stdout).trim().to_string()
557            } else {
558                "Unknown CPU".to_string()
559            }
560        }
561        Err(_) => "Unknown CPU".to_string(),
562    };
563
564    let core_count = std::thread::available_parallelism()
565        .map(|p| p.get())
566        .unwrap_or(1);
567
568    let capabilities = DMSCDeviceCapabilities::new()
569        .with_compute_units(core_count)
570        .with_memory_gb(0.0);
571
572    let device = create_device(
573        format!("CPU: {}", model_name),
574        DMSCDeviceType::CPU,
575        capabilities,
576    );
577    devices.push(device);
578
579    Ok(devices)
580}
581
582async fn discover_windows_cpus(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
583    let mut devices = Vec::new();
584
585    let output = std::process::Command::new("wmic")
586        .args(&["CPU", "Get", "Name,NumberOfCores", "/VALUE"])
587        .output();
588
589    let model_name = match output {
590        Ok(output) => {
591            if output.status.success() {
592                let output_str = String::from_utf8_lossy(&output.stdout);
593                if let Some(name_line) = output_str.lines().find(|l| l.starts_with("Name=")) {
594                    name_line[5..].to_string()
595                } else {
596                    "Unknown CPU".to_string()
597                }
598            } else {
599                "Unknown CPU".to_string()
600            }
601        }
602        Err(_) => "Unknown CPU".to_string(),
603    };
604
605    let core_count = std::thread::available_parallelism()
606        .map(|p| p.get())
607        .unwrap_or(1);
608
609    let capabilities = DMSCDeviceCapabilities::new()
610        .with_compute_units(core_count)
611        .with_memory_gb(0.0);
612
613    let device = create_device(
614        format!("CPU: {}", model_name),
615        DMSCDeviceType::CPU,
616        capabilities,
617    );
618    devices.push(device);
619
620    Ok(devices)
621}
622
623async fn discover_generic_cpus(platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
624    let capabilities = DMSCDeviceCapabilities::new()
625        .with_compute_units(platform.cpu_cores)
626        .with_memory_gb(0.0);
627
628    let device = create_device(
629        format!("Generic CPU ({} cores)", platform.cpu_cores),
630        DMSCDeviceType::CPU,
631        capabilities,
632    );
633
634    Ok(vec![device])
635}
636
637async fn discover_linux_memory(platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
638    let capabilities = DMSCDeviceCapabilities::new()
639        .with_compute_units(0)
640        .with_memory_gb(platform.total_memory as f64 / (1024.0 * 1024.0 * 1024.0));
641
642    let device = create_device(
643        format!("System Memory ({:.2} GB)", platform.total_memory as f64 / (1024.0 * 1024.0 * 1024.0)),
644        DMSCDeviceType::Memory,
645        capabilities,
646    );
647
648    Ok(vec![device])
649}
650
651async fn discover_macos_memory(platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
652    discover_linux_memory(platform).await
653}
654
655async fn discover_windows_memory(platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
656    discover_linux_memory(platform).await
657}
658
659async fn discover_generic_memory(platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
660    discover_linux_memory(platform).await
661}
662
663async fn discover_linux_storage(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
664    let mut devices = Vec::new();
665
666    // Read /proc/mounts to find mounted filesystems
667    if let Ok(content) = std::fs::read_to_string("/proc/mounts") {
668        let mut seen = std::collections::HashSet::new();
669
670        for line in content.lines() {
671            let parts: Vec<&str> = line.split_whitespace().collect();
672            if parts.len() >= 2 {
673                let device = parts[0];
674                if device.starts_with("/dev/") && !seen.contains(device) {
675                    seen.insert(device);
676
677                    let capabilities = DMSCDeviceCapabilities::new()
678                        .with_storage_gb(100.0);
679
680                    let device_info = DMSCDevice::new(
681                        device.to_string(),
682                        DMSCDeviceType::Storage,
683                    ).with_capabilities(capabilities);
684                    devices.push(device_info);
685                }
686            }
687        }
688    }
689
690    Ok(devices)
691}
692
693async fn discover_macos_storage(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
694    let mut devices = Vec::new();
695
696    let output = std::process::Command::new("df")
697        .arg("-l")
698        .output();
699
700    if let Ok(output) = output {
701        if output.status.success() {
702            let mut seen = std::collections::HashSet::new();
703            for line in String::from_utf8_lossy(&output.stdout).lines().skip(1) {
704                let parts: Vec<&str> = line.split_whitespace().collect();
705                if parts.len() >= 9 {
706                    let device = parts[0];
707                    if !seen.contains(device) && device.starts_with("/dev/") {
708                        seen.insert(device);
709                        let capabilities = DMSCDeviceCapabilities::new()
710                            .with_storage_gb(100.0);
711
712                        let device_info = DMSCDevice::new(
713                            device.to_string(),
714                            DMSCDeviceType::Storage,
715                        ).with_capabilities(capabilities);
716                        devices.push(device_info);
717                    }
718                }
719            }
720        }
721    }
722
723    Ok(devices)
724}
725
726async fn discover_windows_storage(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
727    let mut devices = Vec::new();
728
729    let output = std::process::Command::new("wmic")
730        .args(&["LogicalDisk", "Get", "Name,Size", "/VALUE"])
731        .output();
732
733    if let Ok(output) = output {
734        if output.status.success() {
735            for line in String::from_utf8_lossy(&output.stdout).lines() {
736                if line.starts_with("Name=") {
737                    let drive = &line[5..];
738                    let capabilities = DMSCDeviceCapabilities::new()
739                        .with_storage_gb(100.0);
740
741                    let device_info = DMSCDevice::new(
742                        drive.to_string(),
743                        DMSCDeviceType::Storage,
744                    ).with_capabilities(capabilities);
745                    devices.push(device_info);
746                }
747            }
748        }
749    }
750
751    Ok(devices)
752}
753
754async fn discover_generic_storage(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
755    let capabilities = DMSCDeviceCapabilities::new()
756        .with_storage_gb(100.0);
757
758    let device = create_device(
759        "Generic Storage".to_string(),
760        DMSCDeviceType::Storage,
761        capabilities,
762    );
763
764    Ok(vec![device])
765}
766
767async fn discover_linux_network(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
768    let mut devices = Vec::new();
769
770    if let Ok(content) = std::fs::read_to_string("/proc/net/dev") {
771        for line in content.lines().skip(2) {
772            let parts: Vec<&str> = line.split(':').collect();
773            if parts.len() >= 2 {
774                let interface = parts[0].trim();
775                if !interface.is_empty() && interface != "lo" {
776                    let capabilities = DMSCDeviceCapabilities::new()
777                        .with_bandwidth_gbps(1.0);
778
779                    let device = DMSCDevice::new(
780                        format!("Network Interface: {}", interface),
781                        DMSCDeviceType::Network,
782                    ).with_capabilities(capabilities);
783                    devices.push(device);
784                }
785            }
786        }
787    }
788
789    Ok(devices)
790}
791
792async fn discover_macos_network(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
793    let mut devices = Vec::new();
794
795    let output = std::process::Command::new("ifconfig")
796        .output();
797
798    if let Ok(output) = output {
799        for line in String::from_utf8_lossy(&output.stdout).lines() {
800            if line.starts_with_flags(&['a'..='z', 'A'..='Z']) && !line.starts_with("lo") {
801                let parts: Vec<&str> = line.split(':').collect();
802                if parts.len() >= 1 {
803                    let interface = parts[0].trim();
804                    if !interface.is_empty() {
805                        let capabilities = DMSCDeviceCapabilities::new()
806                            .with_bandwidth_gbps(1.0);
807
808                        let device = DMSCDevice::new(
809                            format!("Network Interface: {}", interface),
810                            DMSCDeviceType::Network,
811                        ).with_capabilities(capabilities);
812                        devices.push(device);
813                    }
814                }
815            }
816        }
817    }
818
819    Ok(devices)
820}
821
822async fn discover_windows_network(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
823    let mut devices = Vec::new();
824
825    let output = std::process::Command::new("wmic")
826        .args(&["NicConfig", "Get", "Description,MACAddress", "/VALUE"])
827        .output();
828
829    if let Ok(output) = output {
830        if output.status.success() {
831            for line in String::from_utf8_lossy(&output.stdout).lines() {
832                if line.starts_with("Description=") {
833                    let name = &line[12..];
834                    let capabilities = DMSCDeviceCapabilities::new()
835                        .with_bandwidth_gbps(1.0);
836
837                    let device = DMSCDevice::new(
838                        name.to_string(),
839                        DMSCDeviceType::Network,
840                    ).with_capabilities(capabilities);
841                    devices.push(device);
842                }
843            }
844        }
845    }
846
847    Ok(devices)
848}
849
850async fn discover_generic_network(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
851    let capabilities = DMSCDeviceCapabilities::new()
852        .with_bandwidth_gbps(1.0);
853
854    let device = create_device(
855        "Generic Network Adapter".to_string(),
856        DMSCDeviceType::Network,
857        capabilities,
858    );
859
860    Ok(vec![device])
861}
862
863async fn discover_linux_gpus(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
864    let mut devices = Vec::new();
865
866    // Check for NVIDIA GPUs
867    if let Ok(nvidia_output) = std::process::Command::new("nvidia-smi")
868        .arg("--query-gpu=name,memory.total,driver_version")
869        .arg("--format=csv,noheader")
870        .output()
871    {
872        if nvidia_output.status.success() {
873            for line in String::from_utf8_lossy(&nvidia_output.stdout).lines() {
874                let parts: Vec<&str> = line.split(',').collect();
875                if parts.len() >= 1 {
876                    let name = parts[0].trim();
877                    let capabilities = DMSCDeviceCapabilities::new()
878                        .with_compute_units(1)
879                        .with_memory_gb(8.0);
880
881                    let device = DMSCDevice::new(
882                        format!("NVIDIA GPU: {}", name),
883                        DMSCDeviceType::GPU,
884                    ).with_capabilities(capabilities);
885                    devices.push(device);
886                }
887            }
888        }
889    }
890
891    // Check for AMD GPUs in sysfs
892    if let Ok(amd_dirs) = std::fs::read_dir("/sys/class/drm") {
893        for entry in amd_dirs.flatten() {
894            if let Ok(path) = entry.path().join("device").read_link() {
895                if path.to_string_lossy().contains("pci") {
896                    let capabilities = DMSCDeviceCapabilities::new()
897                        .with_compute_units(1)
898                        .with_memory_gb(4.0);
899
900                    let device = DMSCDevice::new(
901                        format!("GPU: {}", entry.file_name().to_string_lossy()),
902                        DMSCDeviceType::GPU,
903                    ).with_capabilities(capabilities);
904                    devices.push(device);
905                }
906            }
907        }
908    }
909
910    Ok(devices)
911}
912
913async fn discover_macos_gpus(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
914    let mut devices = Vec::new();
915
916    let output = std::process::Command::new("system_profiler")
917        .args(&["SPDisplaysDataType", "-detailLevel", "mini"])
918        .output();
919
920    if let Ok(output) = output {
921        if output.status.success() {
922            let content = String::from_utf8_lossy(&output.stdout);
923            let capabilities = DMSCDeviceCapabilities::new()
924                .with_compute_units(1)
925                .with_memory_gb(4.0);
926
927            let device = DMSCDevice::new(
928                format!("GPU: {}", content.lines().next().unwrap_or("Unknown")),
929                DMSCDeviceType::GPU,
930            ).with_capabilities(capabilities);
931            devices.push(device);
932        }
933    }
934
935    Ok(devices)
936}
937
938async fn discover_windows_gpus(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
939    let mut devices = Vec::new();
940
941    let output = std::process::Command::new("wmic")
942        .args(&["Path", "Win32_VideoController", "Get", "Name,AdapterRAM", "/VALUE"])
943        .output();
944
945    if let Ok(output) = output {
946        if output.status.success() {
947            for line in String::from_utf8_lossy(&output.stdout).lines() {
948                if line.starts_with("Name=") {
949                    let name = &line[5..];
950                    let capabilities = DMSCDeviceCapabilities::new()
951                        .with_compute_units(1)
952                        .with_memory_gb(4.0);
953
954                    let device = DMSCDevice::new(
955                        name.to_string(),
956                        DMSCDeviceType::GPU,
957                    ).with_capabilities(capabilities);
958                    devices.push(device);
959                }
960            }
961        }
962    }
963
964    Ok(devices)
965}
966
967async fn discover_generic_gpus(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
968    let capabilities = DMSCDeviceCapabilities::new()
969        .with_compute_units(1)
970        .with_memory_gb(4.0);
971
972    let device = create_device(
973        "Generic GPU".to_string(),
974        DMSCDeviceType::GPU,
975        capabilities,
976    );
977
978    Ok(vec![device])
979}
980
981async fn discover_linux_usb(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
982    let mut devices = Vec::new();
983
984    if let Ok(usb_dirs) = std::fs::read_dir("/sys/bus/usb/devices") {
985        for entry in usb_dirs.flatten() {
986            if let Ok(id) = entry.file_name().into_string() {
987                if !id.is_empty() && !id.starts_with('.') {
988                    let capabilities = DMSCDeviceCapabilities::new();
989
990                    let device = DMSCDevice::new(
991                        format!("USB Device: {}", id),
992                        DMSCDeviceType::Custom,
993                    ).with_capabilities(capabilities);
994                    devices.push(device);
995                }
996            }
997        }
998    }
999
1000    Ok(devices)
1001}
1002
1003async fn discover_macos_usb(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
1004    let mut devices = Vec::new();
1005
1006    let output = std::process::Command::new("system_profiler")
1007        .args(&["SPUSBDataType", "-detailLevel", "mini"])
1008        .output();
1009
1010    if let Ok(output) = output {
1011        if output.status.success() {
1012            let content = String::from_utf8_lossy(&output.stdout);
1013            let capabilities = DMSCDeviceCapabilities::new();
1014
1015            let device = DMSCDevice::new(
1016                format!("USB: {}", content.lines().next().unwrap_or("Unknown")),
1017                DMSCDeviceType::Custom,
1018            ).with_capabilities(capabilities);
1019            devices.push(device);
1020        }
1021    }
1022
1023    Ok(devices)
1024}
1025
1026async fn discover_windows_usb(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
1027    let mut devices = Vec::new();
1028
1029    let output = std::process::Command::new("wmic")
1030        .args(&["USBController", "Get", "Name", "/VALUE"])
1031        .output();
1032
1033    if let Ok(output) = output {
1034        if output.status.success() {
1035            for line in String::from_utf8_lossy(&output.stdout).lines() {
1036                if line.starts_with("Name=") {
1037                    let name = &line[5..];
1038                    let capabilities = DMSCDeviceCapabilities::new();
1039
1040                    let device = DMSCDevice::new(
1041                        name.to_string(),
1042                        DMSCDeviceType::Custom,
1043                    ).with_capabilities(capabilities);
1044                    devices.push(device);
1045                }
1046            }
1047        }
1048    }
1049
1050    Ok(devices)
1051}
1052
1053trait StartsWith {
1054    fn starts_with_flags(&self, ranges: &[std::ops::RangeInclusive<char>]) -> bool;
1055}
1056
1057impl StartsWith for str {
1058    fn starts_with_flags(&self, ranges: &[std::ops::RangeInclusive<char>]) -> bool {
1059        if let Some(first_char) = self.chars().next() {
1060            ranges.iter().any(|r| r.contains(&first_char))
1061        } else {
1062            false
1063        }
1064    }
1065}