infrarust_server_manager 1.6.3

A Minecraft server manager that handles API monitoring and system commands
Documentation
use crate::api::{ApiProvider, ApiServerStatus};
use crate::error::ServerManagerError;
use std::time::{Duration, Instant};

#[derive(Debug, Clone, PartialEq)]
pub enum ServerState {
    Starting,
    Running,
    Stopping,
    Stopped,
    Crashed,
    Unknown,
}

impl From<&str> for ServerState {
    fn from(state: &str) -> Self {
        match state.to_lowercase().as_str() {
            "starting" => ServerState::Starting,
            "running" => ServerState::Running,
            "stopping" => ServerState::Stopping,
            "stopped" => ServerState::Stopped,
            "offline" => ServerState::Stopped,
            "crashed" => ServerState::Crashed,
            _ => ServerState::Unknown,
        }
    }
}

#[derive(Debug, Clone)]
pub struct ServerStatus {
    pub server_id: String,
    pub state: ServerState,
    pub last_checked: Instant,
    pub uptime: Option<Duration>,
    pub last_crash_time: Option<Instant>,
    pub crash_count: u32,
}

impl ServerStatus {
    pub fn new(server_id: &str) -> Self {
        ServerStatus {
            server_id: server_id.to_string(),
            state: ServerState::Unknown,
            last_checked: Instant::now(),
            uptime: None,
            last_crash_time: None,
            crash_count: 0,
        }
    }

    pub fn update_state(&mut self, new_state: ServerState) {
        if new_state == ServerState::Crashed && self.state != ServerState::Crashed {
            self.last_crash_time = Some(Instant::now());
            self.crash_count += 1;
        }

        if self.state != ServerState::Running && new_state == ServerState::Running {
            self.uptime = Some(Duration::from_secs(0));
        } else if self.state == ServerState::Running
            && new_state == ServerState::Running
            && let Some(current_uptime) = self.uptime
        {
            let elapsed = self.last_checked.elapsed();
            self.uptime = Some(current_uptime + elapsed);
        }

        self.state = new_state;
        self.last_checked = Instant::now();
    }

    pub fn is_crashed(&self) -> bool {
        self.state == ServerState::Crashed
    }

    pub fn is_running(&self) -> bool {
        self.state == ServerState::Running
    }
}

impl From<ApiServerStatus> for ServerStatus {
    fn from(api_status: ApiServerStatus) -> Self {
        let mut status = ServerStatus::new(&api_status.id);
        status.update_state(api_status.status);
        status
    }
}

pub async fn check_status<T: ApiProvider>(
    api: &T,
    server_id: &str,
) -> Result<ServerStatus, ServerManagerError> {
    let api_status = api.get_server_status(server_id).await?;

    let mut status = ServerStatus::from(api_status);
    status.server_id = server_id.to_string();

    Ok(status)
}