unifier-cli 0.3.0

Filesystem postbox for inter-process communication via a Unix tree
Documentation
//! Idle auto-flush: persist dirty daemon state when the machine is quiet.

use std::time::{Duration, Instant};

/// Seconds of daemon inactivity before an idle flush is considered.
/// Set `UNIFIER_IDLE_FLUSH_SECS=0` to disable.
pub fn idle_after() -> Duration {
    let secs = std::env::var("UNIFIER_IDLE_FLUSH_SECS")
        .ok()
        .and_then(|s| s.parse::<u64>().ok())
        .unwrap_or(5);
    Duration::from_secs(secs)
}

/// 1-minute load-average ceiling for "no other load".
/// Override with `UNIFIER_IDLE_MAX_LOAD` (default 0.2).
pub fn max_load() -> f64 {
    std::env::var("UNIFIER_IDLE_MAX_LOAD")
        .ok()
        .and_then(|s| s.parse::<f64>().ok())
        .unwrap_or(0.2)
}

pub fn loadavg_1min() -> Option<f64> {
    let text = std::fs::read_to_string("/proc/loadavg").ok()?;
    text.split_whitespace().next()?.parse().ok()
}

pub fn system_is_idle(max: f64) -> bool {
    match loadavg_1min() {
        Some(load) => load <= max,
        None => true,
    }
}

pub fn should_idle_flush(
    last_activity: Instant,
    now: Instant,
    idle_after: Duration,
    load_ok: bool,
    dirty: bool,
    tick_active: bool,
) -> bool {
    if idle_after.is_zero() || !dirty || tick_active || !load_ok {
        return false;
    }
    now.duration_since(last_activity) >= idle_after
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Duration;

    #[test]
    fn waits_for_idle_window() {
        let t0 = Instant::now();
        let t1 = t0 + Duration::from_secs(2);
        assert!(!should_idle_flush(
            t0,
            t1,
            Duration::from_secs(5),
            true,
            true,
            false
        ));
        let t2 = t0 + Duration::from_secs(5);
        assert!(should_idle_flush(
            t0,
            t2,
            Duration::from_secs(5),
            true,
            true,
            false
        ));
    }

    #[test]
    fn parse_loadavg_when_present() {
        if let Some(load) = loadavg_1min() {
            assert!(load >= 0.0);
        }
    }

    #[test]
    fn skips_when_system_busy_or_tick_active_or_clean() {
        let t0 = Instant::now();
        let now = t0 + Duration::from_secs(10);
        let idle = Duration::from_secs(5);
        assert!(!should_idle_flush(t0, now, idle, false, true, false));
        assert!(!should_idle_flush(t0, now, idle, true, true, true));
        assert!(!should_idle_flush(t0, now, idle, true, false, false));
        assert!(!should_idle_flush(
            t0,
            now,
            Duration::ZERO,
            true,
            true,
            false
        ));
    }
}