dmsc/device/
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 Control Module
19//! 
20//! This module provides comprehensive smart device control functionality for DMSC, including device
21//! discovery, control, and resource scheduling. It enables efficient management of devices and
22//! their resources across distributed environments.
23//! 
24//! ## Key Components
25//! 
26//! - **DMSCDeviceControlModule**: Main device control module implementing service module traits
27//! - **DMSCDevice**: Device representation with type, status, and capabilities
28//! - **DMSCDeviceType**: Enum defining supported device types
29//! - **DMSCDeviceStatus**: Enum defining device statuses
30//! - **DMSCDeviceCapabilities**: Device capabilities structure
31//! - **DMSCDeviceController**: Device controller for managing devices
32//! - **DMSCDeviceScheduler**: Device scheduler for resource allocation
33//! - **DMSCResourcePool**: Resource pool for managing device resources
34//! - **DMSCResourcePoolManager**: Manager for multiple resource pools
35//! - **DMSCResourcePoolStatistics**: Statistics for resource pool monitoring
36//! - **DMSCDeviceControlConfig**: Configuration for device control behavior
37//! - **DMSCDiscoveryResult**: Result structure for device discovery
38//! - **DMSCResourceRequest**: Request structure for resource allocation
39//! - **DMSCResourceAllocation**: Result structure for resource allocation
40//! - **DMSCResourcePoolStatus**: Status structure for resource pools
41//! 
42//! ## Design Principles
43//! 
44//! 1. **Device Abstraction**: Unified interface for different device types
45//! 2. **Auto Discovery**: Automatic device discovery in the network/environment
46//! 3. **Resource Scheduling**: Intelligent resource allocation and scheduling
47//! 4. **Configurable**: Highly configurable device control behavior
48//! 5. **Async Support**: Full async/await compatibility
49//! 6. **Resource Pooling**: Efficient management of device resources through pooling
50//! 7. **Service Module Integration**: Implements service module traits for seamless integration
51//! 8. **Thread-safe**: Uses Arc and RwLock for safe concurrent access
52//! 9. **Non-critical**: Device control failures should not break the entire application
53//! 10. **Monitoring**: Comprehensive statistics for device and resource monitoring
54//! 11. **Scalable**: Designed to handle large numbers of devices and concurrent tasks
55//! 
56//! ## Usage
57//! 
58//! ```rust
59//! use dmsc::prelude::*;
60//! use dmsc::device::{DMSCDeviceControlConfig, DMSCResourceRequest, DMSCDeviceType, DMSCDeviceCapabilities};
61//! 
62//! async fn example() -> DMSCResult<()> {
63//!     // Create device control configuration
64//!     let device_config = DMSCDeviceControlConfig {
65//!         discovery_enabled: true,
66//!         discovery_interval_secs: 30,
67//!         auto_scheduling_enabled: true,
68//!         max_concurrent_tasks: 100,
69//!         resource_allocation_timeout_secs: 60,
70//!     };
71//!     
72//!     // Create device control module
73//!     let device_module = DMSCDeviceControlModule::new()
74//!         .with_config(device_config);
75//!     
76//!     // Discover devices
77//!     let discovery_result = device_module.discover_devices().await?;
78//!     println!("Discovered {} devices, total devices: {}", 
79//!              discovery_result.discovered_devices.len(), 
80//!              discovery_result.total_devices);
81//!     
82//!     // Get device status
83//!     let devices = device_module.get_device_status().await?;
84//!     println!("Current devices: {:?}", devices);
85//!     
86//!     // Create resource request
87//!     let resource_request = DMSCResourceRequest {
88//!         request_id: "request-123".to_string(),
89//!         device_type: DMSCDeviceType::Compute,
90//!         required_capabilities: DMSCDeviceCapabilities {
91//!             cpu_cores: Some(4),
92//!             memory_gb: Some(8.0),
93//!             storage_gb: Some(100.0),
94//!             gpu_enabled: Some(true),
95//!             network_speed_mbps: Some(1000.0),
96//!             extra: Default::default(),
97//!         },
98//!         priority: 5,
99//!         timeout_secs: 30,
100//!     };
101//!     
102//!     // Allocate resource
103//!     if let Some(allocation) = device_module.allocate_resource(resource_request).await? {
104//!         println!("Allocated device: {} (ID: {})", 
105//!                  allocation.device_name, 
106//!                  allocation.device_id);
107//!         
108//!         // Release resource after use
109//!         device_module.release_resource(&allocation.allocation_id).await?;
110//!     }
111//!     
112//!     Ok(())
113//! }
114//! ```
115
116mod core;
117mod controller;
118pub mod scheduler;
119pub mod pool;
120pub mod discovery_scheduler;
121pub mod discovery;
122
123use std::sync::Arc;
124
125use serde::{Serialize, Deserialize};
126use tokio::sync::RwLock;
127use std::collections::HashMap;
128
129use crate::observability::{DMSCMetricsRegistry, DMSCMetric, DMSCMetricConfig, DMSCMetricType};
130
131#[cfg(feature = "pyo3")]
132use pyo3::prelude::*;
133
134
135pub use core::{DMSCDevice, DMSCDeviceType, DMSCDeviceStatus, DMSCDeviceCapabilities, DMSCDeviceControlConfig, DMSCDeviceConfig, DMSCNetworkDeviceInfo, DMSCDeviceHealthMetrics};
136pub use controller::DMSCDeviceController;
137pub use pool::{DMSCResourcePool, DMSCResourcePoolManager, DMSCConnectionPoolStatistics};
138pub use scheduler::DMSCDeviceScheduler;
139pub use discovery_scheduler::{DMSCDeviceDiscoveryEngine, DMSCResourceScheduler};
140
141// Re-export discovery module types
142pub use discovery::{
143    DMSCDeviceDiscovery,
144    DiscoveryConfig,
145    DiscoveryStats,
146    DiscoveryStrategy,
147    HardwareCategory,
148    PlatformInfo,
149    PlatformType,
150    Architecture,
151    PlatformCompatibility,
152    ProviderRegistry,
153    DMSCHardwareProvider,
154    PluginRegistry,
155    DMSCHardwareDiscoveryPlugin,
156    PluginMetadata,
157    PluginStatus,
158    PluginError,
159    AsyncDiscovery,
160};
161
162use crate::core::{DMSCResult, DMSCServiceContext};
163
164
165/// Main device control module for DMSC.
166/// 
167/// This module provides comprehensive smart device control functionality, including device discovery,
168/// control, and resource scheduling. It manages devices and their resources across distributed environments.
169#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
170pub struct DMSCDeviceControlModule {
171    /// Device controller for managing devices
172    controller: Arc<RwLock<DMSCDeviceController>>,
173    /// Device scheduler for resource allocation
174    scheduler: Arc<RwLock<DMSCDeviceScheduler>>,
175    /// Discovery engine for device discovery
176    discovery_engine: Arc<RwLock<DMSCResourceScheduler>>,
177    /// Map of resource pool names to resource pool instances
178    resource_pools: HashMap<String, Arc<DMSCResourcePool>>,
179    /// Device control configuration
180    config: DMSCDeviceControlConfig,
181}
182
183/// Scheduling configuration for device control module
184///
185/// This configuration contains scheduling and resource management settings
186/// for device control operations.
187#[derive(Debug, Clone, Serialize, Deserialize)]
188#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
189pub struct DMSCDeviceSchedulingConfig {
190    /// Whether device discovery is enabled
191    pub discovery_enabled: bool,
192    /// Interval between device discovery scans in seconds
193    pub discovery_interval_secs: u64,
194    /// Whether automatic resource scheduling is enabled
195    pub auto_scheduling_enabled: bool,
196    /// Maximum number of concurrent tasks
197    pub max_concurrent_tasks: usize,
198    /// Timeout for resource allocation in seconds
199    pub resource_allocation_timeout_secs: u64,
200}
201
202impl Default for DMSCDeviceSchedulingConfig {
203    fn default() -> Self {
204        Self {
205            discovery_enabled: true,
206            discovery_interval_secs: 30,
207            auto_scheduling_enabled: true,
208            max_concurrent_tasks: 100,
209            resource_allocation_timeout_secs: 60,
210        }
211    }
212}
213
214#[cfg(feature = "pyo3")]
215#[pymethods]
216impl DMSCDeviceSchedulingConfig {
217    #[new]
218    fn py_new() -> Self {
219        Self::default()
220    }
221    
222    #[staticmethod]
223    fn default_config() -> Self {
224        Self::default()
225    }
226}
227
228/// Result structure for device discovery operations.
229/// 
230/// This struct contains information about the results of a device discovery scan, including
231/// discovered, updated, and removed devices.
232#[derive(Debug, Clone, Serialize, Deserialize)]
233#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
234pub struct DMSCDiscoveryResult {
235    /// Newly discovered devices
236    pub discovered_devices: Vec<DMSCDevice>,
237    /// Devices with updated information
238    pub updated_devices: Vec<DMSCDevice>,
239    /// IDs of removed devices
240    pub removed_devices: Vec<String>, // device IDs
241    /// Total number of devices after discovery
242    pub total_devices: usize,
243}
244
245#[cfg(feature = "pyo3")]
246#[pymethods]
247impl DMSCDiscoveryResult {
248    #[new]
249    fn py_new() -> Self {
250        Self {
251            discovered_devices: Vec::new(),
252            updated_devices: Vec::new(),
253            removed_devices: Vec::new(),
254            total_devices: 0,
255        }
256    }
257    
258    #[staticmethod]
259    fn default_result() -> Self {
260        Self::default()
261    }
262    
263    fn discovered_devices_impl(&self) -> Vec<DMSCDevice> {
264        self.discovered_devices.clone()
265    }
266    
267    fn updated_devices_impl(&self) -> Vec<DMSCDevice> {
268        self.updated_devices.clone()
269    }
270    
271    fn removed_devices_impl(&self) -> Vec<String> {
272        self.removed_devices.clone()
273    }
274    
275    fn total_devices_impl(&self) -> usize {
276        self.total_devices
277    }
278    
279    fn __str__(&self) -> String {
280        format!("DMSCDiscoveryResult(discovered: {}, updated: {}, removed: {}, total: {})", 
281                self.discovered_devices.len(), self.updated_devices.len(), 
282                self.removed_devices.len(), self.total_devices)
283    }
284}
285
286impl Default for DMSCDiscoveryResult {
287    fn default() -> Self {
288        Self {
289            discovered_devices: Vec::new(),
290            updated_devices: Vec::new(),
291            removed_devices: Vec::new(),
292            total_devices: 0,
293        }
294    }
295}
296
297/// Request structure for resource allocation.
298/// 
299/// This struct defines the requirements for resource allocation, including device type, capabilities,
300/// priority, timeout, and advanced scheduling preferences such as SLA, resource weights,
301/// and affinity rules. New fields are optional to preserve backward compatibility.
302#[derive(Debug, Clone, Serialize, Deserialize)]
303#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
304pub struct DMSCResourceRequest {
305    /// Unique request ID
306    pub request_id: String,
307    /// Required device type
308    pub device_type: DMSCDeviceType,
309    /// Required device capabilities
310    pub required_capabilities: DMSCDeviceCapabilities,
311    /// Request priority (1-10, higher is more important)
312    pub priority: u8, // 1-10, higher is more important
313    /// Request timeout in seconds
314    pub timeout_secs: u64,
315    /// Optional SLA class for this request (e.g. Critical / High / Medium / Low)
316    pub sla_class: Option<DMSCRequestSlaClass>,
317    /// Optional multi-dimensional resource weights to influence scheduling decisions
318    pub resource_weights: Option<DMSCResourceWeights>,
319    /// Optional affinity rules describing preferred/required device labels
320    pub affinity: Option<DMSCAffinityRules>,
321    /// Optional anti-affinity rules describing labels or devices to avoid
322    pub anti_affinity: Option<DMSCAffinityRules>,
323}
324
325#[cfg(feature = "pyo3")]
326#[pymethods]
327impl DMSCResourceRequest {
328    #[new]
329    #[pyo3(signature = (request_id, device_type, required_capabilities, priority=5, timeout_secs=60))]
330    fn py_new(request_id: String, device_type: DMSCDeviceType, required_capabilities: DMSCDeviceCapabilities, priority: u8, timeout_secs: u64) -> Self {
331        Self {
332            request_id,
333            device_type,
334            required_capabilities,
335            priority,
336            timeout_secs,
337            sla_class: None,
338            resource_weights: None,
339            affinity: None,
340            anti_affinity: None,
341        }
342    }
343    
344    #[pyo3(name = "request_id")]
345    fn request_id_impl(&self) -> String {
346        self.request_id.clone()
347    }
348    
349    #[pyo3(name = "device_type")]
350    fn device_type_impl(&self) -> DMSCDeviceType {
351        self.device_type
352    }
353    
354    #[pyo3(name = "required_capabilities")]
355    fn required_capabilities_impl(&self) -> DMSCDeviceCapabilities {
356        self.required_capabilities.clone()
357    }
358    
359    #[pyo3(name = "priority")]
360    fn priority_impl(&self) -> u8 {
361        self.priority
362    }
363    
364    #[pyo3(name = "timeout_secs")]
365    fn timeout_secs_impl(&self) -> u64 {
366        self.timeout_secs
367    }
368    
369    #[pyo3(name = "sla_class")]
370    fn sla_class_impl(&self) -> Option<DMSCRequestSlaClass> {
371        self.sla_class
372    }
373    
374    #[pyo3(name = "resource_weights")]
375    fn resource_weights_impl(&self) -> Option<DMSCResourceWeights> {
376        self.resource_weights.clone()
377    }
378    
379    #[pyo3(name = "affinity")]
380    fn affinity_impl(&self) -> Option<DMSCAffinityRules> {
381        self.affinity.clone()
382    }
383    
384    #[pyo3(name = "anti_affinity")]
385    fn anti_affinity_impl(&self) -> Option<DMSCAffinityRules> {
386        self.anti_affinity.clone()
387    }
388    
389    #[pyo3(name = "set_priority")]
390    fn set_priority_impl(&mut self, priority: u8) {
391        self.priority = priority;
392    }
393    
394    #[pyo3(name = "set_timeout_secs")]
395    fn set_timeout_secs_impl(&mut self, timeout_secs: u64) {
396        self.timeout_secs = timeout_secs;
397    }
398    
399    #[pyo3(name = "set_sla_class")]
400    fn set_sla_class_impl(&mut self, sla_class: Option<DMSCRequestSlaClass>) {
401        self.sla_class = sla_class;
402    }
403    
404    #[pyo3(name = "set_resource_weights")]
405    fn set_resource_weights_impl(&mut self, resource_weights: Option<DMSCResourceWeights>) {
406        self.resource_weights = resource_weights;
407    }
408    
409    #[pyo3(name = "set_affinity")]
410    fn set_affinity_impl(&mut self, affinity: Option<DMSCAffinityRules>) {
411        self.affinity = affinity;
412    }
413    
414    #[pyo3(name = "set_anti_affinity")]
415    fn set_anti_affinity_impl(&mut self, anti_affinity: Option<DMSCAffinityRules>) {
416        self.anti_affinity = anti_affinity;
417    }
418    
419    fn __str__(&self) -> String {
420        format!("DMSCResourceRequest(id: {}, type: {:?}, priority: {}, timeout: {}s)", 
421                self.request_id, self.device_type, self.priority, self.timeout_secs)
422    }
423}
424
425/// SLA class for a resource request.
426/// 
427/// This enum describes the service level expectations for a request. Schedulers can
428/// use this information to trade off between latency, availability, and resource usage.
429#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
430#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
431pub enum DMSCRequestSlaClass {
432    /// Mission critical requests that should be served with the highest priority
433    Critical,
434    /// High priority requests
435    High,
436    /// Normal priority requests
437    Medium,
438    /// Low priority / best-effort requests
439    Low,
440}
441
442#[cfg(feature = "pyo3")]
443#[pymethods]
444impl DMSCRequestSlaClass {
445    fn __str__(&self) -> String {
446        match self {
447            DMSCRequestSlaClass::Critical => "Critical".to_string(),
448            DMSCRequestSlaClass::High => "High".to_string(),
449            DMSCRequestSlaClass::Medium => "Medium".to_string(),
450            DMSCRequestSlaClass::Low => "Low".to_string(),
451        }
452    }
453}
454
455/// Multi-dimensional resource weights for scheduling.
456/// 
457/// This struct allows callers to express how important different resource dimensions are
458/// (compute, memory, storage, bandwidth) for a specific request. Schedulers can use these
459/// weights when computing fitness scores.
460#[derive(Debug, Clone, Serialize, Deserialize)]
461#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
462pub struct DMSCResourceWeights {
463    /// Weight for compute resources (e.g. CPU cores, GPU units)
464    pub compute_weight: f64,
465    /// Weight for memory capacity
466    pub memory_weight: f64,
467    /// Weight for storage capacity
468    pub storage_weight: f64,
469    /// Weight for network bandwidth
470    pub bandwidth_weight: f64,
471}
472
473#[cfg(feature = "pyo3")]
474#[pymethods]
475impl DMSCResourceWeights {
476    #[new]
477    #[pyo3(signature = (compute_weight=1.0, memory_weight=1.0, storage_weight=1.0, bandwidth_weight=1.0))]
478    fn py_new(compute_weight: f64, memory_weight: f64, storage_weight: f64, bandwidth_weight: f64) -> Self {
479        Self {
480            compute_weight,
481            memory_weight,
482            storage_weight,
483            bandwidth_weight,
484        }
485    }
486    
487    #[staticmethod]
488    fn default_weights() -> Self {
489        Self::default()
490    }
491    
492    #[pyo3(name = "compute_weight")]
493    fn compute_weight_impl(&self) -> f64 { self.compute_weight }
494    #[pyo3(name = "memory_weight")]
495    fn memory_weight_impl(&self) -> f64 { self.memory_weight }
496    #[pyo3(name = "storage_weight")]
497    fn storage_weight_impl(&self) -> f64 { self.storage_weight }
498    #[pyo3(name = "bandwidth_weight")]
499    fn bandwidth_weight_impl(&self) -> f64 { self.bandwidth_weight }
500    
501    #[pyo3(name = "set_compute_weight")]
502    fn set_compute_weight_impl(&mut self, weight: f64) { self.compute_weight = weight; }
503    #[pyo3(name = "set_memory_weight")]
504    fn set_memory_weight_impl(&mut self, weight: f64) { self.memory_weight = weight; }
505    #[pyo3(name = "set_storage_weight")]
506    fn set_storage_weight_impl(&mut self, weight: f64) { self.storage_weight = weight; }
507    #[pyo3(name = "set_bandwidth_weight")]
508    fn set_bandwidth_weight_impl(&mut self, weight: f64) { self.bandwidth_weight = weight; }
509    
510    fn __str__(&self) -> String {
511        format!("DMSCResourceWeights(compute: {}, memory: {}, storage: {}, bandwidth: {})", 
512                self.compute_weight, self.memory_weight, self.storage_weight, self.bandwidth_weight)
513    }
514}
515
516impl Default for DMSCResourceWeights {
517    fn default() -> Self {
518        Self {
519            compute_weight: 1.0,
520            memory_weight: 1.0,
521            storage_weight: 1.0,
522            bandwidth_weight: 1.0,
523        }
524    }
525}
526
527/// Affinity and anti-affinity rules for device selection.
528/// 
529/// Rules are expressed as label key/value pairs. Implementations can interpret labels
530/// using device metadata such as location, zone, rack, tenant, etc.
531#[derive(Debug, Clone, Serialize, Deserialize)]
532#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
533pub struct DMSCAffinityRules {
534    /// Labels that must be present with matching values
535    pub required_labels: HashMap<String, String>,
536    /// Labels that are preferred (but not strictly required)
537    pub preferred_labels: HashMap<String, String>,
538    /// Labels that must not be present with matching values
539    pub forbidden_labels: HashMap<String, String>,
540}
541
542#[cfg(feature = "pyo3")]
543#[pymethods]
544impl DMSCAffinityRules {
545    #[new]
546    fn py_new() -> Self {
547        Self {
548            required_labels: HashMap::new(),
549            preferred_labels: HashMap::new(),
550            forbidden_labels: HashMap::new(),
551        }
552    }
553    
554    #[staticmethod]
555    fn default_rules() -> Self {
556        Self::default()
557    }
558    
559    #[pyo3(name = "required_labels")]
560    fn required_labels_impl(&self) -> HashMap<String, String> {
561        self.required_labels.clone()
562    }
563    
564    #[pyo3(name = "preferred_labels")]
565    fn preferred_labels_impl(&self) -> HashMap<String, String> {
566        self.preferred_labels.clone()
567    }
568    
569    #[pyo3(name = "forbidden_labels")]
570    fn forbidden_labels_impl(&self) -> HashMap<String, String> {
571        self.forbidden_labels.clone()
572    }
573    
574    fn __str__(&self) -> String {
575        format!("DMSCAffinityRules(required: {}, preferred: {}, forbidden: {})", 
576                self.required_labels.len(), self.preferred_labels.len(), self.forbidden_labels.len())
577    }
578}
579
580impl Default for DMSCAffinityRules {
581    fn default() -> Self {
582        Self {
583            required_labels: HashMap::new(),
584            preferred_labels: HashMap::new(),
585            forbidden_labels: HashMap::new(),
586        }
587    }
588}
589
590/// Result structure for resource allocation.
591/// 
592/// This struct contains information about a successful resource allocation, including the allocated
593/// device, allocation time, and expiration time.
594#[derive(Debug, Clone, Serialize, Deserialize)]
595#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
596pub struct DMSCResourceAllocation {
597    /// Unique allocation ID
598    pub allocation_id: String,
599    /// ID of the allocated device
600    pub device_id: String,
601    /// Name of the allocated device
602    pub device_name: String,
603    /// Time when the resource was allocated
604    pub allocated_at: chrono::DateTime<chrono::Utc>,
605    /// Time when the allocation expires
606    pub expires_at: chrono::DateTime<chrono::Utc>,
607    /// Original resource request
608    pub request: DMSCResourceRequest,
609}
610
611#[cfg(feature = "pyo3")]
612#[pymethods]
613impl DMSCResourceAllocation {
614    #[new]
615    fn py_new(allocation_id: String, device_id: String, device_name: String, request: DMSCResourceRequest) -> Self {
616        let now = chrono::Utc::now();
617        let expires_at = now + chrono::TimeDelta::seconds(request.timeout_secs as i64);
618        
619        Self {
620            allocation_id,
621            device_id,
622            device_name,
623            allocated_at: now,
624            expires_at,
625            request,
626        }
627    }
628    
629    #[pyo3(name = "allocation_id")]
630    fn allocation_id_impl(&self) -> String {
631        self.allocation_id.clone()
632    }
633    
634    #[pyo3(name = "device_id")]
635    fn device_id_impl(&self) -> String {
636        self.device_id.clone()
637    }
638    
639    #[pyo3(name = "device_name")]
640    fn device_name_impl(&self) -> String {
641        self.device_name.clone()
642    }
643    
644    #[pyo3(name = "allocated_at")]
645    fn allocated_at_impl(&self) -> String {
646        self.allocated_at.to_rfc3339()
647    }
648    
649    #[pyo3(name = "expires_at")]
650    fn expires_at_impl(&self) -> String {
651        self.expires_at.to_rfc3339()
652    }
653    
654    #[pyo3(name = "request")]
655    fn request_impl(&self) -> DMSCResourceRequest {
656        self.request.clone()
657    }
658    
659    #[pyo3(name = "is_expired")]
660    fn is_expired_impl(&self) -> bool {
661        chrono::Utc::now() > self.expires_at
662    }
663    
664    #[pyo3(name = "remaining_time")]
665    fn remaining_time_impl(&self) -> i64 {
666        (self.expires_at - chrono::Utc::now()).num_seconds()
667    }
668    
669    fn __str__(&self) -> String {
670        format!("DMSCResourceAllocation(id: {}, device: {} ({}), expires: {})", 
671                self.allocation_id, self.device_name, self.device_id, self.expires_at)
672    }
673}
674
675impl Default for DMSCDeviceControlModule {
676    fn default() -> Self {
677        Self::new()
678    }
679}
680
681impl DMSCDeviceControlModule {
682    /// Creates a new device control module with default configuration.
683    /// 
684    /// # Returns
685    /// 
686    /// A new `DMSCDeviceControlModule` instance with default configuration
687    pub fn new() -> Self {
688        let controller = Arc::new(RwLock::new(DMSCDeviceController::new()));
689        let resource_pool_manager = Arc::new(RwLock::new(DMSCResourcePoolManager::new()));
690        let scheduler = Arc::new(RwLock::new(DMSCDeviceScheduler::new(resource_pool_manager)));
691        let discovery_engine = Arc::new(RwLock::new(DMSCResourceScheduler::new()));
692        
693        Self {
694            controller,
695            scheduler,
696            discovery_engine,
697            resource_pools: HashMap::new(),
698            config: crate::device::core::DMSCDeviceControlConfig::default(),
699        }
700    }
701    
702    /// Configures the device control module with custom settings.
703    /// 
704    /// # Parameters
705    /// 
706    /// - `config`: The custom configuration to apply
707    /// 
708    /// # Returns
709    /// 
710    /// The updated `DMSCDeviceControlModule` instance
711    pub fn with_config(mut self, config: crate::device::core::DMSCDeviceControlConfig) -> Self {
712        self.config = config;
713        self
714    }
715    
716    /// Discovers devices in the network/environment.
717    /// 
718    /// This method performs a device discovery scan if discovery is enabled, returning information
719    /// about discovered, updated, and removed devices.
720    /// 
721    /// # Returns
722    /// 
723    /// A `DMSCResult<DMSCDiscoveryResult>` containing the discovery results
724    pub async fn discover_devices(&self) -> DMSCResult<DMSCDiscoveryResult> {
725        if !self.config.enable_cpu_discovery && !self.config.enable_gpu_discovery && 
726           !self.config.enable_memory_discovery && !self.config.enable_storage_discovery && 
727           !self.config.enable_network_discovery {
728            return Ok(DMSCDiscoveryResult {
729                discovered_devices: vec![],
730                updated_devices: vec![],
731                removed_devices: vec![],
732                total_devices: 0,
733            });
734        }
735        
736        let mut controller = self.controller.write().await;
737        controller.discover_devices().await
738    }
739    
740    /// Allocates a device resource based on the given request.
741    /// 
742    /// This method finds a suitable device based on the requested device type and capabilities,
743    /// allocates it using the device scheduler, and returns an allocation result if successful.
744    /// 
745    /// # Parameters
746    /// 
747    /// - `request`: The resource allocation request
748    /// 
749    /// # Returns
750    /// 
751    /// A `DMSCResult<Option<DMSCResourceAllocation>>` containing the allocation result if successful,
752    /// or None if allocation failed or auto-scheduling is disabled
753    pub async fn allocate_resource(&self, request: DMSCResourceRequest) -> DMSCResult<Option<DMSCResourceAllocation>> {
754        // Check if any device type scheduling is enabled
755        let scheduling_enabled = match request.device_type {
756            DMSCDeviceType::CPU => self.config.enable_cpu_discovery,
757            DMSCDeviceType::GPU => self.config.enable_gpu_discovery,
758            DMSCDeviceType::Memory => self.config.enable_memory_discovery,
759            DMSCDeviceType::Storage => self.config.enable_storage_discovery,
760            DMSCDeviceType::Network => self.config.enable_network_discovery,
761            _ => true, // Default to enabled for unknown types
762        };
763        
764        if !scheduling_enabled {
765            return Ok(None);
766        }
767
768        let allocation_request = crate::device::scheduler::DMSCAllocationRequest {
769            device_type: request.device_type,
770            capabilities: request.required_capabilities,
771            priority: request.priority as u32,
772            timeout_secs: request.timeout_secs,
773            sla_class: request.sla_class,
774            resource_weights: request.resource_weights,
775            affinity: request.affinity,
776            anti_affinity: request.anti_affinity,
777        };
778
779        let scheduler = self.scheduler.write().await;
780        let device = scheduler.select_device(&allocation_request).await;
781
782        if let Some(device) = device {
783            let allocation = DMSCResourceAllocation {
784                allocation_id: uuid::Uuid::new_v4().to_string(),
785                device_id: device.id().to_string(),
786                device_name: device.name().to_string(),
787                allocated_at: chrono::Utc::now(),
788                expires_at: chrono::Utc::now() + chrono::Duration::seconds(allocation_request.timeout_secs as i64),
789                request: DMSCResourceRequest {
790                    request_id: request.request_id,
791                    device_type: allocation_request.device_type,
792                    required_capabilities: allocation_request.capabilities,
793                    priority: request.priority,
794                    timeout_secs: allocation_request.timeout_secs,
795                    sla_class: allocation_request.sla_class,
796                    resource_weights: allocation_request.resource_weights,
797                    affinity: allocation_request.affinity,
798                    anti_affinity: allocation_request.anti_affinity,
799                },
800            };
801
802            // Mark device as busy via controller
803            let mut controller = self.controller.write().await;
804            controller.allocate_device(&allocation.device_id, &allocation.allocation_id).await?;
805
806            Ok(Some(allocation))
807        } else {
808            Ok(None)
809        }
810    }
811    
812    /// Releases a previously allocated device resource.
813    /// 
814    /// This method releases a device resource that was allocated with `allocate_resource`.
815    /// 
816    /// # Parameters
817    /// 
818    /// - `allocation_id`: The ID of the allocation to release
819    /// 
820    /// # Returns
821    /// 
822    /// A `DMSCResult<()>` indicating success or failure
823    pub async fn release_resource(&self, allocation_id: &str) -> DMSCResult<()> {
824        let mut controller = self.controller.write().await;
825        controller.release_device_by_allocation(allocation_id).await
826    }
827    
828    /// Gets the current status of all devices.
829    /// 
830    /// This method returns a list of all devices currently managed by the device controller.
831    /// 
832    /// # Returns
833    /// 
834    /// A `DMSCResult<Vec<DMSCDevice>>` containing all managed devices
835    pub async fn get_device_status(&self) -> DMSCResult<Vec<DMSCDevice>> {
836        let controller = self.controller.read().await;
837        Ok(controller.get_all_devices())
838    }
839    
840    /// Gets the status of all resource pools.
841    /// 
842    /// This method returns a map of resource pool names to their current status.
843    /// 
844    /// # Returns
845    /// 
846    /// A `HashMap<String, DMSCResourcePoolStatus>` containing the status of all resource pools
847    pub fn get_resource_pool_status(&self) -> HashMap<String, DMSCResourcePoolStatus> {
848        let mut status = HashMap::new();
849        for (pool_name, pool) in &self.resource_pools {
850            status.insert(pool_name.clone(), pool.get_status());
851        }
852        status
853    }
854    
855    /// Creates device management metrics and registers them with the metrics registry.
856    /// 
857    /// This method creates and registers the following metrics:
858    /// - dms_device_total: Total number of devices by type and status
859    /// - dms_device_allocation_attempts_total: Total number of allocation attempts
860    /// - dms_device_allocation_success_total: Total number of successful allocations
861    /// - dms_device_allocation_failure_total: Total number of failed allocations
862    /// - dms_device_discovery_attempts_total: Total number of device discovery attempts
863    /// - dms_device_discovery_success_total: Total number of successful device discoveries
864    /// - dms_device_resource_utilization: Resource utilization by device type
865    /// 
866    /// # Parameters
867    /// 
868    /// - `registry`: The metrics registry to register the metrics with
869    /// 
870    /// # Returns
871    /// 
872    /// A `DMSCResult<()>` indicating success or failure
873    #[allow(dead_code)]
874    fn create_device_metrics(&self, registry: Arc<DMSCMetricsRegistry>) -> DMSCResult<()> {
875        // Device total metric (Gauge)
876        let device_total_config = DMSCMetricConfig {
877            metric_type: DMSCMetricType::Gauge,
878            name: "dms_device_total".to_string(),
879            help: "Total number of devices by type and status".to_string(),
880            buckets: vec![],
881            quantiles: vec![],
882            max_age: std::time::Duration::from_secs(300),
883            age_buckets: 5,
884        };
885        let device_total_metric = Arc::new(DMSCMetric::new(device_total_config));
886        registry.register(device_total_metric)?;
887        
888        // Allocation attempts metric (Counter)
889        let allocation_attempts_config = DMSCMetricConfig {
890            metric_type: DMSCMetricType::Counter,
891            name: "dms_device_allocation_attempts_total".to_string(),
892            help: "Total number of device allocation attempts".to_string(),
893            buckets: vec![],
894            quantiles: vec![],
895            max_age: std::time::Duration::from_secs(0),
896            age_buckets: 0,
897        };
898        let allocation_attempts_metric = Arc::new(DMSCMetric::new(allocation_attempts_config));
899        registry.register(allocation_attempts_metric)?;
900        
901        // Allocation success metric (Counter)
902        let allocation_success_config = DMSCMetricConfig {
903            metric_type: DMSCMetricType::Counter,
904            name: "dms_device_allocation_success_total".to_string(),
905            help: "Total number of successful device allocations".to_string(),
906            buckets: vec![],
907            quantiles: vec![],
908            max_age: std::time::Duration::from_secs(0),
909            age_buckets: 0,
910        };
911        let allocation_success_metric = Arc::new(DMSCMetric::new(allocation_success_config));
912        registry.register(allocation_success_metric)?;
913        
914        // Allocation failure metric (Counter)
915        let allocation_failure_config = DMSCMetricConfig {
916            metric_type: DMSCMetricType::Counter,
917            name: "dms_device_allocation_failure_total".to_string(),
918            help: "Total number of failed device allocations".to_string(),
919            buckets: vec![],
920            quantiles: vec![],
921            max_age: std::time::Duration::from_secs(0),
922            age_buckets: 0,
923        };
924        let allocation_failure_metric = Arc::new(DMSCMetric::new(allocation_failure_config));
925        registry.register(allocation_failure_metric)?;
926        
927        // Discovery attempts metric (Counter)
928        let discovery_attempts_config = DMSCMetricConfig {
929            metric_type: DMSCMetricType::Counter,
930            name: "dms_device_discovery_attempts_total".to_string(),
931            help: "Total number of device discovery attempts".to_string(),
932            buckets: vec![],
933            quantiles: vec![],
934            max_age: std::time::Duration::from_secs(0),
935            age_buckets: 0,
936        };
937        let discovery_attempts_metric = Arc::new(DMSCMetric::new(discovery_attempts_config));
938        registry.register(discovery_attempts_metric)?;
939        
940        // Discovery success metric (Counter)
941        let discovery_success_config = DMSCMetricConfig {
942            metric_type: DMSCMetricType::Counter,
943            name: "dms_device_discovery_success_total".to_string(),
944            help: "Total number of successful device discoveries".to_string(),
945            buckets: vec![],
946            quantiles: vec![],
947            max_age: std::time::Duration::from_secs(0),
948            age_buckets: 0,
949        };
950        let discovery_success_metric = Arc::new(DMSCMetric::new(discovery_success_config));
951        registry.register(discovery_success_metric)?;
952        
953        // Resource utilization metric (Gauge)
954        let resource_utilization_config = DMSCMetricConfig {
955            metric_type: DMSCMetricType::Gauge,
956            name: "dms_device_resource_utilization".to_string(),
957            help: "Resource utilization by device type".to_string(),
958            buckets: vec![],
959            quantiles: vec![],
960            max_age: std::time::Duration::from_secs(300),
961            age_buckets: 5,
962        };
963        let resource_utilization_metric = Arc::new(DMSCMetric::new(resource_utilization_config));
964        registry.register(resource_utilization_metric)?;
965        
966        Ok(())
967    }
968}
969
970#[cfg(feature = "pyo3")]
971#[pyo3::prelude::pymethods]
972impl DMSCDeviceControlModule {
973    fn get_config(&self) -> String {
974        format!("{:?}", self.config)
975    }
976}
977
978/// Status structure for resource pools.
979/// 
980/// This struct contains information about the current status of a resource pool, including capacity,
981/// allocation, and utilization.
982#[derive(Debug, Clone, Serialize, Deserialize)]
983#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
984pub struct DMSCResourcePoolStatus {
985    /// Total capacity of the resource pool
986    pub total_capacity: usize,
987    /// Available capacity in the resource pool
988    pub available_capacity: usize,
989    /// Allocated capacity in the resource pool
990    pub allocated_capacity: usize,
991    /// Number of pending resource requests
992    pub pending_requests: usize,
993    /// Resource utilization rate (0.0 to 1.0)
994    pub utilization_rate: f64,
995}
996
997#[cfg(feature = "pyo3")]
998#[pyo3::prelude::pymethods]
999impl DMSCResourcePoolStatus {
1000    #[new]
1001    #[pyo3(signature = (total_capacity=0, available_capacity=0, allocated_capacity=0, pending_requests=0, utilization_rate=0.0))]
1002    fn py_new(total_capacity: usize, available_capacity: usize, allocated_capacity: usize, pending_requests: usize, utilization_rate: f64) -> Self {
1003        Self {
1004            total_capacity,
1005            available_capacity,
1006            allocated_capacity,
1007            pending_requests,
1008            utilization_rate,
1009        }
1010    }
1011    
1012    #[staticmethod]
1013    fn default_status() -> Self {
1014        Self::default()
1015    }
1016    
1017    #[pyo3(name = "total_capacity")]
1018    fn total_capacity_impl(&self) -> usize {
1019        self.total_capacity
1020    }
1021    
1022    #[pyo3(name = "available_capacity")]
1023    fn available_capacity_impl(&self) -> usize {
1024        self.available_capacity
1025    }
1026    
1027    #[pyo3(name = "allocated_capacity")]
1028    fn allocated_capacity_impl(&self) -> usize {
1029        self.allocated_capacity
1030    }
1031    
1032    #[pyo3(name = "pending_requests")]
1033    fn pending_requests_impl(&self) -> usize {
1034        self.pending_requests
1035    }
1036    
1037    #[pyo3(name = "utilization_rate")]
1038    fn utilization_rate_impl(&self) -> f64 {
1039        self.utilization_rate
1040    }
1041    
1042    fn __str__(&self) -> String {
1043        format!("DMSCResourcePoolStatus(total: {}, available: {}, allocated: {}, utilization: {:.2}%)",
1044                self.total_capacity, self.available_capacity, self.allocated_capacity, self.utilization_rate)
1045    }
1046}
1047
1048impl Default for DMSCResourcePoolStatus {
1049    fn default() -> Self {
1050        Self {
1051            total_capacity: 0,
1052            available_capacity: 0,
1053            allocated_capacity: 0,
1054            pending_requests: 0,
1055            utilization_rate: 0.0,
1056        }
1057    }
1058}
1059
1060#[async_trait::async_trait]
1061impl crate::core::DMSCModule for DMSCDeviceControlModule {
1062    /// Returns the name of the device control module.
1063    /// 
1064    /// # Returns
1065    /// 
1066    /// The module name as a string
1067    fn name(&self) -> &str {
1068        "DMSC.DeviceControl"
1069    }
1070    
1071    /// Indicates whether the device control module is critical.
1072    /// 
1073    /// The device control module is non-critical, meaning that if it fails to initialize or operate,
1074    /// it should not break the entire application. This allows the core functionality to continue
1075    /// even if device control features are unavailable.
1076    /// 
1077    /// # Returns
1078    /// 
1079    /// `false` since device control is non-critical
1080    fn is_critical(&self) -> bool {
1081        false // Non-critical, should not break the app if device control fails
1082    }
1083    
1084    /// Initializes the device control module asynchronously.
1085    /// 
1086    /// This method performs the following steps:
1087    /// 1. Loads configuration from the service context
1088    /// 2. Initializes real device discovery based on system hardware
1089    /// 3. Sets up resource scheduling and management
1090    async fn init(&mut self, ctx: &mut DMSCServiceContext) -> DMSCResult<()> {
1091        let binding = ctx.config();
1092        let cfg = binding.config();
1093        let device_config = parse_device_config(cfg.get("device"));
1094        
1095        let mut controller = self.controller.write().await;
1096        controller.discover_system_devices(&device_config).await?;
1097        drop(controller);
1098        
1099        let discovery_engine = DMSCResourceScheduler::new();
1100        
1101        let mut discovery_guard = self.discovery_engine.write().await;
1102        *discovery_guard = discovery_engine;
1103        
1104        if let Some(metrics_registry) = ctx.metrics_registry() {
1105            let mut controller = self.controller.write().await;
1106            controller.initialize_metrics(&metrics_registry)?;
1107            drop(controller);
1108        }
1109        
1110        let logger = ctx.logger();
1111        logger.info("DMSC.DeviceControl", "Device control module initialized with real hardware discovery")?;
1112        Ok(())
1113    }
1114}
1115
1116impl crate::core::ServiceModule for DMSCDeviceControlModule {
1117    fn name(&self) -> &str {
1118        "DMSC.DeviceControl"
1119    }
1120
1121    fn is_critical(&self) -> bool {
1122        false
1123    }
1124
1125    fn priority(&self) -> i32 {
1126        25
1127    }
1128
1129    fn dependencies(&self) -> Vec<&str> {
1130        vec![]
1131    }
1132
1133    fn init(&mut self, _ctx: &mut crate::core::DMSCServiceContext) -> crate::core::DMSCResult<()> {
1134        Ok(())
1135    }
1136
1137    fn start(&mut self, _ctx: &mut crate::core::DMSCServiceContext) -> crate::core::DMSCResult<()> {
1138        Ok(())
1139    }
1140
1141    fn shutdown(&mut self, _ctx: &mut crate::core::DMSCServiceContext) -> crate::core::DMSCResult<()> {
1142        Ok(())
1143    }
1144}
1145
1146fn parse_device_config(config_str: Option<&String>) -> crate::device::core::DMSCDeviceControlConfig {
1147    match config_str {
1148        Some(config) => {
1149            let trimmed = config.trim();
1150            if trimmed.starts_with('{') {
1151                if let Ok(result) = serde_json::from_str::<crate::device::core::DMSCDeviceControlConfig>(trimmed) {
1152                    return result;
1153                }
1154            }
1155            if trimmed.starts_with("---") || trimmed.contains("discovery_enabled:") {
1156                if let Ok(result) = serde_yaml::from_str::<crate::device::core::DMSCDeviceControlConfig>(trimmed) {
1157                    return result;
1158                }
1159            }
1160            if trimmed.contains('[') || trimmed.contains("discovery_enabled") {
1161                if let Ok(result) = toml::from_str::<crate::device::core::DMSCDeviceControlConfig>(trimmed) {
1162                    return result;
1163                }
1164            }
1165            serde_json::from_str::<crate::device::core::DMSCDeviceControlConfig>(trimmed)
1166                .unwrap_or_default()
1167        }
1168        None => crate::device::core::DMSCDeviceControlConfig::default(),
1169    }
1170}