use anyhow::Result; use serde::{Deserialize, Serialize}; use std::path::Path; /// Main dashboard configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DashboardConfig { pub zmq: ZmqConfig, pub ui: UiConfig, pub hosts: HostsConfig, pub metrics: MetricsConfig, pub widgets: WidgetsConfig, } /// ZMQ consumer configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ZmqConfig { pub subscriber_ports: Vec, pub connection_timeout_ms: u64, pub reconnect_interval_ms: u64, } /// UI configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UiConfig { pub refresh_rate_ms: u64, pub theme: String, pub preserve_layout: bool, } /// Hosts configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HostsConfig { pub auto_discovery: bool, pub predefined_hosts: Vec, pub default_host: Option, } /// Metrics configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MetricsConfig { pub history_retention_hours: u64, pub max_metrics_per_host: usize, } /// Widget configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WidgetsConfig { pub cpu: WidgetConfig, pub memory: WidgetConfig, pub storage: WidgetConfig, pub services: WidgetConfig, pub backup: WidgetConfig, } /// Individual widget configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WidgetConfig { pub enabled: bool, pub metrics: Vec, } impl DashboardConfig { pub fn load_from_file>(path: P) -> Result { let path = path.as_ref(); let content = std::fs::read_to_string(path)?; let config: DashboardConfig = toml::from_str(&content)?; Ok(config) } } impl Default for DashboardConfig { fn default() -> Self { Self { zmq: ZmqConfig::default(), ui: UiConfig::default(), hosts: HostsConfig::default(), metrics: MetricsConfig::default(), widgets: WidgetsConfig::default(), } } } impl Default for ZmqConfig { fn default() -> Self { Self { subscriber_ports: vec![6130], connection_timeout_ms: 15000, reconnect_interval_ms: 5000, } } } impl Default for UiConfig { fn default() -> Self { Self { refresh_rate_ms: 100, theme: "default".to_string(), preserve_layout: true, } } } impl Default for HostsConfig { fn default() -> Self { Self { auto_discovery: true, predefined_hosts: vec![ "cmbox".to_string(), "labbox".to_string(), "simonbox".to_string(), "steambox".to_string(), "srv01".to_string(), ], default_host: Some("cmbox".to_string()), } } } impl Default for MetricsConfig { fn default() -> Self { Self { history_retention_hours: 24, max_metrics_per_host: 10000, } } } impl Default for WidgetsConfig { fn default() -> Self { Self { cpu: WidgetConfig { enabled: true, metrics: vec![ "cpu_load_1min".to_string(), "cpu_load_5min".to_string(), "cpu_load_15min".to_string(), "cpu_temperature_celsius".to_string(), ], }, memory: WidgetConfig { enabled: true, metrics: vec![ "memory_usage_percent".to_string(), "memory_total_gb".to_string(), "memory_available_gb".to_string(), ], }, storage: WidgetConfig { enabled: true, metrics: vec![ "disk_nvme0_temperature_celsius".to_string(), "disk_nvme0_wear_percent".to_string(), "disk_nvme0_usage_percent".to_string(), ], }, services: WidgetConfig { enabled: true, metrics: vec![ "service_ssh_status".to_string(), "service_ssh_memory_mb".to_string(), ], }, backup: WidgetConfig { enabled: true, metrics: vec![ "backup_status".to_string(), "backup_last_run_timestamp".to_string(), ], }, } } }