diff --git a/WatcherAgent/src/main.rs b/WatcherAgent/src/main.rs index 16c371d..f4b77a2 100644 --- a/WatcherAgent/src/main.rs +++ b/WatcherAgent/src/main.rs @@ -6,26 +6,7 @@ use std::{error::Error, fs, process::Command, time::Duration}; use sysinfo::{CpuExt, DiskExt, System, SystemExt}; use tokio::time::{interval, sleep}; -// Shared data structures -#[derive(Serialize, Debug)] -struct Metric { - timestamp: String, - server_id: i32, - cpu_load: f32, - cpu_temp: f32, - gpu_load: f32, - gpu_temp: f32, - gpu_vram_size: u32, - gpu_vram_usage: u32, - ram_load: f32, - ram_size: u32, - disk_size: u32, - disk_usage: f32, - disk_temp: f32, - net_in: u64, - net_out: u64, -} - +// Data structures matching the C# DTOs #[derive(Serialize, Debug)] struct RegistrationDto { #[serde(rename = "id")] @@ -42,6 +23,40 @@ struct RegistrationDto { ram_size: f64, } +#[derive(Serialize, Debug)] +struct MetricDto { + #[serde(rename = "serverId")] + server_id: i32, + #[serde(rename = "ipAddress")] + ip_address: String, + #[serde(rename = "cpu_Load")] + cpu_load: f64, + #[serde(rename = "cpu_Temp")] + cpu_temp: f64, + #[serde(rename = "gpu_Load")] + gpu_load: f64, + #[serde(rename = "gpu_Temp")] + gpu_temp: f64, + #[serde(rename = "gpu_Vram_Size")] + gpu_vram_size: f64, + #[serde(rename = "gpu_Vram_Usage")] + gpu_vram_usage: f64, + #[serde(rename = "ram_Load")] + ram_load: f64, + #[serde(rename = "ram_Size")] + ram_size: f64, + #[serde(rename = "disk_Size")] + disk_size: f64, + #[serde(rename = "disk_Usage")] + disk_usage: f64, + #[serde(rename = "disk_Temp")] + disk_temp: f64, + #[serde(rename = "net_In")] + net_in: f64, + #[serde(rename = "net_Out")] + net_out: f64, +} + #[derive(Deserialize)] struct IdResponse { id: i32, @@ -54,7 +69,6 @@ struct HeartbeatPayload { ip_address: String, } -// Hardware info collection struct HardwareInfo { cpu_type: String, cpu_cores: i32, @@ -133,7 +147,6 @@ impl HardwareInfo { } } -// Registration module async fn register_with_server(base_url: &str) -> Result<(i32, String), Box> { let client = Client::builder() .danger_accept_invalid_certs(true) @@ -182,7 +195,6 @@ async fn register_with_server(base_url: &str) -> Result<(i32, String), Box Result<(), Box> { let client = Client::builder() .danger_accept_invalid_certs(true) @@ -206,25 +218,26 @@ async fn heartbeat_loop(base_url: &str, ip: &str) -> Result<(), Box> } } -// Metrics module struct MetricsCollector { sys: System, nvml: Option, server_id: i32, + ip_address: String, } impl MetricsCollector { - fn new(server_id: i32) -> Self { + fn new(server_id: i32, ip_address: String) -> Self { Self { sys: System::new(), nvml: Nvml::init().ok(), server_id, + ip_address, } } async fn collect_and_send_loop(&mut self, base_url: &str) -> Result<(), Box> { let client = Client::new(); - let url = format!("{}/metric/receive", base_url); + let url = format!("{}/monitoring/metric", base_url); let mut interval = interval(Duration::from_secs(30)); loop { @@ -233,9 +246,8 @@ impl MetricsCollector { match client.post(&url).json(&metric).send().await { Ok(res) => println!( - "✅ Sent metrics: {} @ {} | Status: {}", + "✅ Sent metrics for server {} | Status: {}", metric.server_id, - metric.timestamp, res.status() ), Err(err) => eprintln!("❌ Failed to send metrics: {}", err), @@ -243,17 +255,18 @@ impl MetricsCollector { } } - fn collect_metrics(&mut self) -> Metric { + fn collect_metrics(&mut self) -> MetricDto { self.sys.refresh_all(); // CPU - let cpu_load = self.sys.global_cpu_info().cpu_usage(); - let cpu_temp = get_cpu_temp().unwrap_or(0.0); + let cpu_load = self.sys.global_cpu_info().cpu_usage() as f64; + let cpu_temp = get_cpu_temp().unwrap_or(0.0) as f64; // RAM let total_memory = self.sys.total_memory(); let used_memory = self.sys.used_memory(); - let ram_load = (used_memory as f32 / total_memory as f32) * 100.0; + let ram_load = (used_memory as f64 / total_memory as f64) * 100.0; + let ram_size = (total_memory as f64) / 1024.0 / 1024.0; // Disk let disk = self.sys.disks().first(); @@ -261,11 +274,11 @@ impl MetricsCollector { let total = d.total_space(); let available = d.available_space(); ( - total / 1024 / 1024, - (total - available) as f32 / total as f32 * 100.0, + (total as f64) / 1024.0 / 1024.0 / 1024.0, // Convert to GB + (total - available) as f64 / total as f64 * 100.0, ) } else { - (0, 0.0) + (0.0, 0.0) }; // GPU (NVIDIA) @@ -273,46 +286,56 @@ impl MetricsCollector { if let Ok(device) = nvml.device_by_index(0) { let temp = device .temperature(nvml_wrapper::enum_wrappers::device::TemperatureSensor::Gpu) - .unwrap_or(0) as f32; + .unwrap_or(0) as f64; let load = device .utilization_rates() - .map(|u| u.gpu as f32) + .map(|u| u.gpu as f64) .unwrap_or(0.0); let mem = device.memory_info().ok(); - let used = mem.clone().map(|m| m.used / 1024 / 1024).unwrap_or(0); - let total = mem.map(|m| m.total / 1024 / 1024).unwrap_or(0); - (temp, load, used as u32, total as u32) + let used = mem + .clone() + .map(|m| (m.used as f64) / 1024.0 / 1024.0 / 1024.0) + .unwrap_or(0.0); // GB + let total = mem + .map(|m| (m.total as f64) / 1024.0 / 1024.0 / 1024.0) + .unwrap_or(0.0); // GB + (temp, load, used, total) } else { - (0.0, 0.0, 0, 0) + (0.0, 0.0, 0.0, 0.0) } } else { - (0.0, 0.0, 0, 0) + (0.0, 0.0, 0.0, 0.0) }; - // Network + // Network (convert bytes to bits) let (net_in, net_out) = get_network_traffic().unwrap_or((0, 0)); + let net_in_bits = (net_in as f64) * 8.0; + let net_out_bits = (net_out as f64) * 8.0; - Metric { - timestamp: Utc::now().to_rfc3339(), + MetricDto { server_id: self.server_id, + ip_address: self.ip_address.clone(), cpu_load, cpu_temp, gpu_load, gpu_temp, gpu_vram_size: vram_total, - gpu_vram_usage: vram_used, + gpu_vram_usage: if vram_total > 0.0 { + (vram_used / vram_total) * 100.0 + } else { + 0.0 + }, ram_load, - ram_size: (total_memory / 1024) as u32, - disk_size: disk_size as u32, + ram_size, + disk_size, disk_usage: disk_used, - disk_temp: 0.0, - net_in, - net_out, + disk_temp: 0.0, // not supported + net_in: net_in_bits, + net_out: net_out_bits, } } } -// Helper functions fn get_cpu_temp() -> Option { let output = Command::new("sensors").output().ok()?; let stdout = String::from_utf8_lossy(&output.stdout); @@ -349,7 +372,6 @@ fn get_network_traffic() -> Option<(u64, u64)> { Some((rx_total, tx_total)) } -// Main agent #[tokio::main] async fn main() -> Result<(), Box> { let server_base_url = "http://localhost:5258"; @@ -370,12 +392,11 @@ async fn main() -> Result<(), Box> { // Start metrics collection println!("Starting metrics collection..."); - let mut metrics_collector = MetricsCollector::new(server_id); + let mut metrics_collector = MetricsCollector::new(server_id, ip_address); metrics_collector .collect_and_send_loop(server_base_url) .await?; - // This line is theoretically unreachable because both loops are infinite heartbeat_handle.await?; Ok(()) }