use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub struct HealthMonitor {
last_activity: Arc<AtomicU64>,
is_healthy: Arc<AtomicBool>,
monitoring: Arc<AtomicBool>,
}
impl HealthMonitor {
pub fn new() -> Self {
Self {
last_activity: Arc::new(AtomicU64::new(Self::now_as_secs())),
is_healthy: Arc::new(AtomicBool::new(true)),
monitoring: Arc::new(AtomicBool::new(false)),
}
}
pub fn start_monitoring(&self, timeout_secs: u64) -> thread::JoinHandle<()> {
let last_activity = Arc::clone(&self.last_activity);
let is_healthy = Arc::clone(&self.is_healthy);
let monitoring = Arc::clone(&self.monitoring);
monitoring.store(true, Ordering::SeqCst);
thread::spawn(move || {
while monitoring.load(Ordering::SeqCst) {
let last = last_activity.load(Ordering::SeqCst);
let now = Self::now_as_secs();
if now - last > timeout_secs {
is_healthy.store(false, Ordering::SeqCst);
} else {
is_healthy.store(true, Ordering::SeqCst);
}
thread::sleep(Duration::from_secs(1));
}
})
}
pub fn update_activity(&self) {
self.last_activity
.store(Self::now_as_secs(), Ordering::SeqCst);
}
pub fn is_healthy(&self) -> bool {
self.is_healthy.load(Ordering::SeqCst)
}
pub fn stop_monitoring(&self) {
self.monitoring.store(false, Ordering::SeqCst);
}
fn now_as_secs() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or(Duration::ZERO)
.as_secs()
}
}
#[allow(dead_code)]
pub enum RecoveryStrategy {
RefreshTerminal,
ResetBuffers,
#[allow(dead_code)]
RestartProcess,
}
pub fn attempt_recovery(strategy: RecoveryStrategy, master_fd: i32) -> Result<(), String> {
match strategy {
RecoveryStrategy::RefreshTerminal => {
unsafe {
let refresh = b"\x0c";
if libc::write(
master_fd,
refresh.as_ptr() as *const libc::c_void,
refresh.len(),
) < 0
{
return Err("Failed to send refresh".to_string());
}
}
Ok(())
}
RecoveryStrategy::ResetBuffers => {
unsafe {
let _ = libc::tcflush(master_fd, libc::TCIOFLUSH);
}
Ok(())
}
RecoveryStrategy::RestartProcess => {
Err("Process restart not implemented".to_string())
}
}
}