Skip to content

Commit 79c9178

Browse files
authored
Merge pull request #874 from JakeStanger/feat/sysinfo-ironvar
feat(sysinfo): expose values as ironvars
2 parents 934b458 + b83f26c commit 79c9178

File tree

13 files changed

+410
-152
lines changed

13 files changed

+410
-152
lines changed

docs/Ironvars.md

+16-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,19 @@ Any UTF-8 string is a valid value.
66

77
Reference values using `#my_variable`. These update as soon as the value changes.
88

9-
You can set defaults using the `ironvar_defaults` key in your top-level config.
9+
You can set defaults using the `ironvar_defaults` key in your top-level config.
10+
11+
Some modules (such as `sys_info`) expose their values over the Ironvar interface,
12+
allowing you to build custom interfaces and integrate into scripts.
13+
These present their values inside read-only namespaces.
14+
15+
Some examples below:
16+
17+
```shell
18+
ironbar var list
19+
ironbar var list sysinfo
20+
ironbar var list sysinfo.disk_percent
21+
ironbar var get sysinfo.disk_percent./home
22+
ironbar var get sysinfo.disk_percent.mean
23+
ironbar var get sysinfo.memory_percent
24+
```

src/clients/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::await_sync;
1+
use crate::{await_sync, Ironbar};
22
use color_eyre::Result;
33
use std::collections::HashMap;
44
use std::path::Path;
@@ -192,7 +192,11 @@ impl Clients {
192192
#[cfg(feature = "sys_info")]
193193
pub fn sys_info(&mut self) -> Arc<sysinfo::Client> {
194194
self.sys_info
195-
.get_or_insert_with(|| Arc::new(sysinfo::Client::new()))
195+
.get_or_insert_with(|| {
196+
let client = Arc::new(sysinfo::Client::new());
197+
Ironbar::variable_manager().register_namespace("sysinfo", client.clone());
198+
client
199+
})
196200
.clone()
197201
}
198202

src/clients/sysinfo.rs

+228-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
use crate::ironvar::Namespace;
12
use crate::modules::sysinfo::Interval;
23
use crate::{lock, register_client};
4+
use color_eyre::{Report, Result};
35
use std::cmp::Ordering;
46
use std::collections::HashMap;
57
use std::fmt::Debug;
6-
use std::sync::Mutex;
8+
use std::str::FromStr;
9+
use std::sync::{Arc, Mutex};
710
use sysinfo::{Components, Disks, LoadAvg, Networks, RefreshKind, System};
811

912
#[repr(u64)]
@@ -43,6 +46,21 @@ pub enum Function {
4346
Name(String),
4447
}
4548

49+
impl FromStr for Function {
50+
type Err = ();
51+
52+
fn from_str(s: &str) -> Result<Self, Self::Err> {
53+
match s.to_lowercase().as_str() {
54+
"sum" => Ok(Self::Sum),
55+
"min" => Ok(Self::Min),
56+
"max" => Ok(Self::Max),
57+
"mean" => Ok(Self::Mean),
58+
"" => Err(()),
59+
_ => Ok(Self::Name(s.to_string())),
60+
}
61+
}
62+
}
63+
4664
#[derive(Debug)]
4765
pub struct ValueSet {
4866
values: HashMap<Box<str>, Value>,
@@ -388,3 +406,212 @@ register_client!(Client, sys_info);
388406
const fn c_to_f(c: f64) -> f64 {
389407
c / 5.0 * 9.0 + 32.0
390408
}
409+
410+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
411+
pub enum TokenType {
412+
CpuFrequency,
413+
CpuPercent,
414+
415+
MemoryFree,
416+
MemoryAvailable,
417+
MemoryTotal,
418+
MemoryUsed,
419+
MemoryPercent,
420+
421+
SwapFree,
422+
SwapTotal,
423+
SwapUsed,
424+
SwapPercent,
425+
426+
TempC,
427+
TempF,
428+
429+
DiskFree,
430+
DiskTotal,
431+
DiskUsed,
432+
DiskPercent,
433+
DiskRead,
434+
DiskWrite,
435+
436+
NetDown,
437+
NetUp,
438+
439+
LoadAverage1,
440+
LoadAverage5,
441+
LoadAverage15,
442+
Uptime,
443+
}
444+
445+
impl FromStr for TokenType {
446+
type Err = Report;
447+
448+
fn from_str(s: &str) -> Result<Self> {
449+
match s {
450+
"cpu_frequency" => Ok(Self::CpuFrequency),
451+
"cpu_percent" => Ok(Self::CpuPercent),
452+
453+
"memory_free" => Ok(Self::MemoryFree),
454+
"memory_available" => Ok(Self::MemoryAvailable),
455+
"memory_total" => Ok(Self::MemoryTotal),
456+
"memory_used" => Ok(Self::MemoryUsed),
457+
"memory_percent" => Ok(Self::MemoryPercent),
458+
459+
"swap_free" => Ok(Self::SwapFree),
460+
"swap_total" => Ok(Self::SwapTotal),
461+
"swap_used" => Ok(Self::SwapUsed),
462+
"swap_percent" => Ok(Self::SwapPercent),
463+
464+
"temp_c" => Ok(Self::TempC),
465+
"temp_f" => Ok(Self::TempF),
466+
467+
"disk_free" => Ok(Self::DiskFree),
468+
"disk_total" => Ok(Self::DiskTotal),
469+
"disk_used" => Ok(Self::DiskUsed),
470+
"disk_percent" => Ok(Self::DiskPercent),
471+
"disk_read" => Ok(Self::DiskRead),
472+
"disk_write" => Ok(Self::DiskWrite),
473+
474+
"net_down" => Ok(Self::NetDown),
475+
"net_up" => Ok(Self::NetUp),
476+
477+
"load_average_1" => Ok(Self::LoadAverage1),
478+
"load_average_5" => Ok(Self::LoadAverage5),
479+
"load_average_15" => Ok(Self::LoadAverage15),
480+
"uptime" => Ok(Self::Uptime),
481+
_ => Err(Report::msg(format!("invalid token type: '{s}'"))),
482+
}
483+
}
484+
}
485+
486+
impl Namespace for Client {
487+
fn get(&self, key: &str) -> Option<String> {
488+
let get = |value: Value| Some(value.get(Prefix::None).to_string());
489+
490+
let token = TokenType::from_str(key).ok()?;
491+
match token {
492+
TokenType::CpuFrequency => None,
493+
TokenType::CpuPercent => None,
494+
TokenType::MemoryFree => get(self.memory_free()),
495+
TokenType::MemoryAvailable => get(self.memory_available()),
496+
TokenType::MemoryTotal => get(self.memory_total()),
497+
TokenType::MemoryUsed => get(self.memory_used()),
498+
TokenType::MemoryPercent => get(self.memory_percent()),
499+
TokenType::SwapFree => get(self.swap_free()),
500+
TokenType::SwapTotal => get(self.swap_total()),
501+
TokenType::SwapUsed => get(self.swap_used()),
502+
TokenType::SwapPercent => get(self.swap_percent()),
503+
TokenType::TempC => None,
504+
TokenType::TempF => None,
505+
TokenType::DiskFree => None,
506+
TokenType::DiskTotal => None,
507+
TokenType::DiskUsed => None,
508+
TokenType::DiskPercent => None,
509+
TokenType::DiskRead => None,
510+
TokenType::DiskWrite => None,
511+
TokenType::NetDown => None,
512+
TokenType::NetUp => None,
513+
TokenType::LoadAverage1 => get(self.load_average_1()),
514+
TokenType::LoadAverage5 => get(self.load_average_5()),
515+
TokenType::LoadAverage15 => get(self.load_average_15()),
516+
TokenType::Uptime => Some(self.uptime()),
517+
}
518+
}
519+
520+
fn list(&self) -> Vec<String> {
521+
vec![
522+
"memory_free",
523+
"memory_available",
524+
"memory_total",
525+
"memory_used",
526+
"memory_percent",
527+
"swap_free",
528+
"swap_total",
529+
"swap_used",
530+
"swap_percent",
531+
"load_average_1",
532+
"load_average_5",
533+
"load_average_15",
534+
"uptime",
535+
]
536+
.into_iter()
537+
.map(ToString::to_string)
538+
.collect()
539+
}
540+
541+
fn namespaces(&self) -> Vec<String> {
542+
vec![
543+
"cpu_frequency",
544+
"cpu_percent",
545+
"temp_c",
546+
"temp_f",
547+
"disk_free",
548+
"disk_total",
549+
"disk_used",
550+
"disk_percent",
551+
"disk_read",
552+
"disk_write",
553+
"net_down",
554+
"net_up",
555+
]
556+
.into_iter()
557+
.map(ToString::to_string)
558+
.collect()
559+
}
560+
561+
fn get_namespace(&self, key: &str) -> Option<Arc<dyn Namespace + Sync + Send>> {
562+
let token = TokenType::from_str(key).ok()?;
563+
564+
match token {
565+
TokenType::CpuFrequency => Some(Arc::new(self.cpu_frequency())),
566+
TokenType::CpuPercent => Some(Arc::new(self.cpu_percent())),
567+
TokenType::MemoryFree => None,
568+
TokenType::MemoryAvailable => None,
569+
TokenType::MemoryTotal => None,
570+
TokenType::MemoryUsed => None,
571+
TokenType::MemoryPercent => None,
572+
TokenType::SwapFree => None,
573+
TokenType::SwapTotal => None,
574+
TokenType::SwapUsed => None,
575+
TokenType::SwapPercent => None,
576+
TokenType::TempC => Some(Arc::new(self.temp_c())),
577+
TokenType::TempF => Some(Arc::new(self.temp_f())),
578+
TokenType::DiskFree => Some(Arc::new(self.disk_free())),
579+
TokenType::DiskTotal => Some(Arc::new(self.disk_total())),
580+
TokenType::DiskUsed => Some(Arc::new(self.disk_used())),
581+
TokenType::DiskPercent => Some(Arc::new(self.disk_percent())),
582+
TokenType::DiskRead => Some(Arc::new(self.disk_read(Interval::All(1)))),
583+
TokenType::DiskWrite => Some(Arc::new(self.disk_write(Interval::All(1)))),
584+
TokenType::NetDown => Some(Arc::new(self.net_down(Interval::All(1)))),
585+
TokenType::NetUp => Some(Arc::new(self.net_up(Interval::All(1)))),
586+
TokenType::LoadAverage1 => None,
587+
TokenType::LoadAverage5 => None,
588+
TokenType::LoadAverage15 => None,
589+
TokenType::Uptime => None,
590+
}
591+
}
592+
}
593+
594+
impl Namespace for ValueSet {
595+
fn get(&self, key: &str) -> Option<String> {
596+
let function = Function::from_str(key).ok()?;
597+
Some(self.apply(&function, Prefix::None).to_string())
598+
}
599+
600+
fn list(&self) -> Vec<String> {
601+
let mut vec = vec!["sum", "min", "max", "mean"]
602+
.into_iter()
603+
.map(ToString::to_string)
604+
.collect::<Vec<_>>();
605+
606+
vec.extend(self.values.keys().map(ToString::to_string));
607+
vec
608+
}
609+
610+
fn namespaces(&self) -> Vec<String> {
611+
vec![]
612+
}
613+
614+
fn get_namespace(&self, _key: &str) -> Option<Arc<dyn Namespace + Sync + Send>> {
615+
None
616+
}
617+
}

src/dynamic_value/dynamic_bool.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl DynamicBool {
5858
let variable_manager = Ironbar::variable_manager();
5959

6060
let variable_name = variable[1..].into(); // remove hash
61-
let mut rx = crate::write_lock!(variable_manager).subscribe(variable_name);
61+
let mut rx = variable_manager.subscribe(variable_name);
6262

6363
while let Ok(value) = rx.recv().await {
6464
let has_value = value.is_some_and(|s| is_truthy(&s));

src/dynamic_value/dynamic_string.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ where
7171

7272
spawn(async move {
7373
let variable_manager = Ironbar::variable_manager();
74-
let mut rx = crate::write_lock!(variable_manager).subscribe(name);
74+
let mut rx = variable_manager.subscribe(name);
7575

7676
while let Ok(value) = rx.recv().await {
7777
if let Some(value) = value {

src/ipc/commands.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub enum IronvarCommand {
5252
},
5353

5454
/// Gets the current value of all `ironvar`s.
55-
List,
55+
List { namespace: Option<Box<str>> },
5656
}
5757

5858
#[derive(Args, Debug, Serialize, Deserialize)]

0 commit comments

Comments
 (0)