use serde::Serialize;
use crate::config::Config;
#[derive(Debug, Clone, Serialize)]
pub struct OverlayStatus {
pub enabled: bool,
pub kind: String,
pub iface: Option<String>,
pub present: bool,
pub operstate: Option<String>,
pub up: bool,
pub note: String,
}
fn is_up(present: bool, operstate: Option<&str>) -> bool {
present && matches!(operstate, None | Some("up") | Some("unknown"))
}
pub fn status(cfg: &Config) -> OverlayStatus {
if !cfg.overlay_enabled {
return OverlayStatus {
enabled: false,
kind: cfg.overlay_kind.clone(),
iface: cfg.overlay_iface.clone(),
present: false,
operstate: None,
up: false,
note: "Remote-access overlay disabled (HELDAR_OVERLAY_ENABLED=false); reachable on the LAN only."
.into(),
};
}
let Some(iface) = cfg.overlay_iface.clone() else {
return OverlayStatus {
enabled: true,
kind: cfg.overlay_kind.clone(),
iface: None,
present: false,
operstate: None,
up: false,
note: "Overlay enabled but HELDAR_OVERLAY_IFACE is unset; cannot determine status."
.into(),
};
};
let base = std::path::Path::new("/sys/class/net").join(&iface);
let present = base.exists();
let operstate = std::fs::read_to_string(base.join("operstate"))
.ok()
.map(|s| s.trim().to_string());
let up = is_up(present, operstate.as_deref());
let note = if !present {
format!(
"Overlay interface '{iface}' not found — is the {} daemon running and connected?",
cfg.overlay_kind
)
} else if up {
format!(
"Overlay '{}' up on '{iface}'; deployment reachable to authorized peers (P2P-first, end-to-end encrypted).",
cfg.overlay_kind
)
} else {
format!(
"Overlay interface '{iface}' present but not up (operstate={}).",
operstate.as_deref().unwrap_or("?")
)
};
OverlayStatus {
enabled: true,
kind: cfg.overlay_kind.clone(),
iface: Some(iface),
present,
operstate,
up,
note,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tun_unknown_counts_as_up() {
assert!(is_up(true, Some("unknown")));
assert!(is_up(true, Some("up")));
assert!(is_up(true, None));
}
#[test]
fn down_or_absent_is_not_up() {
assert!(!is_up(true, Some("down")));
assert!(!is_up(false, Some("up")));
assert!(!is_up(false, None));
}
}