456 lines
18 KiB
Rust
456 lines
18 KiB
Rust
mod args;
|
|
mod builtin;
|
|
mod external;
|
|
mod proc;
|
|
mod swaybar_object;
|
|
|
|
use std::fmt::Write as FMTWrite;
|
|
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(11);
|
|
let mut net_graph_max: Option<f64> = None;
|
|
let mut net_graph_is_dynamic: bool = false;
|
|
let mut net_graph_show_dynamic_max: bool = false;
|
|
let mut interval: Duration = Duration::from_secs(5);
|
|
let mut net_graph_size: Option<usize> = None;
|
|
if args_result.map.contains_key("netdev") {
|
|
if let Some(size_str) = args_result.map.get("netgraph-size") {
|
|
if let Ok(size) = size_str.parse::<usize>() {
|
|
if size > 0 {
|
|
net_graph_size = Some(size);
|
|
} else {
|
|
let mut stderr_handle = io::stderr().lock();
|
|
stderr_handle
|
|
.write_all(
|
|
"WARNING: Invalid value passed to --netgraph_size=..., ignoring...\n"
|
|
.as_bytes(),
|
|
)
|
|
.ok();
|
|
}
|
|
} else {
|
|
let mut stderr_handle = io::stderr().lock();
|
|
stderr_handle
|
|
.write_all(
|
|
"WARNING: Invalid value passed to --netgraph_size=..., ignoring...\n"
|
|
.as_bytes(),
|
|
)
|
|
.ok();
|
|
}
|
|
}
|
|
net_obj = Some(proc::NetInfo::new(
|
|
args_result.map.get("netdev").unwrap().to_owned(),
|
|
net_graph_size,
|
|
));
|
|
}
|
|
if net_graph_size.is_none() {
|
|
net_graph_size = Some(10);
|
|
}
|
|
|
|
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(
|
|
"WARNING: Invalid value passed to --netdev_width=..., ignoring...\n".as_bytes(),
|
|
)
|
|
.ok();
|
|
}
|
|
}
|
|
if args_result.map.contains_key("netgraph") {
|
|
if args_result.map.get("netgraph").as_ref().unwrap() == &"dynamic" {
|
|
net_graph_is_dynamic = true;
|
|
} else {
|
|
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(
|
|
"WARNING: Invalid value passed to --netgraph_max_bytes=..., ignoring...\n"
|
|
.as_bytes(),
|
|
)
|
|
.ok();
|
|
}
|
|
}
|
|
}
|
|
if args_result.map.contains_key("netgraph-dyndisplay") {
|
|
net_graph_show_dynamic_max = true;
|
|
}
|
|
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 net_graph_is_dynamic && net_graph_show_dynamic_max {
|
|
array.push_object(SwaybarObject::from_error_string(
|
|
"net_graph_dyn_max".to_owned(),
|
|
"net ERROR".into(),
|
|
));
|
|
}
|
|
|
|
if graph_max_opt.is_some() || net_graph_is_dynamic {
|
|
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 net_graph_is_dynamic && net_graph_show_dynamic_max {
|
|
if let Some(dyn_max) = array.get_by_name_mut("net_graph_dyn_max") {
|
|
dyn_max.update_as_error("Net ERROR".to_owned());
|
|
}
|
|
}
|
|
|
|
if graph_max_opt.is_some() || net_graph_is_dynamic {
|
|
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_items, max_idx, history_max) =
|
|
net.get_netstring(net_graph_max)?;
|
|
let netinfo_parts: Vec<&str> = netinfo_string.split_whitespace().collect();
|
|
|
|
if is_empty {
|
|
if net_graph_is_dynamic && net_graph_show_dynamic_max {
|
|
let mut graph_obj =
|
|
SwaybarObject::from_string("net_graph_dyn_max".to_owned(), history_max);
|
|
graph_obj.color = Some("#ffff88".into());
|
|
array.push_object(graph_obj);
|
|
}
|
|
|
|
if net_graph_max.is_some() || net_graph_is_dynamic {
|
|
let mut graph_obj = SwaybarObject::from_string(
|
|
"net_graph".to_owned(),
|
|
" ".to_owned().repeat(net_graph_size.unwrap()),
|
|
);
|
|
graph_obj.markup = Some("pango".to_owned());
|
|
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_is_dynamic && net_graph_show_dynamic_max {
|
|
if let Some(graph_obj) = array.get_by_name_mut("net_graph_dyn_max") {
|
|
graph_obj.full_text = history_max;
|
|
if (net_graph_max.is_some() || net_graph_is_dynamic) && !graph_items.is_empty()
|
|
{
|
|
match graph_items[max_idx].get_value_type() {
|
|
proc::GraphItemType::Download => {
|
|
graph_obj.color = Some("#ff8888ff".into())
|
|
}
|
|
proc::GraphItemType::Upload => {
|
|
graph_obj.color = Some("#88ff88ff".into())
|
|
}
|
|
proc::GraphItemType::Both => graph_obj.color = Some("#ffff88ff".into()),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if net_graph_max.is_some() || net_graph_is_dynamic {
|
|
if let Some(graph_obj) = array.get_by_name_mut("net_graph") {
|
|
let mut text = String::new();
|
|
for item in graph_items.iter() {
|
|
match item.get_value_type() {
|
|
proc::GraphItemType::Download => {
|
|
write!(
|
|
&mut text,
|
|
"<span color=\"#ff8888ff\">{}</span>",
|
|
item.get_value()
|
|
)?;
|
|
}
|
|
proc::GraphItemType::Upload => {
|
|
write!(
|
|
&mut text,
|
|
"<span color=\"#88ff88ff\">{}</span>",
|
|
item.get_value()
|
|
)?;
|
|
}
|
|
proc::GraphItemType::Both => {
|
|
write!(
|
|
&mut text,
|
|
"<span color=\"#ffff88ff\">{}</span>",
|
|
item.get_value()
|
|
)?;
|
|
}
|
|
}
|
|
}
|
|
graph_obj.full_text = text;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|