use crate::error::{Error, Result};
use crate::server::{ServerId, ServerStatus};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::Instant;
use tracing;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ServerLifecycleEvent {
Started,
Stopped,
Failed,
Restarted,
}
#[derive(Debug, Clone)]
pub struct ServerEvent {
pub id: ServerId,
pub name: String,
pub event: ServerLifecycleEvent,
pub timestamp: Instant,
pub details: Option<String>,
}
pub struct ServerLifecycleManager {
events: Arc<Mutex<Vec<ServerEvent>>>,
statuses: Arc<Mutex<HashMap<ServerId, ServerStatus>>>,
}
impl ServerLifecycleManager {
pub fn new() -> Self {
Self {
events: Arc::new(Mutex::new(Vec::new())),
statuses: Arc::new(Mutex::new(HashMap::new())),
}
}
#[tracing::instrument(skip(self), fields(server_id = %id, server_name = %name, event_type = ?event))]
pub fn record_event(
&self,
id: ServerId,
name: String,
event: ServerLifecycleEvent,
details: Option<String>,
) -> Result<()> {
tracing::info!(details = ?details, "Recording server lifecycle event");
let server_event = ServerEvent {
id,
name,
event,
timestamp: Instant::now(),
details,
};
{
let mut statuses = self.statuses.lock().map_err(|_| {
tracing::error!("Failed to lock server statuses");
Error::Other("Failed to lock server statuses".to_string())
})?;
let status = match event {
ServerLifecycleEvent::Started => ServerStatus::Running,
ServerLifecycleEvent::Stopped => ServerStatus::Stopped,
ServerLifecycleEvent::Failed => ServerStatus::Failed,
ServerLifecycleEvent::Restarted => ServerStatus::Running,
};
tracing::debug!(new_status = ?status, "Updating server status");
statuses.insert(id, status);
}
{
let mut events = self.events.lock().map_err(|_| {
tracing::error!("Failed to lock server events");
Error::Other("Failed to lock server events".to_string())
})?;
events.push(server_event);
tracing::debug!(total_events = events.len(), "Added event to history");
if events.len() > 1000 {
tracing::trace!("Trimming event history (exceeded 1000 events)");
events.remove(0);
}
}
tracing::info!("Successfully recorded server event");
Ok(())
}
pub fn get_status(&self, id: ServerId) -> Result<ServerStatus> {
let statuses = self
.statuses
.lock()
.map_err(|_| Error::Other("Failed to lock server statuses".to_string()))?;
statuses
.get(&id)
.copied()
.ok_or_else(|| Error::ServerNotFound(format!("{:?}", id)))
}
pub fn get_server_events(
&self,
id: ServerId,
limit: Option<usize>,
) -> Result<Vec<ServerEvent>> {
let events = self
.events
.lock()
.map_err(|_| Error::Other("Failed to lock server events".to_string()))?;
let mut server_events: Vec<ServerEvent> =
events.iter().filter(|e| e.id == id).cloned().collect();
server_events.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
if let Some(limit) = limit {
server_events.truncate(limit);
}
Ok(server_events)
}
pub fn get_all_events(&self, limit: Option<usize>) -> Result<Vec<ServerEvent>> {
let events = self
.events
.lock()
.map_err(|_| Error::Other("Failed to lock server events".to_string()))?;
let mut all_events = events.clone();
all_events.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
if let Some(limit) = limit {
all_events.truncate(limit);
}
Ok(all_events)
}
pub fn clear_events(&self) -> Result<()> {
let mut events = self
.events
.lock()
.map_err(|_| Error::Other("Failed to lock server events".to_string()))?;
events.clear();
Ok(())
}
}
impl Default for ServerLifecycleManager {
fn default() -> Self {
Self::new()
}
}