/// WatcherAgent - A Rust-based system monitoring agent /// This agent collects hardware metrics and sends them to a backend server. /// It supports CPU, GPU, RAM, disk, and network metrics. pub mod api; pub mod hardware; pub mod metrics; pub mod models; pub mod docker; use std::env; use std::error::Error; use std::marker::Send; use std::marker::Sync; use std::result::Result; use tokio::task::JoinHandle; use bollard::Docker; async fn flatten( handle: JoinHandle>>, ) -> Result> { match handle.await { Ok(Ok(result)) => Ok(result), Ok(Err(err)) => Err(err), Err(_err) => Err("handling failed".into()), } } #[tokio::main] async fn main() -> Result<(), Box> { // Initialize Docker client let docker = Docker::connect_with_local_defaults() .map_err(|e| format!("Failed to connect to Docker: {}", e))?; // Get current image version let client_version = match docker::serverclientcomm::get_client_container(&docker).await { Ok(Some(version)) => version.image, Ok(None) => { eprintln!("Warning: No image version found"); "unknown".to_string() } Err(e) => { eprintln!("Warning: Could not get current image version: {}", e); "unknown".to_string() } }; println!("Client Version: {}", client_version); let args: Vec = env::args().collect(); // args[0] is the binary name, args[1] is the first actual argument if args.len() < 2 { eprintln!("Usage: {} ", args[0]); return Err("Missing server URL argument".into()); } let server_url = &args[1]; println!("Server URL: {:?}", server_url); // Registration let (server_id, ip) = match api::register_with_server(&server_url).await { Ok((id, ip)) => (id, ip), Err(e) => { eprintln!("Fehler bei der Registrierung am Server: {e}"); return Err(e); } }; // Start background tasks // Start server listening for commands let listening_handle = tokio::spawn({ let docker = docker.clone(); let server_url = server_url.to_string(); async move { api::listening_to_server(&docker, &server_url).await } }); // Start heartbeat in background let heartbeat_handle = tokio::spawn({ let ip = ip.clone(); let server_url = server_url.to_string(); async move { api::heartbeat_loop(&server_url, &ip).await } }); // Main metrics loop println!("Starting metrics collection..."); let metrics_handle = tokio::spawn({ let ip = ip.clone(); let server_url = server_url.to_string(); async move { let mut collector = metrics::Collector::new(server_id, ip); collector.run(&server_url).await } }); // Wait for all tasks and check for errors let (listening_result, heartbeat_result, metrics_result) = tokio::try_join!( flatten(listening_handle), flatten(heartbeat_handle), flatten(metrics_handle) )?; println!( "All tasks completed: listening={:?}, heartbeat={:?}, metrics={:?}", listening_result, heartbeat_result, metrics_result ); println!("All tasks completed successfully."); Ok(()) }