#![forbid(unsafe_code)] #![deny(clippy::unwrap_used, clippy::panic, clippy::expect_used)] use std::process::exit; use tracing::{error, info}; use tracing_subscriber::{ Layer, filter::LevelFilter, fmt, layer::SubscriberExt, registry::Registry, reload, util::SubscriberInitExt, }; use crate::connector::master::{MasterConnector, MasterConnectorTrait, ssh::SshMasterConnector}; mod cli; mod config; mod connector; #[tokio::main] async fn main() { // install a global subscriber for logging let reload_handle = install_tracing_subscriber(); // Load configuration settings let settings = match config::settings::Settings::load() { Ok(s) => s, Err(e) => { error!("Failed to load configuration: {}", e); std::process::exit(1); } }; reload_handle .modify(|filter| *filter = Box::new(settings.log.level)) .inspect_err(|e| { error!( "Failed to set log level: {}. Continuing with default level.", e ) }) // ignore errors here since we can still run with the default log level .ok(); // print the loaded settings for debugging // info!("Loaded settings: {:#?}", settings); info!("Starting NxMesh Agent..."); // install grpc client #[expect(clippy::expect_used)] let ssh_connector = SshMasterConnector::new(settings.grpc.clone()) .await .inspect_err(|e| { error!("Failed to create SSH Master Connector: {}", e); exit(1); }) .expect("Failed to create SSH Master Connector"); let mut master_connector = MasterConnector::new(Box::new(ssh_connector)); if let Err(e) = master_connector.connect(&settings).await { error!("Failed to connect to master: {}", e); exit(1); } // send a dummy heartbeat to verify the connection is working let client = master_connector.get_client(); let request = nxmesh_proto::HealthReport { ..Default::default() }; match client.lock().await.report_health(request).await { Ok(_) => info!("Successfully sent health report to master."), Err(e) => { error!("Failed to send health report to master: {}", e); exit(1); } } info!("Successfully connected to master. Agent is running."); } fn install_tracing_subscriber() -> reload::Handle + Send + Sync>, Registry> { let filter = LevelFilter::INFO; let (filter_layer, reload_handle) = reload::Layer::new(Box::new(fmt::layer().with_filter(filter)) as Box + Send + Sync>); tracing_subscriber::registry() .with(filter_layer) .with(fmt::Layer::default()) .init(); reload_handle }