Files
mc-proxy-controller/src/state.rs

110 lines
2.7 KiB
Rust

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<u64> {
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<RwLock<ServerState>>,
metrics: Arc<RwLock<StartupMetrics>>,
}
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<u64> {
self.metrics.read().await.average_startup_time()
}
}
impl Default for SharedServerState {
fn default() -> Self {
Self::new()
}
}