Compare commits

...

3 Commits

Author SHA1 Message Date
750a2813d3 Changed debug option names
* --debug-json -> --debug
* --debug-modules -> --debug-icons
2025-06-06 17:57:14 -07:00
c84e9698d7 Added CPU usage module 2025-06-06 17:50:16 -07:00
e6719dc6f5 Use available mem instead of free mem 2025-06-06 17:48:35 -07:00
7 changed files with 203 additions and 17 deletions

View File

@@ -0,0 +1,183 @@
use std::fs::File;
// use std::path::Path;
// use std::io::prelude::*;
// use regex::Regex;
use std::io::{self, BufRead, BufReader};
use std::thread;
use std::time::Duration;
use crate::common;
use crate::bar_modules;
#[derive(Debug, Default, Clone)]
struct CpuTimes {
user: u64,
nice: u64,
system: u64,
idle: u64,
iowait: u64,
irq: u64,
softirq: u64,
steal: u64,
guest: u64,
guest_nice: u64,
}
impl CpuTimes {
pub fn new() -> Self {
CpuTimes {
user: 0,
nice: 0,
system: 0,
idle: 0,
iowait: 0,
irq: 0,
softirq: 0,
steal: 0,
guest: 0,
guest_nice: 0
}
}
fn total(&self) -> u64 {
self.user
+ self.nice
+ self.system
+ self.idle
+ self.iowait
+ self.irq
+ self.softirq
+ self.steal
+ self.guest
+ self.guest_nice
}
fn idle(&self) -> u64 {
self.idle + self.iowait
}
}
#[derive(Clone)]
pub struct UnibarModuleCpu {
opts: common::AppOptions,
cpu_times_sample_1: CpuTimes,
cpu_times_sample_2: CpuTimes,
}
impl UnibarModuleCpu {
// --------------------
pub fn new(o :common::AppOptions) -> Self {
UnibarModuleCpu {
opts: o,
cpu_times_sample_1: CpuTimes::new(),
cpu_times_sample_2: CpuTimes::new(),
}
}
// --------------------
// cpu 242109 7 60985 6538626 8344 39138 9647 0 0 0
// * user time spent in user mode
// * nice time spent processing nice processes in user mode
// * system time spent executing kernel code
// * idle time spent idle
// * iowait time spent waiting for I/O
// * irq time spent servicing interrupts
// * softirq time spent servicing software interrupts
// * steal time stolen from a virtual machine
// * guest time spent running a virtual CPU for a guest operating system
// * guest_nice time spent running a virtual CPU for a “niced” guest operating system
fn read_cpu_times(&self) -> io::Result<CpuTimes> {
let file = File::open("/proc/stat")?;
let reader = BufReader::new(file);
for line in reader.lines() {
let line = line?;
if line.starts_with("cpu ") {
let fields: Vec<u64> = line.split_whitespace().skip(1).map(|s| s.parse().unwrap_or(0)).collect();
if fields.len() >= 8 {
return Ok(CpuTimes {
user: fields[0],
nice: fields[1],
system: fields[2],
idle: fields[3],
iowait: fields[4],
irq: fields[5],
softirq: fields[6],
steal: fields[7],
guest: if fields.len() > 8 { fields[8] } else { 0 },
guest_nice: if fields.len() > 9 { fields[9] } else { 0 },
});
}
}
}
Err(io::Error::new(io::ErrorKind::InvalidData, "Could not find cpu line in /proc/stat"))
}
}
impl bar_modules::BarModuleActions for UnibarModuleCpu {
// --------------------
fn generate_data(&mut self) {
self.cpu_times_sample_1 = self.read_cpu_times().expect("REASON");
thread::sleep(Duration::from_millis(1000));
self.cpu_times_sample_2 = self.read_cpu_times().expect("REASON");
if self.opts.debug {
println!("-----> CPU times sample 1 - {:#?}", self.cpu_times_sample_1);
println!("-----> CPU times sample 2 - {:#?}", self.cpu_times_sample_2);
}
}
// --------------------
fn get_content(&self) -> String {
let sample_1_total = self.cpu_times_sample_1.total();
let sample_2_total = self.cpu_times_sample_2.total();
let sample_1_idle = self.cpu_times_sample_1.idle();
let sample_2_idle = self.cpu_times_sample_2.idle();
let total_diff = sample_2_total - sample_1_total;
let idle_diff = sample_2_idle - sample_1_idle;
if total_diff > 0 {
let cpu_usage = (1.0 - (idle_diff as f64 / total_diff as f64)) * 100.0;
return format!("{}%", cpu_usage.ceil() as i32);
} else {
return format!("CPU?");
}
// let re = Regex::new(r"cpu\s+.*").unwrap();
// let caps = re.captures(self.procstat_str.as_str()).unwrap();
// let cpu_line = caps.get(0).unwrap().as_str();
// if self.opts.debug {
// println!("-----> CPU line - {:#?}", cpu_line);
// }
// let binding = Regex::new(r"\s+").unwrap();
// let mut parts :Vec<&str> = binding.split(cpu_line).collect();
// parts.remove(0); // Remove the 'cpu' part
// let cpu_idle :f32 = parts[3].parse::<f32>().unwrap();
// let mut cpu_total :f32 = 0.0;
// for usg in parts {
// cpu_total += usg.parse::<f32>().unwrap();
// }
// return format!("{}%", (((cpu_total - cpu_idle)/cpu_total) * 100.0).ceil() as i32);
}
// --------------------
fn get_icon(&self) -> String {
return "💻".to_string();
}
}
impl bar_modules::BarModuleDebug for UnibarModuleCpu {
// --------------------
fn post_debug(&self) {
}
}

View File

@@ -29,7 +29,7 @@ impl bar_modules::BarModuleActions for UnibarModuleMemory {
fn generate_data(&mut self) {
let path = Path::new("/proc/meminfo");
// Contents of '/process/meminfo' has memory information
// Contents of '/proc/meminfo' has memory information
let mut meminfo_file = match File::open(&path) {
Err(why) => panic!("couldn't open {}: {}", path.display(), why),
Ok(file) => file,
@@ -37,7 +37,7 @@ impl bar_modules::BarModuleActions for UnibarModuleMemory {
match meminfo_file.read_to_string(&mut self.meminfo_str) {
Err(why) => panic!("couldn't read {}: {}", path.display(), why),
Ok(_) => if self.opts.debug_json {
Ok(_) => if self.opts.debug {
println!("-----> meminfo - {:#?}", self.meminfo_str);
},
};
@@ -48,12 +48,12 @@ impl bar_modules::BarModuleActions for UnibarModuleMemory {
// --------------------
// MemTotal: 7822812 kB\nMemFree: 399244 kB\nMemAvailable: 3986504 kB
fn get_content(&self) -> String {
let re = Regex::new(r"MemTotal:\s+(\d+)\s+kB\nMemFree:\s+(\d+)").unwrap();
let re = Regex::new(r"MemTotal:\s+(\d+)\s+kB\nMemFree:\s+(\d+)\s+kB\nMemAvailable:\s+(\d+)").unwrap();
let caps = re.captures(self.meminfo_str.as_str()).unwrap();
let total_mem :f32 = caps.get(1).unwrap().as_str().parse::<f32>().unwrap();
let free_mem :f32 = caps.get(2).unwrap().as_str().parse::<f32>().unwrap();
return format!("{}%", ((total_mem - free_mem)/total_mem * 100.0).ceil() as i32);
let avail_mem :f32 = caps.get(3).unwrap().as_str().parse::<f32>().unwrap();
return format!("{}%", ((total_mem - avail_mem)/total_mem * 100.0).ceil() as i32);
}
// --------------------

View File

@@ -41,7 +41,7 @@ impl bar_modules::BarModuleActions for UnibarModuleNetwork {
let network_data: Value = serde_json::from_str::<Value>(self.ip_addr_stdout.as_str()).unwrap();
if let Some(interfaces) = network_data.as_array() {
if self.opts.debug_json {
if self.opts.debug {
println!("-----> network_data - {:#?}", network_data);
}
// Get all interfaces that are up
@@ -58,7 +58,7 @@ impl bar_modules::BarModuleActions for UnibarModuleNetwork {
.filter(|ai| ai["scope"].as_str().unwrap().contains("global"))
.cloned().collect();
if inet_addr.len() > 0 {
if self.opts.debug_json {
if self.opts.debug {
println!("-----> Inet Addr - {:#?}", inet_addr);
}
self.network_info = inet_addr[0].clone();
@@ -66,7 +66,7 @@ impl bar_modules::BarModuleActions for UnibarModuleNetwork {
}
}
}
if self.opts.debug_json {
if self.opts.debug {
println!("-----> ip_addr - {:#?}", self.network_info);
}
}

View File

@@ -175,7 +175,7 @@ impl bar_modules::BarModuleActions for UnibarModuleWeather {
}).unwrap();
transfer.perform().unwrap();
}
if self.opts.debug_json {
if self.opts.debug {
println!("-----> curl_data - [{}]", std::str::from_utf8(&curl_ret).unwrap());
}

View File

@@ -21,3 +21,4 @@ pub mod bar_module_weather;
pub mod bar_module_music;
pub mod bar_module_network;
pub mod bar_module_memory;
pub mod bar_module_cpu;

View File

@@ -26,6 +26,6 @@ pub struct AppOptions {
pub weather_units: TemperatureUnits,
pub weather_station: String,
pub music_progress: bool,
pub debug_json: bool,
pub debug_modules: bool,
pub debug: bool,
pub debug_icons: bool,
}

View File

@@ -28,11 +28,11 @@ struct CommandlineArgs {
/// Show JSON data returned by query
#[arg(short = 'D', long)]
debug_json: bool,
debug: bool,
/// Show ICON debug information
#[arg(short = 'I', long)]
debug_modules: bool,
debug_icons: bool,
}
//
@@ -46,7 +46,7 @@ struct Unibar {
impl Unibar {
// --------------------
fn run(&self) {
if self.opts.debug_json {
if self.opts.debug {
self.debug_msg("Debugging ...");
}
self.check_options();
@@ -55,6 +55,7 @@ impl Unibar {
let bar_modules_enabled: Vec<Box<dyn bar_modules::BarModuleActions>> = vec! [
Box::new(bar_modules::bar_module_music::UnibarModuleMusic::new(self.opts.clone())),
Box::new(bar_modules::bar_module_memory::UnibarModuleMemory::new(self.opts.clone())),
Box::new(bar_modules::bar_module_cpu::UnibarModuleCpu::new(self.opts.clone())),
Box::new(bar_modules::bar_module_network::UnibarModuleNetwork::new(self.opts.clone())),
Box::new(bar_modules::bar_module_weather::UnibarModuleWeather::new(self.opts.clone())),
];
@@ -79,12 +80,13 @@ impl Unibar {
}
// Show module debug information if enabled
if self.opts.debug_modules {
if self.opts.debug_icons {
let bar_modules_debugged: Vec<Box<dyn bar_modules::BarModuleDebug>> = vec! [
Box::new(bar_modules::bar_module_weather::UnibarModuleWeather::new(self.opts.clone())),
Box::new(bar_modules::bar_module_music::UnibarModuleMusic::new(self.opts.clone())),
Box::new(bar_modules::bar_module_memory::UnibarModuleMemory::new(self.opts.clone())),
Box::new(bar_modules::bar_module_network::UnibarModuleNetwork::new(self.opts.clone())),
Box::new(bar_modules::bar_module_cpu::UnibarModuleCpu::new(self.opts.clone())),
];
for md in bar_modules_debugged {
md.post_debug();
@@ -122,8 +124,8 @@ fn main() {
else { common::TemperatureUnits::Imperial },
weather_station: cmd_args.weather_station,
music_progress: cmd_args.music_progress,
debug_json: cmd_args.debug_json,
debug_modules: cmd_args.debug_modules
debug: cmd_args.debug,
debug_icons: cmd_args.debug_icons
},
};