ados_protocol/
plugin_loopback_guard.rs1use std::path::{Path, PathBuf};
11
12use serde::{Deserialize, Serialize};
13
14pub const SIDECAR_NAME: &str = "plugin-loopback-guard.json";
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct GuardState {
20 pub active: bool,
22 #[serde(default)]
24 pub reason: String,
25}
26
27impl GuardState {
28 pub fn unavailable(reason: impl Into<String>) -> Self {
30 Self {
31 active: false,
32 reason: reason.into(),
33 }
34 }
35
36 pub fn label(&self) -> &'static str {
38 if self.active {
39 "active"
40 } else {
41 "unavailable"
42 }
43 }
44}
45
46pub fn sidecar_path() -> PathBuf {
48 let run = std::env::var("ADOS_RUN_DIR").unwrap_or_else(|_| "/run/ados".to_string());
49 Path::new(&run).join(SIDECAR_NAME)
50}
51
52pub fn read_state_at(path: &Path) -> GuardState {
54 std::fs::read_to_string(path)
55 .ok()
56 .and_then(|t| serde_json::from_str(&t).ok())
57 .unwrap_or_else(|| GuardState::unavailable("the plugin host has not loaded the guard"))
58}
59
60pub fn read_state() -> GuardState {
62 read_state_at(&sidecar_path())
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn an_absent_or_garbled_sidecar_reads_unavailable() {
71 let dir = tempfile::tempdir().unwrap();
72 let path = dir.path().join(SIDECAR_NAME);
73 assert_eq!(read_state_at(&path).label(), "unavailable");
74 std::fs::write(&path, "not json").unwrap();
75 assert_eq!(read_state_at(&path).label(), "unavailable");
76 std::fs::write(&path, r#"{"active":true}"#).unwrap();
77 assert_eq!(read_state_at(&path).label(), "active");
78 }
79}