1use 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
53pub type DiscoveryResult<T> = Result<T, String>;
55
56#[async_trait]
58pub trait DMSCHardwareProvider: Send + Sync {
59 fn name(&self) -> &str;
61
62 fn categories(&self) -> Vec<HardwareCategory>;
64
65 async fn discover(&self, platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>>;
67
68 fn priority(&self) -> u32;
70
71 fn is_available(&self, platform: &PlatformInfo) -> bool;
73}
74
75pub struct CPUProvider {
77 priority: u32,
78}
79
80impl CPUProvider {
81 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 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 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
135pub 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
192pub 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
249pub 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
306pub 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 platform.platform_type != super::platform::PlatformType::WebAssembly
361 }
362}
363
364pub 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 }
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#[derive(Default)]
423pub struct ProviderRegistry {
424 providers: Arc<RwLock<Vec<Arc<dyn DMSCHardwareProvider>>>>,
425}
426
427impl ProviderRegistry {
428 pub fn new() -> Self {
430 Self {
431 providers: Arc::new(RwLock::new(Vec::new())),
432 }
433 }
434
435 pub async fn register(&self, provider: Box<dyn DMSCHardwareProvider>) {
437 let mut providers = self.providers.write().await;
438 providers.push(Arc::from(provider));
439 providers.sort_by_key(|p| p.priority());
441 }
442
443 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 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 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 pub async fn provider_count(&self) -> usize {
493 self.providers.read().await.len()
494 }
495}
496
497fn 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
507async fn discover_linux_cpus(_platform: &PlatformInfo) -> DiscoveryResult<Vec<DMSCDevice>> {
510 let mut devices = Vec::new();
511
512 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); 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 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 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 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 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}