use std::time::Instant;
use crate::adapter::net::compute::DaemonControl;
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum MeshOsControl {
Shutdown {
deadline: Instant,
},
DrainStart {
deadline: Instant,
},
DrainFinish,
BackpressureOn {
level: f32,
},
BackpressureOff,
}
pub trait ControlSink: Send + Sync + 'static {
fn emit(&self, event: MeshOsControl);
}
impl MeshOsControl {
pub fn to_daemon_control(&self, now: Instant) -> DaemonControl {
match self {
MeshOsControl::Shutdown { deadline } => DaemonControl::Shutdown {
grace_period_ms: deadline.saturating_duration_since(now).as_millis() as u64,
},
MeshOsControl::DrainStart { deadline } => DaemonControl::DrainStart {
grace_period_ms: deadline.saturating_duration_since(now).as_millis() as u64,
},
MeshOsControl::DrainFinish => DaemonControl::DrainFinish,
MeshOsControl::BackpressureOn { level } => {
DaemonControl::BackpressureOn { level: *level }
}
MeshOsControl::BackpressureOff => DaemonControl::BackpressureOff,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn enum_variants_are_constructible_with_runtime_values() {
let now = Instant::now();
let _ = MeshOsControl::Shutdown {
deadline: now + Duration::from_secs(5),
};
let _ = MeshOsControl::DrainStart {
deadline: now + Duration::from_secs(30),
};
let _ = MeshOsControl::DrainFinish;
let _ = MeshOsControl::BackpressureOn { level: 0.5 };
let _ = MeshOsControl::BackpressureOff;
}
#[test]
fn to_daemon_control_converts_instant_deadlines_to_relative_ms() {
let now = Instant::now();
let ev = MeshOsControl::Shutdown {
deadline: now + Duration::from_millis(2500),
};
match ev.to_daemon_control(now) {
DaemonControl::Shutdown { grace_period_ms } => {
assert!((2400..=2500).contains(&grace_period_ms));
}
other => panic!("expected Shutdown, got {other:?}"),
}
}
#[test]
fn to_daemon_control_clamps_past_deadlines_to_zero() {
let now = Instant::now();
let ev = MeshOsControl::DrainStart {
deadline: now - Duration::from_secs(1),
};
match ev.to_daemon_control(now) {
DaemonControl::DrainStart { grace_period_ms } => {
assert_eq!(grace_period_ms, 0);
}
other => panic!("expected DrainStart, got {other:?}"),
}
}
#[test]
fn to_daemon_control_passes_backpressure_level_through_unchanged() {
let now = Instant::now();
let ev = MeshOsControl::BackpressureOn { level: 0.75 };
match ev.to_daemon_control(now) {
DaemonControl::BackpressureOn { level } => {
assert!((level - 0.75).abs() < 1e-6);
}
other => panic!("expected BackpressureOn, got {other:?}"),
}
}
#[test]
fn to_daemon_control_passes_drain_finish_and_backpressure_off_through() {
let now = Instant::now();
assert!(matches!(
MeshOsControl::DrainFinish.to_daemon_control(now),
DaemonControl::DrainFinish
));
assert!(matches!(
MeshOsControl::BackpressureOff.to_daemon_control(now),
DaemonControl::BackpressureOff
));
}
}