//! Data models for RAIDGuard X use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Controller { pub id: i32, pub ip: String, pub hostname: String, pub serial_number: String, pub model: String, pub firmware_version: String, pub status: String, pub enclosures: i32, pub total_disks: i32, } impl Controller { pub fn from_json(value: &serde_json::Value) -> Option { Some(Self { id: value["id"].as_i64()? as i32, ip: value["ip"].as_str()?.to_string(), hostname: value["hostname"].as_str()?.to_string(), serial_number: value["serial_number"].as_str()?.to_string(), model: value["model"].as_str()?.to_string(), firmware_version: value["firmware_version"].as_str()?.to_string(), status: value["status"].as_str()?.to_string(), enclosures: value["enclosures"].as_i64().unwrap_or(0) as i32, total_disks: value["total_disks"].as_i64().unwrap_or(0) as i32, }) } pub fn is_online(&self) -> bool { self.status == "online" } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RaidArray { pub id: i32, pub controller_id: i32, pub name: String, pub raid_level: String, pub status: String, pub total_capacity_tb: f64, pub used_capacity_tb: f64, pub free_capacity_tb: f64, pub disk_count: i32, pub rebuild_progress: Option, } impl RaidArray { pub fn from_json(value: &serde_json::Value) -> Option { Some(Self { id: value["id"].as_i64()? as i32, controller_id: value["controller_id"].as_i64().unwrap_or(0) as i32, name: value["name"].as_str()?.to_string(), raid_level: value["raid_level"].as_str()?.to_string(), status: value["status"].as_str()?.to_string(), total_capacity_tb: value["total_capacity_tb"].as_f64().unwrap_or(0.0), used_capacity_tb: value["used_capacity_tb"].as_f64().unwrap_or(0.0), free_capacity_tb: value["free_capacity_tb"].as_f64().unwrap_or(0.0), disk_count: value["disk_count"].as_i64().unwrap_or(0) as i32, rebuild_progress: value["rebuild_progress"].as_i64().map(|v| v as i32), }) } pub fn usage_percent(&self) -> f64 { if self.total_capacity_tb > 0.0 { (self.used_capacity_tb / self.total_capacity_tb) * 100.0 } else { 0.0 } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Disk { pub slot: i32, pub enclosure: i32, pub serial_number: String, pub model: String, pub vendor: String, pub capacity_tb: f64, pub status: String, pub disk_type: String, pub temperature: i32, pub array_id: Option, pub controller_id: i32, } impl Disk { pub fn from_json(value: &serde_json::Value) -> Option { Some(Self { slot: value["slot"].as_i64().unwrap_or(0) as i32, enclosure: value["enclosure"].as_i64().unwrap_or(0) as i32, serial_number: value["serial_number"].as_str().unwrap_or("").to_string(), model: value["model"].as_str().unwrap_or("").to_string(), vendor: value["vendor"].as_str().unwrap_or("").to_string(), capacity_tb: value["capacity_tb"].as_f64().unwrap_or(0.0), status: value["status"].as_str().unwrap_or("").to_string(), disk_type: value["disk_type"].as_str().unwrap_or("").to_string(), temperature: value["temperature"].as_i64().unwrap_or(0) as i32, array_id: value["array_id"].as_i64().map(|v| v as i32), controller_id: value["controller_id"].as_i64().unwrap_or(0) as i32, }) } pub fn is_online(&self) -> bool { self.status == "online" } pub fn is_failed(&self) -> bool { self.status == "failed" } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Event { pub id: i32, pub controller_id: i32, pub timestamp: i64, pub level: String, pub event_type: String, pub message: String, } impl Event { pub fn from_json(value: &serde_json::Value) -> Option { Some(Self { id: value["id"].as_i64().unwrap_or(0) as i32, controller_id: value["controller_id"].as_i64().unwrap_or(0) as i32, timestamp: value["timestamp"].as_i64().unwrap_or(0), level: value["level"].as_str().unwrap_or("info").to_string(), event_type: value["event_type"].as_str().unwrap_or("").to_string(), message: value["message"].as_str().unwrap_or("").to_string(), }) } pub fn formatted_time(&self) -> String { use chrono::{DateTime, Utc}; let dt = DateTime::from_timestamp(self.timestamp, 0).unwrap_or_else(|| Utc::now()); dt.format("%Y-%m-%d %H:%M:%S").to_string() } }