use std::sync::Arc; use tokio::sync::RwLock; use tokio::time::Instant; #[derive(Debug, Clone, Default)] pub struct StartupMetrics { pub total_startups: u32, pub total_duration_secs: u64, } impl StartupMetrics { pub fn record_startup(&mut self, duration_secs: u64) { self.total_startups += 1; self.total_duration_secs += duration_secs; } pub fn average_startup_time(&self) -> Option { if self.total_startups == 0 { None } else { Some(self.total_duration_secs / self.total_startups as u64) } } } #[derive(Debug, Clone, PartialEq)] pub enum ServerState { Unknown, Stopped, Starting { started_at: Instant, }, Running { rcon_connected_at: Instant, }, Stopping { stop_requested_at: Instant, }, } #[derive(Clone)] pub struct SharedServerState { state: Arc>, metrics: Arc>, } impl SharedServerState { pub fn new() -> Self { Self { state: Arc::new(RwLock::new(ServerState::Unknown)), metrics: Arc::new(RwLock::new(StartupMetrics::default())), } } pub async fn get(&self) -> ServerState { self.state.read().await.clone() } pub async fn set(&self, new_state: ServerState) { let mut state = self.state.write().await; let old_state = state.clone(); *state = new_state.clone(); if old_state != new_state { println!("State transition: {:?} -> {:?}", old_state, new_state); } } pub async fn transition_to_starting(&self) { self.set(ServerState::Starting { started_at: Instant::now(), }).await; } pub async fn transition_to_running(&self) { self.set(ServerState::Running { rcon_connected_at: Instant::now(), }).await; } pub async fn transition_to_stopping(&self) { self.set(ServerState::Stopping { stop_requested_at: Instant::now(), }).await; } pub async fn transition_to_stopped(&self) { self.set(ServerState::Stopped).await; } pub async fn record_startup_duration(&self, duration_secs: u64) { let mut metrics = self.metrics.write().await; metrics.record_startup(duration_secs); println!("Server startup took {}s (avg: {}s over {} startups)", duration_secs, metrics.average_startup_time().unwrap_or(0), metrics.total_startups); } pub async fn get_average_startup_time(&self) -> Option { self.metrics.read().await.average_startup_time() } } impl Default for SharedServerState { fn default() -> Self { Self::new() } }