bar-rubble 0.5.2

Quickly generate output for viewing in swaybar or similar
Documentation
use crate::RubbleResult;
use clap::Args;
use clap::ValueEnum;
use handlebars::JsonValue;
use serde_json::json;
use std::error::Error;
use std::thread;
use std::time::Duration;
use systemstat::{Platform, System};

#[derive(Args)]
pub struct DeviceArgs {
    pub selector: SystemStats,
}

#[derive(Copy, Clone, ValueEnum)]
pub enum SystemStats {
    /// CPU Stats
    CPU,
    /// Load Avg
    LoadAvg,
    /// Temp
    Temp,
    /// Time Machine last booted
    BootTime,
    /// Battery info
    Battery,
}

impl SystemStats {
    pub fn default_format(&self) -> &'static str {
        match self {
            SystemStats::CPU => "{{total}}%",
            SystemStats::LoadAvg => "{{load_avg_1}}, {{load_avg_5}}, {{load_avg_15}}",
            SystemStats::Temp => "{{temp}}",
            SystemStats::BootTime => "{{boot_time}}",
            SystemStats::Battery => "{{charge}}%",
        }
    }

    pub fn formatting_strings(&self) -> &'static str {
        match self {
            SystemStats::CPU => "total user nice system interrupt",
            SystemStats::LoadAvg => "load_avg_1 load_avg_5 load_avg_15",
            SystemStats::Temp => "temp",
            SystemStats::BootTime => "boot_time",
            SystemStats::Battery => "charge time_remaining",
        }
    }

    pub fn to_result(&self) -> RubbleResult {
        let sys = System::new();
        let r = match self {
            SystemStats::CPU => cpu_stat(sys),
            SystemStats::LoadAvg => load_avg(sys),
            SystemStats::Temp => temp(sys),
            SystemStats::BootTime => boot_time(sys),
            SystemStats::Battery => battery(sys),
        };
        RubbleResult::new(r, self.default_format())
    }
}

fn battery(sys: System) -> Result<JsonValue, Box<dyn Error>> {
    match sys.battery_life() {
        Ok(battery) => Ok(json!({
            "charge": battery.remaining_capacity * 100.0,
            "time_remaining": format!(
              "{}h{}m",
              battery.remaining_time.as_secs() / 3600,
              battery.remaining_time.as_secs() % 60
            )

        })),
        Err(e) => Err(e.into()),
    }
}

fn cpu_stat(sys: System) -> Result<JsonValue, Box<dyn Error>> {
    match sys.cpu_load_aggregate() {
        Ok(cpu) => {
            thread::sleep(Duration::from_secs(1));
            let cpu = cpu.done().unwrap();
            let u = cpu.user * 100.00;
            let n = cpu.nice * 100.00;
            let s = cpu.system * 100.00;
            let i = cpu.interrupt * 100.00;
            let t = u + n + s + i;
            Ok(json!({ "total": t, "user": u, "nice": n, "system": s, "interrupt": i }))
        }
        Err(e) => Err(e.into()),
    }
}

fn load_avg(sys: System) -> Result<JsonValue, Box<dyn Error>> {
    match sys.load_average() {
        Ok(loadavg) => Ok(json!({
          "load_avg_1": loadavg.one,
          "load_avg_5": loadavg.five,
          "load_avg_15": loadavg.fifteen,
        })),
        Err(e) => Err(e.into()),
    }
}

fn temp(sys: System) -> Result<JsonValue, Box<dyn Error>> {
    match sys.cpu_temp() {
        Ok(cpu_temp) => Ok(json!({ "temp": cpu_temp })),
        Err(e) => Err(e.into()),
    }
}

fn boot_time(sys: System) -> Result<JsonValue, Box<dyn Error>> {
    match sys.boot_time() {
        Ok(boot_time) => Ok(json!({ "boot_time": boot_time.to_string() })),
        Err(x) => Err(x.into()),
    }
}