gunnar_server/
stop_record.rs1pub const RECORD: &str = "/boot/gunnar-last-stop.txt";
11
12pub const SAID: &str = "the previous stop (kept on the ESP):";
14
15pub fn render(power_off_epoch_ms: u128, line: &str) -> String {
17 format!(
18 "power_off_epoch_ms={power_off_epoch_ms} {}\n",
19 line.replace('\n', " ")
20 )
21}
22
23pub fn power_off_epoch_ms(text: &str) -> Option<u128> {
25 text.split("power_off_epoch_ms=")
26 .nth(1)?
27 .split_whitespace()
28 .next()?
29 .parse()
30 .ok()
31}
32
33pub fn keep(line: &str) -> bool {
35 let now = std::time::SystemTime::now()
36 .duration_since(std::time::UNIX_EPOCH)
37 .map(|d| d.as_millis())
38 .unwrap_or(0);
39 crate::narrate::write_esp_file(std::path::Path::new(RECORD), render(now, line).as_bytes())
40}
41
42pub fn say_previous() {
44 let path = std::path::Path::new(RECORD);
45 if let Ok(text) = std::fs::read_to_string(path) {
46 tracing::info!("{SAID} {}", text.trim());
47 crate::narrate::remove_esp_file(path);
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
57 fn a_stop_record_is_one_line_whose_power_off_time_reads_back() {
58 let r = render(1_790_850_910_705, "front: stopped cleanly on ACPI power button — power-off: sync(2) done in 3 ms; 2 writer(s) released;\n/data remounted read-only in 41 ms");
59 assert_eq!(r.matches('\n').count(), 1, "{r}");
60 assert!(
61 r.starts_with("power_off_epoch_ms=1790850910705 front: stopped cleanly"),
62 "{r}"
63 );
64 assert_eq!(power_off_epoch_ms(&r), Some(1_790_850_910_705));
65 assert_eq!(
66 power_off_epoch_ms(&format!("INFO {SAID} {r}")),
67 Some(1_790_850_910_705),
68 "read back out of the next boot's line too"
69 );
70 }
71}