#![allow(non_snake_case)]
use serde::{Serialize, Deserialize};
use std::collections::HashMap as FxHashMap;
use uuid::Uuid;
#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct RiDeviceControlConfig {
pub enable_cpu_discovery: bool,
pub enable_gpu_discovery: bool,
pub enable_memory_discovery: bool,
pub enable_storage_discovery: bool,
pub enable_network_discovery: bool,
pub discovery_timeout_secs: u64,
pub max_devices_per_type: usize,
}
impl Default for RiDeviceControlConfig {
fn default() -> Self {
Self {
enable_cpu_discovery: true,
enable_gpu_discovery: true,
enable_memory_discovery: true,
enable_storage_discovery: true,
enable_network_discovery: true,
discovery_timeout_secs: 30,
max_devices_per_type: 100,
}
}
}
#[cfg(feature = "pyo3")]
#[pymethods]
impl RiDeviceControlConfig {
#[new]
fn py_new() -> Self {
Self::default()
}
#[staticmethod]
fn default_config() -> Self {
Self::default()
}
}
#[cfg(feature = "pyo3")]
#[pymethods]
impl RiDeviceHealthMetrics {
#[new]
fn py_new() -> Self {
Self::default()
}
#[staticmethod]
fn default_metrics() -> Self {
Self::default()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct RiDeviceConfig {
pub enable_cpu_discovery: bool,
pub enable_gpu_discovery: bool,
pub enable_memory_discovery: bool,
pub enable_storage_discovery: bool,
pub enable_network_discovery: bool,
pub discovery_timeout_secs: u64,
pub max_devices_per_type: usize,
}
impl Default for RiDeviceConfig {
fn default() -> Self {
Self {
enable_cpu_discovery: true,
enable_gpu_discovery: true,
enable_memory_discovery: true,
enable_storage_discovery: true,
enable_network_discovery: true,
discovery_timeout_secs: 30,
max_devices_per_type: 100,
}
}
}
#[cfg(feature = "pyo3")]
#[pymethods]
impl RiDeviceConfig {
#[new]
fn py_new() -> Self {
Self::default()
}
#[staticmethod]
fn default_config() -> Self {
Self::default()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct RiNetworkDeviceInfo {
pub id: String,
pub device_type: String,
pub source: String,
pub compute_units: Option<usize>,
pub memory_gb: Option<f64>,
pub storage_gb: Option<f64>,
pub bandwidth_gbps: Option<f64>,
}
#[cfg(feature = "pyo3")]
#[pymethods]
impl RiNetworkDeviceInfo {
#[new]
fn py_new(id: String, device_type: String, source: String) -> Self {
Self {
id,
device_type,
source,
compute_units: None,
memory_gb: None,
storage_gb: None,
bandwidth_gbps: None,
}
}
#[staticmethod]
fn default_info(id: String, device_type: String, source: String) -> Self {
Self::py_new(id, device_type, source)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub enum RiDeviceType {
CPU,
GPU,
Memory,
Storage,
Network,
Sensor,
Actuator,
Custom,
}
impl std::fmt::Display for RiDeviceType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RiDeviceType::CPU => write!(f, "CPU"),
RiDeviceType::GPU => write!(f, "GPU"),
RiDeviceType::Memory => write!(f, "Memory"),
RiDeviceType::Storage => write!(f, "Storage"),
RiDeviceType::Network => write!(f, "Network"),
RiDeviceType::Sensor => write!(f, "Sensor"),
RiDeviceType::Actuator => write!(f, "Actuator"),
RiDeviceType::Custom => write!(f, "Custom"),
}
}
}
#[cfg(feature = "pyo3")]
#[pymethods]
impl RiDeviceType {
#[staticmethod]
fn new_cpu() -> Self {
RiDeviceType::CPU
}
#[staticmethod]
fn new_gpu() -> Self {
RiDeviceType::GPU
}
#[staticmethod]
fn new_memory() -> Self {
RiDeviceType::Memory
}
#[staticmethod]
fn new_storage() -> Self {
RiDeviceType::Storage
}
#[staticmethod]
fn new_network() -> Self {
RiDeviceType::Network
}
#[staticmethod]
fn new_sensor() -> Self {
RiDeviceType::Sensor
}
#[staticmethod]
fn new_actuator() -> Self {
RiDeviceType::Actuator
}
#[staticmethod]
fn new_custom() -> Self {
RiDeviceType::Custom
}
fn __str__(&self) -> String {
self.to_string()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
pub struct RiDeviceCapabilities {
pub compute_units: Option<usize>,
pub memory_gb: Option<f64>,
pub storage_gb: Option<f64>,
pub bandwidth_gbps: Option<f64>,
pub custom_capabilities: FxHashMap<String, String>,
}
impl Default for RiDeviceCapabilities {
fn default() -> Self {
Self::new()
}
}
impl RiDeviceCapabilities {
pub fn new() -> Self {
Self {
compute_units: None,
memory_gb: None,
storage_gb: None,
bandwidth_gbps: None,
custom_capabilities: FxHashMap::default(),
}
}
pub fn with_compute_units(mut self, units: usize) -> Self {
self.compute_units = Some(units);
self
}
pub fn with_memory_gb(mut self, memory: f64) -> Self {
self.memory_gb = Some(memory);
self
}
pub fn with_storage_gb(mut self, storage: f64) -> Self {
self.storage_gb = Some(storage);
self
}
pub fn with_bandwidth_gbps(mut self, bandwidth: f64) -> Self {
self.bandwidth_gbps = Some(bandwidth);
self
}
pub fn with_custom_capability(mut self, key: String, value: String) -> Self {
self.custom_capabilities.insert(key, value);
self
}
pub fn meets_requirements(&self, requirements: &RiDeviceCapabilities) -> bool {
if let Some(required_units) = requirements.compute_units {
if let Some(available_units) = self.compute_units {
if available_units < required_units {
return false;
}
} else {
return false; }
}
if let Some(required_memory) = requirements.memory_gb {
if let Some(available_memory) = self.memory_gb {
if available_memory < required_memory {
return false;
}
} else {
return false; }
}
if let Some(required_storage) = requirements.storage_gb {
if let Some(available_storage) = self.storage_gb {
if available_storage < required_storage {
return false;
}
} else {
return false; }
}
if let Some(required_bandwidth) = requirements.bandwidth_gbps {
if let Some(available_bandwidth) = self.bandwidth_gbps {
if available_bandwidth < required_bandwidth {
return false;
}
} else {
return false; }
}
for (key, required_value) in &requirements.custom_capabilities {
match self.custom_capabilities.get(key) {
Some(available_value) => {
if available_value != required_value {
return false;
}
}
None => return false, }
}
true
}
}
#[cfg(feature = "pyo3")]
#[pymethods]
impl RiDeviceCapabilities {
#[new]
fn py_new() -> Self {
Self::new()
}
#[staticmethod]
fn default_capabilities() -> Self {
Self::default()
}
#[pyo3(name = "with_compute_units")]
fn with_compute_units_impl(&self, units: usize) -> Self {
let mut new = self.clone();
new.compute_units = Some(units);
new
}
#[pyo3(name = "with_memory_gb")]
fn with_memory_gb_impl(&self, memory: f64) -> Self {
let mut new = self.clone();
new.memory_gb = Some(memory);
new
}
#[pyo3(name = "with_storage_gb")]
fn with_storage_gb_impl(&self, storage: f64) -> Self {
let mut new = self.clone();
new.storage_gb = Some(storage);
new
}
#[pyo3(name = "with_bandwidth_gbps")]
fn with_bandwidth_gbps_impl(&self, bandwidth: f64) -> Self {
let mut new = self.clone();
new.bandwidth_gbps = Some(bandwidth);
new
}
#[pyo3(name = "with_custom_capability")]
fn with_custom_capability_impl(&self, key: String, value: String) -> Self {
let mut new = self.clone();
new.custom_capabilities.insert(key, value);
new
}
#[pyo3(name = "get_compute_units")]
fn get_compute_units_impl(&self) -> Option<usize> {
self.compute_units
}
#[pyo3(name = "get_memory_gb")]
fn get_memory_gb_impl(&self) -> Option<f64> {
self.memory_gb
}
#[pyo3(name = "get_storage_gb")]
fn get_storage_gb_impl(&self) -> Option<f64> {
self.storage_gb
}
#[pyo3(name = "get_bandwidth_gbps")]
fn get_bandwidth_gbps_impl(&self) -> Option<f64> {
self.bandwidth_gbps
}
#[pyo3(name = "get_custom_capabilities")]
fn get_custom_capabilities_impl(&self) -> FxHashMap<String, String> {
self.custom_capabilities.clone()
}
#[pyo3(name = "meets_requirements")]
fn meets_requirements_impl(&self, requirements: &RiDeviceCapabilities) -> bool {
self.meets_requirements(requirements)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub enum RiDeviceStatus {
Unknown,
Available,
Busy,
Error,
Offline,
Maintenance,
Degraded,
Allocated,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
pub struct RiDeviceHealthMetrics {
pub cpu_usage_percent: f64,
pub memory_usage_percent: f64,
pub temperature_celsius: f64,
pub error_count: u32,
pub throughput: u64, pub network_latency_ms: f64,
pub disk_iops: u64,
pub battery_level_percent: f64,
pub response_time_ms: f64,
pub uptime_seconds: u64,
}
impl Default for RiDeviceHealthMetrics {
fn default() -> Self {
Self {
cpu_usage_percent: 0.0,
memory_usage_percent: 0.0,
temperature_celsius: 0.0,
error_count: 0,
throughput: 0,
network_latency_ms: 0.0,
disk_iops: 0,
battery_level_percent: 0.0,
response_time_ms: 0.0,
uptime_seconds: 0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
pub struct RiDevice {
id: String,
name: String,
device_type: RiDeviceType,
status: RiDeviceStatus,
capabilities: RiDeviceCapabilities,
health_metrics: RiDeviceHealthMetrics,
location: Option<String>,
group: Option<String>,
tags: Vec<String>,
metadata: FxHashMap<String, String>,
last_seen: chrono::DateTime<chrono::Utc>,
current_allocation_id: Option<String>,
}
impl RiDevice {
pub fn new(name: String, device_type: RiDeviceType) -> Self {
Self {
id: Uuid::new_v4().to_string(),
name,
device_type,
status: RiDeviceStatus::Unknown,
capabilities: RiDeviceCapabilities::new(),
health_metrics: RiDeviceHealthMetrics::default(),
location: None,
group: None,
tags: Vec::new(),
metadata: FxHashMap::default(),
last_seen: chrono::Utc::now(),
current_allocation_id: None,
}
}
pub fn id(&self) -> &str {
&self.id
}
pub fn name(&self) -> &str {
&self.name
}
pub fn device_type(&self) -> RiDeviceType {
self.device_type
}
pub fn status(&self) -> RiDeviceStatus {
self.status
}
pub fn capabilities(&self) -> &RiDeviceCapabilities {
&self.capabilities
}
pub fn health_metrics(&self) -> &RiDeviceHealthMetrics {
&self.health_metrics
}
pub fn set_status(&mut self, status: RiDeviceStatus) {
self.status = status;
self.last_seen = chrono::Utc::now();
}
pub fn update_health_metrics(&mut self, metrics: RiDeviceHealthMetrics) {
self.health_metrics = metrics;
self.last_seen = chrono::Utc::now();
}
pub fn increment_error_count(&mut self) {
self.health_metrics.error_count += 1;
self.last_seen = chrono::Utc::now();
}
pub fn update_throughput(&mut self, throughput: u64) {
self.health_metrics.throughput = throughput;
self.last_seen = chrono::Utc::now();
}
pub fn with_capabilities(mut self, capabilities: RiDeviceCapabilities) -> Self {
self.capabilities = capabilities;
self
}
pub fn set_location(&mut self, location: String) {
self.location = Some(location);
}
pub fn add_metadata(&mut self, key: String, value: String) {
self.metadata.insert(key, value);
}
pub fn update_last_seen(&mut self) {
self.last_seen = chrono::Utc::now();
}
pub fn last_seen(&self) -> chrono::DateTime<chrono::Utc> {
self.last_seen
}
pub fn is_available(&self) -> bool {
self.status == RiDeviceStatus::Available && self.current_allocation_id.is_none()
}
pub fn is_allocated(&self) -> bool {
self.current_allocation_id.is_some()
}
pub fn allocate(&mut self, allocation_id: &str) -> bool {
if self.is_available() {
self.current_allocation_id = Some(allocation_id.to_string());
self.status = RiDeviceStatus::Busy;
true
} else {
false
}
}
pub fn release(&mut self) {
self.current_allocation_id = None;
if self.status == RiDeviceStatus::Busy {
self.status = RiDeviceStatus::Available;
}
}
pub fn group(&self) -> Option<&str> {
self.group.as_deref()
}
pub fn set_group(&mut self, group: Option<String>) {
self.group = group;
}
pub fn tags(&self) -> &Vec<String> {
&self.tags
}
pub fn add_tag(&mut self, tag: String) {
if !self.tags.contains(&tag) {
self.tags.push(tag);
}
}
pub fn remove_tag(&mut self, tag: &str) -> bool {
let initial_len = self.tags.len();
self.tags.retain(|t| t != tag);
self.tags.len() < initial_len
}
pub fn has_tag(&self, tag: &str) -> bool {
self.tags.contains(&tag.to_string())
}
pub fn get_allocation_id(&self) -> Option<&str> {
self.current_allocation_id.as_deref()
}
pub fn health_score(&self) -> u8 {
match self.status {
RiDeviceStatus::Available => 100,
RiDeviceStatus::Busy => 80,
RiDeviceStatus::Allocated => 80,
RiDeviceStatus::Maintenance => 60,
RiDeviceStatus::Degraded => 40,
RiDeviceStatus::Offline => 20,
RiDeviceStatus::Error => 10,
RiDeviceStatus::Unknown => 0,
}
}
pub fn is_responsive(&self, timeout_secs: i64) -> bool {
let elapsed = chrono::Utc::now() - self.last_seen;
elapsed.num_seconds() < timeout_secs
}
pub fn dynamic_health_score(&self, health_metrics: &RiDeviceHealthMetrics) -> u8 {
let mut score = self.health_score() as f64;
let cpu_penalty = (health_metrics.cpu_usage_percent / 100.0) * 20.0;
score -= cpu_penalty;
let memory_penalty = (health_metrics.memory_usage_percent / 100.0) * 15.0;
score -= memory_penalty;
let temp_penalty = if health_metrics.temperature_celsius > 80.0 {
(health_metrics.temperature_celsius - 80.0) * 2.0
} else {
0.0
};
score -= temp_penalty;
let error_penalty = (health_metrics.error_count as f64) * 5.0;
score -= error_penalty;
if matches!(self.device_type, RiDeviceType::Network) {
let latency_penalty = if health_metrics.network_latency_ms > 100.0 {
(health_metrics.network_latency_ms - 100.0) * 0.5
} else {
0.0
};
score -= latency_penalty;
}
if matches!(self.device_type, RiDeviceType::Storage) {
let iops_penalty = if health_metrics.disk_iops < 100 {
(100.0 - health_metrics.disk_iops as f64) * 0.3
} else {
0.0
};
score -= iops_penalty;
}
let battery_penalty = if health_metrics.battery_level_percent < 20.0 {
(20.0 - health_metrics.battery_level_percent) * 2.0
} else {
0.0
};
score -= battery_penalty;
let response_time_penalty = if health_metrics.response_time_ms > 50.0 {
(health_metrics.response_time_ms - 50.0) * 1.0
} else {
0.0
};
score -= response_time_penalty;
score.clamp(0.0, 100.0) as u8
}
pub fn is_healthy(&self, health_metrics: &RiDeviceHealthMetrics, timeout_secs: i64) -> bool {
self.is_responsive(timeout_secs) &&
self.dynamic_health_score(health_metrics) > 50 &&
self.status != RiDeviceStatus::Error &&
self.status != RiDeviceStatus::Offline
}
pub fn metadata(&self) -> &FxHashMap<String, String> {
&self.metadata
}
}
#[cfg(feature = "pyo3")]
#[pymethods]
impl RiDevice {
#[new]
fn py_new(name: String, device_type: RiDeviceType) -> Self {
Self::new(name, device_type)
}
#[staticmethod]
fn default_device(name: String, device_type: RiDeviceType) -> Self {
Self::new(name, device_type)
}
#[pyo3(name = "id")]
fn id_impl(&self) -> String {
self.id().to_string()
}
#[pyo3(name = "name")]
fn name_impl(&self) -> String {
self.name().to_string()
}
#[pyo3(name = "device_type")]
fn device_type_impl(&self) -> RiDeviceType {
self.device_type()
}
#[pyo3(name = "status")]
fn status_impl(&self) -> RiDeviceStatus {
self.status()
}
#[pyo3(name = "capabilities")]
fn capabilities_impl(&self) -> RiDeviceCapabilities {
self.capabilities().clone()
}
#[pyo3(name = "health_metrics")]
fn health_metrics_impl(&self) -> RiDeviceHealthMetrics {
self.health_metrics().clone()
}
#[pyo3(name = "set_status")]
fn set_status_impl(&mut self, status: RiDeviceStatus) {
self.set_status(status)
}
#[pyo3(name = "update_health_metrics")]
fn update_health_metrics_impl(&mut self, metrics: RiDeviceHealthMetrics) {
self.update_health_metrics(metrics)
}
#[pyo3(name = "increment_error_count")]
fn increment_error_count_impl(&mut self) {
self.increment_error_count()
}
#[pyo3(name = "update_throughput")]
fn update_throughput_impl(&mut self, throughput: u64) {
self.update_throughput(throughput)
}
#[pyo3(name = "with_capabilities")]
fn with_capabilities_impl(&self, capabilities: RiDeviceCapabilities) -> Self {
self.clone().with_capabilities(capabilities)
}
#[pyo3(name = "set_location")]
fn set_location_impl(&mut self, location: String) {
self.set_location(location)
}
#[pyo3(name = "add_metadata")]
fn add_metadata_impl(&mut self, key: String, value: String) {
self.add_metadata(key, value)
}
#[pyo3(name = "update_last_seen")]
fn update_last_seen_impl(&mut self) {
self.update_last_seen()
}
#[pyo3(name = "is_available")]
fn is_available_impl(&self) -> bool {
self.is_available()
}
#[pyo3(name = "is_allocated")]
fn is_allocated_impl(&self) -> bool {
self.is_allocated()
}
#[pyo3(name = "allocate")]
fn allocate_impl(&mut self, allocation_id: String) -> bool {
self.allocate(&allocation_id)
}
#[pyo3(name = "release")]
fn release_impl(&mut self) {
self.release()
}
#[pyo3(name = "group")]
fn group_impl(&self) -> Option<String> {
self.group().map(|s| s.to_string())
}
#[pyo3(name = "set_group")]
fn set_group_impl(&mut self, group: Option<String>) {
self.set_group(group)
}
#[pyo3(name = "tags")]
fn tags_impl(&self) -> Vec<String> {
self.tags().clone()
}
#[pyo3(name = "add_tag")]
fn add_tag_impl(&mut self, tag: String) {
self.add_tag(tag)
}
#[pyo3(name = "remove_tag")]
fn remove_tag_impl(&mut self, tag: String) -> bool {
self.remove_tag(&tag)
}
#[pyo3(name = "has_tag")]
fn has_tag_impl(&self, tag: String) -> bool {
self.has_tag(&tag)
}
#[pyo3(name = "get_allocation_id")]
fn get_allocation_id_impl(&self) -> Option<String> {
self.get_allocation_id().map(|s| s.to_string())
}
#[pyo3(name = "health_score")]
fn health_score_impl(&self) -> u8 {
self.health_score()
}
#[pyo3(name = "is_responsive")]
fn is_responsive_impl(&self, timeout_secs: i64) -> bool {
self.is_responsive(timeout_secs)
}
#[pyo3(name = "dynamic_health_score")]
fn dynamic_health_score_impl(&self, health_metrics: RiDeviceHealthMetrics) -> u8 {
self.dynamic_health_score(&health_metrics)
}
#[pyo3(name = "is_healthy")]
fn is_healthy_impl(&self, health_metrics: RiDeviceHealthMetrics, timeout_secs: i64) -> bool {
self.is_healthy(&health_metrics, timeout_secs)
}
#[pyo3(name = "metadata")]
fn metadata_impl(&self) -> FxHashMap<String, String> {
self.metadata().clone()
}
}