i3status_rs/blocks/
load.rs1use super::prelude::*;
33use crate::util;
34
35#[derive(Deserialize, Debug, SmartDefault)]
36#[serde(deny_unknown_fields, default)]
37pub struct Config {
38 pub format: FormatConfig,
39 #[default(3.into())]
40 pub interval: Seconds,
41 #[default(0.3)]
42 pub info: f64,
43 #[default(0.6)]
44 pub warning: f64,
45 #[default(0.9)]
46 pub critical: f64,
47}
48
49pub(crate) fn prepare(config: &Config) -> Result<Arc<BlockPlan>> {
50 BlockPlan::new(vec![
51 OutputPlan::new("main", config.format.with_default(" $icon $1m.eng(w:4) ")?)
52 .icon("icon", IconChoices::one(icons::COGS)),
53 ])
54}
55
56pub(crate) async fn run(config: &Config, api: &CommonApi, plan: &Arc<BlockPlan>) -> Result<()> {
57 let output_main = plan.output("main")?;
58
59 let logical_cores = util::read_file("/proc/cpuinfo")
61 .await
62 .error("Your system doesn't support /proc/cpuinfo")?
63 .lines()
64 .filter(|l| l.starts_with("processor"))
65 .count();
66
67 loop {
68 let loadavg = util::read_file("/proc/loadavg")
69 .await
70 .error("Your system does not support reading the load average from /proc/loadavg")?;
71 let mut values = loadavg.split(' ');
72 let m1: f64 = values
73 .next()
74 .and_then(|x| x.parse().ok())
75 .error("bad /proc/loadavg file")?;
76 let m5: f64 = values
77 .next()
78 .and_then(|x| x.parse().ok())
79 .error("bad /proc/loadavg file")?;
80 let m15: f64 = values
81 .next()
82 .and_then(|x| x.parse().ok())
83 .error("bad /proc/loadavg file")?;
84
85 let mut widget = output_main.new_widget();
86 widget.state = match m1 / logical_cores as f64 {
87 x if x > config.critical => State::Critical,
88 x if x > config.warning => State::Warning,
89 x if x > config.info => State::Info,
90 _ => State::Idle,
91 };
92 widget.set_values(map! {
93 "icon" => Value::icon(icons::COGS),
94 "1m" => Value::number(m1),
95 "5m" => Value::number(m5),
96 "15m" => Value::number(m15),
97 });
98 api.set_widget(widget)?;
99
100 select! {
101 _ = sleep(config.interval.0) => (),
102 _ = api.wait_for_update_request() => (),
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn plan_declares_main_output_with_cogs_icon() {
113 let plan = prepare(&Config::default()).unwrap();
114 let declared: Vec<_> = plan.outputs().map(|o| o.id()).collect();
115 assert_eq!(declared, ["main"]);
116 let output = plan.output("main").unwrap();
117 assert_eq!(output.single_icon("icon").unwrap(), "cogs");
118 }
119
120 #[test]
121 fn custom_format_is_respected() {
122 let config = Config {
123 format: " $5m ".parse().unwrap(),
124 ..Config::default()
125 };
126 let plan = prepare(&config).unwrap();
127 let output = plan.output("main").unwrap();
128 assert!(output.format().contains_key("5m"));
129 assert!(!output.format().contains_key("icon"));
130 }
131}