use std::sync::{Arc, Mutex};
use std::time::Instant;
#[derive(Clone, Copy, PartialEq)]
pub enum ConnectionStatus {
Unknown,
Disconnected,
Connecting,
Connected,
Evicted,
NotMcp,
}
impl ConnectionStatus {
pub fn label(&self) -> &'static str {
match self {
Self::Unknown => "Unknown",
Self::Disconnected => "Disconnected",
Self::Connecting => "Connecting…",
Self::Connected => "Connected",
Self::Evicted => "Evicted",
Self::NotMcp => "Not MCP",
}
}
}
pub enum CloudSyncStatus {
Ok { count: usize },
Failed { message: String },
}
pub struct ProxyHealth {
pub proxy_url: String,
pub tunnel_url: String,
pub mcp_upstream: String,
pub mcp_status: ConnectionStatus,
pub mcp_warning: Option<String>,
pub tunnel_status: ConnectionStatus,
pub cloud_endpoint: Option<String>,
pub cloud_sync: Option<CloudSyncStatus>,
pub started_at: Instant,
pub request_count: u64,
}
impl ProxyHealth {
pub fn new() -> Self {
Self {
proxy_url: String::new(),
tunnel_url: String::new(),
mcp_upstream: String::new(),
mcp_status: ConnectionStatus::Unknown,
mcp_warning: None,
tunnel_status: ConnectionStatus::Disconnected,
cloud_endpoint: None,
cloud_sync: None,
started_at: Instant::now(),
request_count: 0,
}
}
pub fn confirm_mcp_connected(&mut self) {
self.mcp_status = ConnectionStatus::Connected;
self.mcp_warning = None;
}
pub fn record_request(&mut self) {
self.request_count += 1;
}
pub fn uptime(&self) -> String {
let secs = self.started_at.elapsed().as_secs();
if secs < 60 {
format!("{secs}s")
} else if secs < 3600 {
format!("{}m {}s", secs / 60, secs % 60)
} else {
format!("{}h {}m", secs / 3600, (secs % 3600) / 60)
}
}
}
impl Default for ProxyHealth {
fn default() -> Self {
Self::new()
}
}
pub type SharedProxyHealth = Arc<Mutex<ProxyHealth>>;
pub fn new_shared_health() -> SharedProxyHealth {
Arc::new(Mutex::new(ProxyHealth::new()))
}
pub fn lock_health(health: &SharedProxyHealth) -> std::sync::MutexGuard<'_, ProxyHealth> {
health.lock().unwrap_or_else(|e| e.into_inner())
}