swaybar_info/src/main.rs
Stephen Seo fb49271a7e Refactored handling of Option wrapping primitives
Option wrapping primities implement Copy, so they can be used directly
in the closure, and is more efficient to use copies of f64/u16 than with
references to them.
2022-10-18 21:47:11 +09:00

353 lines
13 KiB
Rust

mod args;
mod builtin;
mod external;
mod proc;
mod swaybar_object;
use std::io::{self, Write};
use std::time::Duration;
use swaybar_object::*;
const DEFAULT_FMT_STRING: &str = "%F %r";
fn main() {
let args_result = args::get_args();
if args_result.map.contains_key("help") {
args::print_usage();
return;
}
let mut cmds: Vec<(&str, Vec<&str>, regex::Regex)> = Vec::new();
for regex_cmd in &args_result.regex_cmds {
let mut split_strs = regex_cmd.split_terminator("[SPLIT]");
let cmd: &str = split_strs.next().expect("Should have cmd in option");
let mut args: Vec<&str> = Vec::new();
let mut next: Option<&str>;
loop {
next = split_strs.next();
if let Some(str) = next {
args.push(str);
} else {
break;
}
}
if args.is_empty() {
panic!("Missing regex for --regex-cmd=<cmd>,<args...>,<regex>");
}
let regex_str: &str = args[args.len() - 1];
args.pop();
let regex = regex::Regex::new(regex_str).expect("Should be able to compile regex");
cmds.push((cmd, args, regex));
}
let mut net_obj: Option<proc::NetInfo> = None;
let mut net_width: Option<u16> = Some(10);
let mut net_graph_max: Option<f64> = None;
let mut interval: Duration = Duration::from_secs(5);
if args_result.map.contains_key("netdev") {
net_obj = Some(proc::NetInfo::new(
args_result.map.get("netdev").unwrap().to_owned(),
));
}
if args_result.map.contains_key("netdevwidth") {
let width_result: Result<u16, _> = args_result.map.get("netdevwidth").unwrap().parse();
if let Ok(width) = width_result {
net_width = Some(width);
} else {
let mut stderr_handle = io::stderr().lock();
stderr_handle
.write_all(
format!("WARNING: Invalid value passed to --netdev_width=..., ignoring...\n")
.as_bytes(),
)
.ok();
}
}
if args_result.map.contains_key("netgraph") {
let graph_max_result: Result<f64, _> = args_result.map.get("netgraph").unwrap().parse();
if let Ok(graph_max) = graph_max_result {
net_graph_max = Some(graph_max);
} else {
let mut stderr_handle = io::stderr().lock();
stderr_handle
.write_all(
format!(
"WARNING: Invalid value passed to --netgraph_max_bytes=..., ignoring...\n"
)
.as_bytes(),
)
.ok();
}
}
if args_result.map.contains_key("interval-sec") {
let seconds: Result<i64, _> = args_result.map.get("interval-sec").unwrap().parse();
if let Ok(seconds_value) = seconds {
if seconds_value > 0 {
interval = Duration::from_secs(seconds_value as u64);
} else {
let mut stderr_handle = io::stderr().lock();
stderr_handle
.write_all(
format!(
"WARNING: Invalid --interval-sec=\"{}\", defaulting to 5!\n",
seconds_value
)
.as_bytes(),
)
.ok();
}
} else {
let mut stderr_handle = io::stderr().lock();
stderr_handle
.write_all(b"WARNING: Failed to parse --interval-sec=?, defaulting to 5!\n")
.ok();
}
}
let mut batt_info: builtin::BattInfo = Default::default();
let batt_info_enabled: bool = args_result.map.contains_key("acpi-builtin");
let mut batt_info_error: bool = false;
let mut time_fmt_str = DEFAULT_FMT_STRING;
if let Some(s) = args_result.map.get("time-format") {
time_fmt_str = s;
}
println!(
"{}",
serde_json::to_string(&swaybar_object::SwaybarHeader::new())
.expect("Should be able to serialize SwaybarHeader")
);
println!("[");
let mut array = SwaybarArray::new();
let set_net_error = |is_empty: bool, array: &mut SwaybarArray, graph_max_opt: &Option<f64>| {
if is_empty {
if graph_max_opt.is_some() {
array.push_object(SwaybarObject::from_error_string(
"net_graph".to_owned(),
"net ERROR".into(),
));
}
let down_obj =
SwaybarObject::from_error_string("net_down".to_owned(), "Net ERROR".into());
array.push_object(down_obj);
let up_obj = SwaybarObject::from_error_string("net_up".to_owned(), "Net ERROR".into());
array.push_object(up_obj);
} else {
if graph_max_opt.is_some() {
if let Some(graph_ref) = array.get_by_name_mut("net_graph") {
graph_ref.update_as_error("Net ERROR".to_owned());
}
}
let down_ref_opt = array.get_by_name_mut("net_down");
if let Some(down_ref) = down_ref_opt {
down_ref.update_as_error("Net ERROR".to_owned());
}
let up_ref_opt = array.get_by_name_mut("net_up");
if let Some(up_ref) = up_ref_opt {
up_ref.update_as_error("Net ERROR".to_owned());
}
}
};
let handle_net = |is_empty: bool,
net: &mut proc::NetInfo,
array: &mut SwaybarArray|
-> Result<(), proc::Error> {
net.update()?;
let (netinfo_string, graph_string) = net.get_netstring(net_graph_max)?;
let netinfo_parts: Vec<&str> = netinfo_string.split_whitespace().collect();
if is_empty {
if net_graph_max.is_some() {
let mut graph_obj =
SwaybarObject::from_string("net_graph".to_owned(), graph_string);
graph_obj.color = Some("#ffff88".into());
array.push_object(graph_obj);
}
let mut width_string: Option<String> = None;
if let Some(width) = net_width {
let mut string = String::with_capacity(width.into());
for _ in 0..width {
string.push('0');
}
width_string = Some(string);
}
{
let mut down_object = SwaybarObject::from_string(
"net_down".to_owned(),
format!("{} {}", netinfo_parts[0], netinfo_parts[1]),
);
down_object.color = Some("#ff8888ff".into());
down_object.min_width = width_string.clone();
down_object.align = Some(String::from("right"));
array.push_object(down_object);
}
{
let mut up_object = SwaybarObject::from_string(
"net_up".to_owned(),
format!("{} {}", netinfo_parts[2], netinfo_parts[3]),
);
up_object.color = Some("#88ff88ff".into());
up_object.min_width = width_string;
up_object.align = Some(String::from("right"));
array.push_object(up_object);
}
} else {
if net_graph_max.is_some() {
if let Some(graph_obj) = array.get_by_name_mut("net_graph") {
graph_obj.full_text = graph_string;
}
}
if let Some(down_object) = array.get_by_name_mut("net_down") {
down_object
.update_as_net_down(format!("{} {}", netinfo_parts[0], netinfo_parts[1]));
}
if let Some(up_object) = array.get_by_name_mut("net_up") {
up_object.update_as_net_up(format!("{} {}", netinfo_parts[2], netinfo_parts[3]));
}
}
Ok(())
};
loop {
let is_empty = array.is_empty();
// network traffic
if let Some(net) = net_obj.as_mut() {
if let Err(e) = handle_net(is_empty, net, &mut array) {
let mut stderr_handle = io::stderr().lock();
stderr_handle.write_all(format!("{}\n", e).as_bytes()).ok();
net_obj = None;
set_net_error(is_empty, &mut array, &net_graph_max);
}
}
// meminfo
{
let meminfo_result = proc::get_meminfo();
let meminfo_string: String = if let Err(e) = meminfo_result {
let mut stderr_handle = io::stderr().lock();
stderr_handle.write_all(format!("{}\n", e).as_bytes()).ok();
String::from("MEMINFO ERROR")
} else {
meminfo_result.unwrap()
};
if is_empty {
let meminfo_obj = SwaybarObject::from_string("meminfo".to_owned(), meminfo_string);
array.push_object(meminfo_obj);
} else if let Some(meminfo_obj) = array.get_by_name_mut("meminfo") {
meminfo_obj.update_as_generic(meminfo_string, None);
}
}
// regex_cmds
{
for (idx, (cmd, args, regex)) in cmds.iter().enumerate() {
let cmd_result = external::get_cmd_output(cmd, args, regex);
if let Ok(cmd_struct) = cmd_result {
if is_empty {
let mut cmd_obj = SwaybarObject::from_string(
format!("regex_cmd_{}", idx),
cmd_struct.matched,
);
cmd_obj.color = cmd_struct.color;
array.push_object(cmd_obj);
} else if let Some(cmd_obj) =
array.get_by_name_mut(&format!("regex_cmd_{}", idx))
{
cmd_obj.update_as_generic(cmd_struct.matched, cmd_struct.color);
}
} else if let Err(e) = cmd_result {
let mut stderr_handle = io::stderr().lock();
stderr_handle.write_all(format!("{}\n", e).as_bytes()).ok();
if is_empty {
let cmd_obj = SwaybarObject::from_error_string(
format!("regex_cmd_{}", idx),
"REGEX_CMD ERROR".into(),
);
array.push_object(cmd_obj);
} else if let Some(cmd_obj) =
array.get_by_name_mut(&format!("regex_cmd_{}", idx))
{
cmd_obj.update_as_error("REGEX_CMD ERROR".into());
}
}
}
}
// batt_info
if batt_info_enabled {
if is_empty {
let mut new_object = SwaybarObject::new("battinfo".to_owned());
let result = batt_info.update(&mut new_object);
if result.is_ok() {
array.push_object(new_object);
} else {
new_object.update_as_error("BATTINFO ERROR".to_owned());
array.push_object(new_object);
batt_info_error = true;
let mut stderr_handle = io::stderr().lock();
stderr_handle
.write_all(format!("{}\n", result.unwrap_err()).as_bytes())
.ok();
}
} else if let Some(obj) = array.get_by_name_mut("battinfo") {
if !batt_info_error {
let result = batt_info.update(obj);
if let Err(e) = result {
obj.update_as_error("BATTINFO ERROR".to_owned());
batt_info_error = true;
let mut stderr_handle = io::stderr().lock();
stderr_handle.write_all(format!("{}\n", e).as_bytes()).ok();
}
}
}
}
// loadavg
{
let loadavg_result = proc::get_loadavg();
let loadavg_string: String = if let Err(e) = loadavg_result {
let mut stderr_handle = io::stderr().lock();
stderr_handle.write_all(format!("{}\n", e).as_bytes()).ok();
String::from("LOADAVG ERROR")
} else {
loadavg_result.unwrap()
};
if is_empty {
let loadavg_obj = SwaybarObject::from_string("loadavg".to_owned(), loadavg_string);
array.push_object(loadavg_obj);
} else if let Some(loadavg_obj) = array.get_by_name_mut("loadavg") {
loadavg_obj.update_as_generic(loadavg_string, None);
}
}
// time
if is_empty {
let mut time_obj = SwaybarObject::new("current_time".to_owned());
time_obj.update_as_date(time_fmt_str);
array.push_object(time_obj);
} else if let Some(time_obj) = array.get_by_name_mut("current_time") {
time_obj.update_as_date(time_fmt_str);
}
println!("{}", array);
std::thread::sleep(interval);
}
}