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=,,"); } 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 = None; let mut net_width: Option = Some(11); let mut net_graph_max: Option = 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 = 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::() { 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 = 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 = 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 = 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| { 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 = 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, "{}", item.get_value() )?; } proc::GraphItemType::Upload => { write!( &mut text, "{}", item.get_value() )?; } proc::GraphItemType::Both => { write!( &mut text, "{}", 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); } }