summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorClementTsang <clementjhtsang@gmail.com>2019-09-15 00:06:57 -0400
committerClementTsang <clementjhtsang@gmail.com>2019-09-15 00:06:57 -0400
commit282acd1395fb521be3ca94c7731abfdfa2c9ae0c (patch)
tree1539d67a995ba268ec1d70f3fb615fbe3c7c1d18 /src
parent2435b9d90ce8029dd731238972f3610a56b6c3f9 (diff)
Made charting look better, switched back to braille markers (its the only way I could make it look good), and dealt with some issues regarding the display of networking.
Diffstat (limited to 'src')
-rw-r--r--src/app/data_collection.rs1
-rw-r--r--src/app/data_collection/disks.rs20
-rw-r--r--src/app/data_collection/processes.rs32
-rw-r--r--src/canvas.rs29
-rw-r--r--src/main.rs132
5 files changed, 158 insertions, 56 deletions
diff --git a/src/app/data_collection.rs b/src/app/data_collection.rs
index 4b7a04e9..4e45b719 100644
--- a/src/app/data_collection.rs
+++ b/src/app/data_collection.rs
@@ -103,7 +103,6 @@ impl DataState {
}
// Filter out stale timed entries
- // TODO: ideally make this a generic function!
let current_instant = std::time::Instant::now();
self.data.list_of_cpu_packages = self
.data
diff --git a/src/app/data_collection/disks.rs b/src/app/data_collection/disks.rs
index ad897aed..1700ddbb 100644
--- a/src/app/data_collection/disks.rs
+++ b/src/app/data_collection/disks.rs
@@ -56,16 +56,18 @@ pub async fn get_disk_usage_list() -> Result<Vec<DiskData>, heim::Error> {
let mut partitions_stream = heim::disk::partitions_physical();
while let Some(part) = partitions_stream.next().await {
- let partition = part?; // TODO: Change this? We don't want to error out immediately...
- let usage = heim::disk::usage(partition.mount_point().to_path_buf()).await?;
+ if let Ok(part) = part {
+ let partition = part;
+ let usage = heim::disk::usage(partition.mount_point().to_path_buf()).await?;
- vec_disks.push(DiskData {
- free_space : usage.free().get::<heim_common::units::information::megabyte>(),
- used_space : usage.used().get::<heim_common::units::information::megabyte>(),
- total_space : usage.total().get::<heim_common::units::information::megabyte>(),
- mount_point : Box::from(partition.mount_point().to_str().unwrap_or("Name Unavailable")),
- name : Box::from(partition.device().unwrap_or_else(|| std::ffi::OsStr::new("Name Unavailable")).to_str().unwrap_or("Name Unavailable")),
- });
+ vec_disks.push(DiskData {
+ free_space : usage.free().get::<heim_common::units::information::megabyte>(),
+ used_space : usage.used().get::<heim_common::units::information::megabyte>(),
+ total_space : usage.total().get::<heim_common::units::information::megabyte>(),
+ mount_point : Box::from(partition.mount_point().to_str().unwrap_or("Name Unavailable")),
+ name : Box::from(partition.device().unwrap_or_else(|| std::ffi::OsStr::new("Name Unavailable")).to_str().unwrap_or("Name Unavailable")),
+ });
+ }
}
vec_disks.sort_by(|a, b| {
diff --git a/src/app/data_collection/processes.rs b/src/app/data_collection/processes.rs
index 2ef587bb..b1d495bf 100644
--- a/src/app/data_collection/processes.rs
+++ b/src/app/data_collection/processes.rs
@@ -39,15 +39,20 @@ fn vangelis_cpu_usage_calculation(prev_idle : &mut f64, prev_non_idle : &mut f64
let first_line = stat_results.split('\n').collect::<Vec<&str>>()[0];
let val = first_line.split_whitespace().collect::<Vec<&str>>();
- let user : f64 = val[1].parse::<_>().unwrap_or(-1_f64); // TODO: Better checking
- let nice : f64 = val[2].parse::<_>().unwrap_or(-1_f64);
- let system : f64 = val[3].parse::<_>().unwrap_or(-1_f64);
- let idle : f64 = val[4].parse::<_>().unwrap_or(-1_f64);
- let iowait : f64 = val[5].parse::<_>().unwrap_or(-1_f64);
- let irq : f64 = val[6].parse::<_>().unwrap_or(-1_f64);
- let softirq : f64 = val[7].parse::<_>().unwrap_or(-1_f64);
- let steal : f64 = val[8].parse::<_>().unwrap_or(-1_f64);
- let guest : f64 = val[9].parse::<_>().unwrap_or(-1_f64);
+ // SC in case that the parsing will fail due to length:
+ if val.len() <= 10 {
+ return Ok(1.0); // TODO: This is not the greatest...
+ }
+
+ let user : f64 = val[1].parse::<_>().unwrap_or(0_f64);
+ let nice : f64 = val[2].parse::<_>().unwrap_or(0_f64);
+ let system : f64 = val[3].parse::<_>().unwrap_or(0_f64);
+ let idle : f64 = val[4].parse::<_>().unwrap_or(0_f64);
+ let iowait : f64 = val[5].parse::<_>().unwrap_or(0_f64);
+ let irq : f64 = val[6].parse::<_>().unwrap_or(0_f64);
+ let softirq : f64 = val[7].parse::<_>().unwrap_or(0_f64);
+ let steal : f64 = val[8].parse::<_>().unwrap_or(0_f64);
+ let guest : f64 = val[9].parse::<_>().unwrap_or(0_f64);
let idle = idle + iowait;
let non_idle = user + nice + system + irq + softirq + steal + guest;
@@ -204,12 +209,13 @@ pub async fn get_sorted_processes_list(prev_idle : &mut f64, prev_non_idle : &mu
}
}
else if cfg!(target_os = "macos") {
- // macOS
- dbg!("Mac"); // TODO: Remove
+ // TODO: macOS
+ debug!("Mac");
}
else {
- dbg!("Else"); // TODO: Remove
- // Solaris: https://stackoverflow.com/a/4453581
+ // TODO: Others?
+ debug!("Else");
+ // Solaris: https://stackoverflow.com/a/4453581
}
Ok(process_vector)
diff --git a/src/canvas.rs b/src/canvas.rs
index 333e0382..7858c42b 100644
--- a/src/canvas.rs
+++ b/src/canvas.rs
@@ -7,13 +7,16 @@ use tui::{
use crate::utils::error;
-const COLOUR_LIST : [Color; 6] = [Color::LightRed, Color::LightGreen, Color::LightYellow, Color::LightBlue, Color::LightCyan, Color::LightMagenta];
+const COLOUR_LIST : [Color; 6] = [Color::Red, Color::Green, Color::LightYellow, Color::LightBlue, Color::LightCyan, Color::LightMagenta];
const TEXT_COLOUR : Color = Color::Gray;
const GRAPH_COLOUR : Color = Color::Gray;
const BORDER_STYLE_COLOUR : Color = Color::Gray;
+const GRAPH_MARKER : Marker = Marker::Braille;
#[derive(Default)]
pub struct CanvasData {
+ pub rx_display : String,
+ pub tx_display : String,
pub network_data_rx : Vec<(f64, f64)>,
pub network_data_tx : Vec<(f64, f64)>,
pub disk_data : Vec<Vec<String>>,
@@ -61,14 +64,14 @@ pub fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, canvas_
// CPU usage graph
{
let x_axis : Axis<String> = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([0.0, 600_000.0]);
- let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([0.0, 100.0]).labels(&["0%", "50%", "100%"]);
+ let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([-0.5, 100.0]).labels(&["0%", "100%"]);
let mut dataset_vector : Vec<Dataset> = Vec::new();
for (i, cpu) in canvas_data.cpu_data.iter().enumerate() {
dataset_vector.push(
Dataset::default()
.name(&cpu.0)
- .marker(Marker::Dot)
+ .marker(GRAPH_MARKER)
.style(Style::default().fg(COLOUR_LIST[i % COLOUR_LIST.len()]))
.data(&(cpu.1)),
);
@@ -85,20 +88,20 @@ pub fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, canvas_
//Memory usage graph
{
let x_axis : Axis<String> = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([0.0, 600_000.0]);
- let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([0.0, 100.0]).labels(&["0%", "50%", "100%"]);
+ let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([-0.5, 100.0]).labels(&["0%", "100%"]); // Offset as the zero value isn't drawn otherwise...
Chart::default()
.block(Block::default().title("Memory Usage").borders(Borders::ALL).border_style(border_style))
.x_axis(x_axis)
.y_axis(y_axis)
.datasets(&[
Dataset::default()
- .name(&("MEM :".to_string() + &format!("{:3}%", (canvas_data.mem_data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64))))
- .marker(Marker::Dot)
+ .name(&("RAM:".to_string() + &format!("{:3}%", (canvas_data.mem_data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64))))
+ .marker(GRAPH_MARKER)
.style(Style::default().fg(Color::LightBlue))
.data(&canvas_data.mem_data),
Dataset::default()
- .name(&("SWAP:".to_string() + &format!("{:3}%", (canvas_data.swap_data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64))))
- .marker(Marker::Dot)
+ .name(&("SWP:".to_string() + &format!("{:3}%", (canvas_data.swap_data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64))))
+ .marker(GRAPH_MARKER)
.style(Style::default().fg(Color::LightYellow))
.data(&canvas_data.swap_data),
])
@@ -128,20 +131,20 @@ pub fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, canvas_
// Network graph
{
let x_axis : Axis<String> = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([0.0, 600_000.0]);
- let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([0.0, 1000.0]).labels(&["0Kb", "1000Kb"]);
+ let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([-0.5, 1_000_000.0]).labels(&["0GB", "1GB"]);
Chart::default()
.block(Block::default().title("Network").borders(Borders::ALL).border_style(border_style))
.x_axis(x_axis)
.y_axis(y_axis)
.datasets(&[
Dataset::default()
- .name(&("RX:".to_string() + &format!("{:3}%", (canvas_data.network_data_rx.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64))))
- .marker(Marker::Dot)
+ .name(&(canvas_data.rx_display))
+ .marker(GRAPH_MARKER)
.style(Style::default().fg(Color::LightBlue))
.data(&canvas_data.network_data_rx),
Dataset::default()
- .name(&("TX:".to_string() + &format!("{:3}%", (canvas_data.network_data_tx.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64))))
- .marker(Marker::Dot)
+ .name(&(canvas_data.tx_display))
+ .marker(GRAPH_MARKER)
.style(Style::default().fg(Color::LightYellow))
.data(&canvas_data.network_data_tx),
])
diff --git a/src/main.rs b/src/main.rs
index c8b74cf2..75f66dc3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -41,7 +41,7 @@ fn main() -> error::Result<()> {
(about: "A graphical top clone.")
(@arg THEME: -t --theme +takes_value "Sets a colour theme.")
(@arg AVG_CPU: -a --avgcpu "Enables showing the average CPU usage.")
- (@arg DEBUG: -d --debug "Enables debug mode.")
+ (@arg DEBUG: -d --debug "Enables debug mode.") // TODO: This isn't done yet!
(@group TEMPERATURE_TYPE =>
(@arg CELSIUS : -c --celsius "Sets the temperature type to Celsius. This is the default option.")
(@arg FAHRENHEIT : -f --fahrenheit "Sets the temperature type to Fahrenheit.")
@@ -52,11 +52,16 @@ fn main() -> error::Result<()> {
.after_help("Themes:")
.get_matches();
- let update_rate_in_milliseconds : u64 = matches.value_of("RATE").unwrap_or("1000").parse::<u64>()?;
+ let update_rate_in_milliseconds : u128 = matches.value_of("RATE").unwrap_or("1000").parse::<u128>()?;
if update_rate_in_milliseconds < 250 {
return Err(RustopError::InvalidArg {
- message : "Please set your rate to be greater than 250 milliseconds.".to_string(),
+ message : "Please set your update rate to be greater than 250 milliseconds.".to_string(),
+ });
+ }
+ else if update_rate_in_milliseconds > u128::from(std::u64::MAX) {
+ return Err(RustopError::InvalidArg {
+ message : "Please set your update rate to be less than unsigned INT_MAX.".to_string(),
});
}
@@ -72,8 +77,7 @@ fn main() -> error::Result<()> {
let show_average_cpu = matches.is_present("AVG_CPU");
// Create "app" struct, which will control most of the program and store settings/state
- // TODO: Error handling here because users may be stupid and pass INT_MAX.
- let mut app = app::App::new(show_average_cpu, temperature_type, update_rate_in_milliseconds);
+ let mut app = app::App::new(show_average_cpu, temperature_type, update_rate_in_milliseconds as u64);
// Set up input handling
let (tx, rx) = mpsc::channel();
@@ -104,7 +108,7 @@ fn main() -> error::Result<()> {
loop {
futures::executor::block_on(data_state.update_data());
tx.send(Event::Update(Box::from(data_state.data.clone()))).unwrap();
- thread::sleep(Duration::from_millis(update_rate_in_milliseconds));
+ thread::sleep(Duration::from_millis(update_rate_in_milliseconds as u64));
}
});
}
@@ -151,6 +155,8 @@ fn main() -> error::Result<()> {
let network_data = update_network_data_points(&app_data);
canvas_data.network_data_rx = network_data.rx;
canvas_data.network_data_tx = network_data.tx;
+ canvas_data.rx_display = network_data.rx_display;
+ canvas_data.tx_display = network_data.tx_display;
canvas_data.disk_data = update_disk_row(&app_data);
canvas_data.temp_sensor_data = update_temp_row(&app_data, &app.temperature_type);
canvas_data.process_data = update_process_row(&app_data);
@@ -253,8 +259,6 @@ fn update_cpu_data_points(show_avg_cpu : bool, app_data : &data_collection::Data
let mut cpu_collection : Vec<Vec<(f64, f64)>> = Vec::new();
if !app_data.list_of_cpu_packages.is_empty() {
- // Initially, populate the cpu_collection. We want to inject elements in between if possible.
-
// I'm sorry for the if statement but I couldn't be bothered here...
for cpu_num in (if show_avg_cpu { 0 } else { 1 })..app_data.list_of_cpu_packages.last().unwrap().cpu_vec.len() {
let mut this_cpu_data : Vec<(f64, f64)> = Vec::new();
@@ -262,10 +266,24 @@ fn update_cpu_data_points(show_avg_cpu : bool, app_data : &data_collection::Data
for data in &app_data.list_of_cpu_packages {
let current_time = std::time::Instant::now();
let current_cpu_usage = data.cpu_vec[cpu_num].cpu_usage;
- this_cpu_data.push((
+
+ let new_entry = (
((STALE_MAX_MILLISECONDS as f64 - current_time.duration_since(data.instant).as_millis() as f64) * 10_f64).floor(),
current_cpu_usage,
- ));
+ );
+
+ // Now, inject our joining points...
+ if !this_cpu_data.is_empty() {
+ let previous_element_data = *(this_cpu_data.last().unwrap());
+ for idx in 0..100 {
+ this_cpu_data.push((
+ previous_element_data.0 + ((new_entry.0 - previous_element_data.0) / 100.0 * f64::from(idx)),
+ previous_element_data.1 + ((new_entry.1 - previous_element_data.1) / 100.0 * f64::from(idx)),
+ ));
+ }
+ }
+
+ this_cpu_data.push(new_entry);
}
cpu_collection.push(this_cpu_data);
@@ -298,11 +316,23 @@ fn convert_mem_data(mem_data : &[data_collection::mem::MemData]) -> Vec<(f64, f6
for data in mem_data {
let current_time = std::time::Instant::now();
-
- result.push((
+ let new_entry = (
((STALE_MAX_MILLISECONDS as f64 - current_time.duration_since(data.instant).as_millis() as f64) * 10_f64).floor(),
data.mem_used_in_mb as f64 / data.mem_total_in_mb as f64 * 100_f64,
- ));
+ );
+
+ // Now, inject our joining points...
+ if !result.is_empty() {
+ let previous_element_data = *(result.last().unwrap());
+ for idx in 0..100 {
+ result.push((
+ previous_element_data.0 + ((new_entry.0 - previous_element_data.0) / 100.0 * f64::from(idx)),
+ previous_element_data.1 + ((new_entry.1 - previous_element_data.1) / 100.0 * f64::from(idx)),
+ ));
+ }
+ }
+
+ result.push(new_entry);
//debug!("Pushed: ({}, {})", result.last().unwrap().0, result.last().unwrap().1);
}
@@ -312,6 +342,8 @@ fn convert_mem_data(mem_data : &[data_collection::mem::MemData]) -> Vec<(f64, f6
struct ConvertedNetworkData {
rx : Vec<(f64, f64)>,
tx : Vec<(f64, f64)>,
+ rx_display : String,
+ tx_display : String,
}
fn update_network_data_points(app_data : &data_collection::Data) -> ConvertedNetworkData {
@@ -324,20 +356,80 @@ fn convert_network_data_points(network_data : &[data_collection::network::Networ
for data in network_data {
let current_time = std::time::Instant::now();
-
- rx.push((
+ let rx_data = (
((STALE_MAX_MILLISECONDS as f64 - current_time.duration_since(data.instant).as_millis() as f64) * 10_f64).floor(),
data.rx as f64 / 1024.0,
- ));
-
- tx.push((
+ );
+ let tx_data = (
((STALE_MAX_MILLISECONDS as f64 - current_time.duration_since(data.instant).as_millis() as f64) * 10_f64).floor(),
data.tx as f64 / 1024.0,
- ));
+ );
+
+ // Now, inject our joining points...
+ if !rx.is_empty() {
+ let previous_element_data = *(rx.last().unwrap());
+ for idx in 0..100 {
+ rx.push((
+ previous_element_data.0 + ((rx_data.0 - previous_element_data.0) / 100.0 * f64::from(idx)),
+ previous_element_data.1 + ((rx_data.1 - previous_element_data.1) / 100.0 * f64::from(idx)),
+ ));
+ }
+ }
+
+ // Now, inject our joining points...
+ if !tx.is_empty() {
+ let previous_element_data = *(tx.last().unwrap());
+ for idx in 0..100 {
+ tx.push((
+ previous_element_data.0 + ((tx_data.0 - previous_element_data.0) / 100.0 * f64::from(idx)),
+ previous_element_data.1 + ((tx_data.1 - previous_element_data.1) / 100.0 * f64::from(idx)),
+ ));
+ }
+ }
+
+ rx.push(rx_data);
+ tx.push(tx_data);
debug!("Pushed rx: ({}, {})", rx.last().unwrap().0, rx.last().unwrap().1);
debug!("Pushed tx: ({}, {})", tx.last().unwrap().0, tx.last().unwrap().1);
}
- ConvertedNetworkData { rx, tx }
+ let rx_display = if network_data.is_empty() {
+ "0B".to_string()
+ }
+ else {
+ let num_bytes = network_data.last().unwrap().rx;
+ if num_bytes < 1024 {
+ format!("RX: {:4} B", num_bytes).to_string()
+ }
+ else if num_bytes < (1024 * 1024) {
+ format!("RX: {:4}KB", num_bytes / 1024).to_string()
+ }
+ else if num_bytes < (1024 * 1024 * 1024) {
+ format!("RX: {:4}MB", num_bytes / 1024 / 1024).to_string()
+ }
+ else {
+ format!("RX: {:4}GB", num_bytes / 1024 / 1024 / 1024).to_string()
+ }
+ };
+ let tx_display = if network_data.is_empty() {
+ "0B".to_string()
+ }
+ else {
+ let num_bytes = network_data.last().unwrap().tx;
+ if num_bytes < 1024 {
+ format!("TX: {:4} B", num_bytes).to_string()
+ }
+ else if num_bytes < (1024 * 1024) {
+ format!("TX: {:4}KB", num_bytes / 1024).to_string()
+ }
+ else if num_bytes < (1024 * 1024 * 1024) {
+ format!("TX: {:4}MB", num_bytes / 1024 / 1024).to_string()
+ }
+ else {
+ format!("TX: {:4}GB", num_bytes / 1024 / 1024 / 1024).to_string()
+ }
+ };
+
+ ConvertedNetworkData { rx, tx, rx_display, tx_display }
}