1use crate::RubbleResult;
2use clap::Args;
3use clap::ValueEnum;
4use handlebars::JsonValue;
5use serde_json::json;
6use std::error::Error;
7use std::thread;
8use std::time::Duration;
9use systemstat::{Platform, System};
10
11#[derive(Args)]
12pub struct DeviceArgs {
13 pub selector: SystemStats,
14}
15
16#[derive(Copy, Clone, ValueEnum)]
17pub enum SystemStats {
18 CPU,
20 LoadAvg,
22 Temp,
24 BootTime,
26 Battery,
28}
29
30impl SystemStats {
31 pub fn default_format(&self) -> &'static str {
32 match self {
33 SystemStats::CPU => "{{total}}%",
34 SystemStats::LoadAvg => "{{load_avg_1}}, {{load_avg_5}}, {{load_avg_15}}",
35 SystemStats::Temp => "{{temp}}",
36 SystemStats::BootTime => "{{boot_time}}",
37 SystemStats::Battery => "{{charge}}%",
38 }
39 }
40
41 pub fn formatting_strings(&self) -> &'static str {
42 match self {
43 SystemStats::CPU => "total user nice system interrupt",
44 SystemStats::LoadAvg => "load_avg_1 load_avg_5 load_avg_15",
45 SystemStats::Temp => "temp",
46 SystemStats::BootTime => "boot_time",
47 SystemStats::Battery => "charge time_remaining",
48 }
49 }
50
51 pub fn to_result(&self) -> RubbleResult {
52 let sys = System::new();
53 let r = match self {
54 SystemStats::CPU => cpu_stat(sys),
55 SystemStats::LoadAvg => load_avg(sys),
56 SystemStats::Temp => temp(sys),
57 SystemStats::BootTime => boot_time(sys),
58 SystemStats::Battery => battery(sys),
59 };
60 RubbleResult::new(r, self.default_format())
61 }
62}
63
64fn battery(sys: System) -> Result<JsonValue, Box<dyn Error>> {
65 match sys.battery_life() {
66 Ok(battery) => Ok(json!({
67 "charge": battery.remaining_capacity * 100.0,
68 "time_remaining": format!(
69 "{}h{}m",
70 battery.remaining_time.as_secs() / 3600,
71 battery.remaining_time.as_secs() % 60
72 )
73
74 })),
75 Err(e) => Err(e.into()),
76 }
77}
78
79fn cpu_stat(sys: System) -> Result<JsonValue, Box<dyn Error>> {
80 match sys.cpu_load_aggregate() {
81 Ok(cpu) => {
82 thread::sleep(Duration::from_secs(1));
83 let cpu = cpu.done().unwrap();
84 let u = cpu.user * 100.00;
85 let n = cpu.nice * 100.00;
86 let s = cpu.system * 100.00;
87 let i = cpu.interrupt * 100.00;
88 let t = u + n + s + i;
89 Ok(json!({ "total": t, "user": u, "nice": n, "system": s, "interrupt": i }))
90 }
91 Err(e) => Err(e.into()),
92 }
93}
94
95fn load_avg(sys: System) -> Result<JsonValue, Box<dyn Error>> {
96 match sys.load_average() {
97 Ok(loadavg) => Ok(json!({
98 "load_avg_1": loadavg.one,
99 "load_avg_5": loadavg.five,
100 "load_avg_15": loadavg.fifteen,
101 })),
102 Err(e) => Err(e.into()),
103 }
104}
105
106fn temp(sys: System) -> Result<JsonValue, Box<dyn Error>> {
107 match sys.cpu_temp() {
108 Ok(cpu_temp) => Ok(json!({ "temp": cpu_temp })),
109 Err(e) => Err(e.into()),
110 }
111}
112
113fn boot_time(sys: System) -> Result<JsonValue, Box<dyn Error>> {
114 match sys.boot_time() {
115 Ok(boot_time) => Ok(json!({ "boot_time": boot_time.to_string() })),
116 Err(x) => Err(x.into()),
117 }
118}