From b22c07aba27f3d0f72568250139000f36bc1a8b9 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Wed, 1 Jan 2020 23:39:47 -0500 Subject: [PATCH] Added dialog for dd, added error message if fail to dd, cleaned up some stuff --- src/app.rs | 214 +++++++++++++++++++++++++------------- src/app/process_killer.rs | 13 ++- src/canvas.rs | 151 ++++++++++++++++----------- src/data_conversion.rs | 37 +++++-- src/main.rs | 42 ++++---- 5 files changed, 289 insertions(+), 168 deletions(-) diff --git a/src/app.rs b/src/app.rs index 1780ad9b..6764c594 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,7 +2,7 @@ pub mod data_collection; use data_collection::{processes, temperature}; use std::time::Instant; -use crate::constants; +use crate::{canvas, constants, data_conversion::ConvertedProcessData, utils::error::Result}; mod process_killer; @@ -47,10 +47,14 @@ pub struct App { second_char: char, pub use_dot: bool, pub show_help: bool, + pub show_dd: bool, + pub dd_err: Option, + to_delete_process: Option, pub is_frozen: bool, pub left_legend: bool, pub use_current_cpu_total: bool, last_key_press: Instant, + pub canvas_data: canvas::CanvasData, } impl App { @@ -80,15 +84,23 @@ impl App { second_char: ' ', use_dot, show_help: false, + show_dd: false, + dd_err: None, + to_delete_process: None, is_frozen: false, left_legend, use_current_cpu_total, last_key_press: Instant::now(), + canvas_data: canvas::CanvasData::default(), } } pub fn reset(&mut self) { self.reset_multi_tap_keys(); + self.show_help = false; + self.show_dd = false; + self.to_delete_process = None; + self.dd_err = None; } fn reset_multi_tap_keys(&mut self) { @@ -96,18 +108,30 @@ impl App { self.second_char = ' '; } - pub fn on_enter(&mut self) {} - - pub fn on_esc(&mut self) { - if self.show_help { - self.show_help = false; - } - self.reset_multi_tap_keys(); + fn is_in_dialog(&self) -> bool { + self.show_help || self.show_dd } - // TODO: How should we make it for process panel specific hotkeys? Only if we're on process panel? Or what? - pub fn on_key(&mut self, caught_char: char) { - if !self.show_help { + /// One of two functions allowed to run while in a dialog... + pub fn on_enter(&mut self) { + if self.show_dd { + // If within dd... + if self.dd_err.is_none() { + // Also ensure that we didn't just fail a dd... + let dd_result = self.kill_highlighted_process(); + if let Err(dd_err) = dd_result { + // There was an issue... inform the user... + self.dd_err = Some(dd_err.to_string()); + } else { + self.show_dd = false; + } + } + } + } + + pub fn on_char_key(&mut self, caught_char: char) { + // Forbid any char key presses when showing a dialog box... + if !self.is_in_dialog() { let current_key_press_inst = Instant::now(); if current_key_press_inst.duration_since(self.last_key_press).as_millis() > constants::MAX_KEY_TIMEOUT_IN_MILLISECONDS { self.reset_multi_tap_keys(); @@ -120,7 +144,11 @@ impl App { if self.awaiting_second_char && self.second_char == 'd' { self.awaiting_second_char = false; self.second_char = ' '; - self.kill_highlighted_process().unwrap_or(()); // TODO: Return error to user? We have a dialog box... + + let current_process = &self.canvas_data.process_data[self.currently_selected_process_position as usize]; + self.to_delete_process = Some(current_process.clone()); + self.show_dd = true; + self.reset_multi_tap_keys(); } else { self.awaiting_second_char = true; self.second_char = 'd'; @@ -196,12 +224,21 @@ impl App { } } - fn kill_highlighted_process(&self) -> crate::utils::error::Result<()> { - let current_pid = u64::from(self.data.list_of_processes[self.currently_selected_process_position as usize].pid); - process_killer::kill_process_given_pid(current_pid)?; + pub fn kill_highlighted_process(&mut self) -> Result<()> { + // Technically unnecessary but this is a good check... + if let ApplicationPosition::Process = self.current_application_position { + if let Some(current_selected_process) = &(self.to_delete_process) { + process_killer::kill_process_given_pid(current_selected_process.pid)?; + } + self.to_delete_process = None; + } Ok(()) } + pub fn get_current_highlighted_process(&self) -> Option { + self.to_delete_process.clone() + } + // For now, these are hard coded --- in the future, they shouldn't be! // // General idea for now: @@ -212,91 +249,118 @@ impl App { // Network -(up)> MEM, -(right)> PROC // PROC -(up)> Disk, -(left)> Network pub fn on_left(&mut self) { - self.current_application_position = match self.current_application_position { - ApplicationPosition::Process => ApplicationPosition::Network, - ApplicationPosition::Disk => ApplicationPosition::Mem, - ApplicationPosition::Temp => ApplicationPosition::Mem, - _ => self.current_application_position, - }; - self.reset_multi_tap_keys(); + if !self.is_in_dialog() { + self.current_application_position = match self.current_application_position { + ApplicationPosition::Process => ApplicationPosition::Network, + ApplicationPosition::Disk => ApplicationPosition::Mem, + ApplicationPosition::Temp => ApplicationPosition::Mem, + _ => self.current_application_position, + }; + self.reset_multi_tap_keys(); + } } pub fn on_right(&mut self) { - self.current_application_position = match self.current_application_position { - ApplicationPosition::Mem => ApplicationPosition::Temp, - ApplicationPosition::Network => ApplicationPosition::Process, - _ => self.current_application_position, - }; - self.reset_multi_tap_keys(); + if !self.is_in_dialog() { + self.current_application_position = match self.current_application_position { + ApplicationPosition::Mem => ApplicationPosition::Temp, + ApplicationPosition::Network => ApplicationPosition::Process, + _ => self.current_application_position, + }; + self.reset_multi_tap_keys(); + } } pub fn on_up(&mut self) { - self.current_application_position = match self.current_application_position { - ApplicationPosition::Mem => ApplicationPosition::Cpu, - ApplicationPosition::Network => ApplicationPosition::Mem, - ApplicationPosition::Process => ApplicationPosition::Disk, - ApplicationPosition::Temp => ApplicationPosition::Cpu, - ApplicationPosition::Disk => ApplicationPosition::Temp, - _ => self.current_application_position, - }; - self.reset_multi_tap_keys(); + if !self.is_in_dialog() { + self.current_application_position = match self.current_application_position { + ApplicationPosition::Mem => ApplicationPosition::Cpu, + ApplicationPosition::Network => ApplicationPosition::Mem, + ApplicationPosition::Process => ApplicationPosition::Disk, + ApplicationPosition::Temp => ApplicationPosition::Cpu, + ApplicationPosition::Disk => ApplicationPosition::Temp, + _ => self.current_application_position, + }; + self.reset_multi_tap_keys(); + } } pub fn on_down(&mut self) { - self.current_application_position = match self.current_application_position { - ApplicationPosition::Cpu => ApplicationPosition::Mem, - ApplicationPosition::Mem => ApplicationPosition::Network, - ApplicationPosition::Temp => ApplicationPosition::Disk, - ApplicationPosition::Disk => ApplicationPosition::Process, - _ => self.current_application_position, - }; - self.reset_multi_tap_keys(); + if !self.is_in_dialog() { + self.current_application_position = match self.current_application_position { + ApplicationPosition::Cpu => ApplicationPosition::Mem, + ApplicationPosition::Mem => ApplicationPosition::Network, + ApplicationPosition::Temp => ApplicationPosition::Disk, + ApplicationPosition::Disk => ApplicationPosition::Process, + _ => self.current_application_position, + }; + self.reset_multi_tap_keys(); + } } pub fn skip_to_first(&mut self) { - match self.current_application_position { - ApplicationPosition::Process => self.currently_selected_process_position = 0, - ApplicationPosition::Temp => self.currently_selected_temperature_position = 0, - ApplicationPosition::Disk => self.currently_selected_disk_position = 0, - _ => {} + if !self.is_in_dialog() { + match self.current_application_position { + ApplicationPosition::Process => self.currently_selected_process_position = 0, + ApplicationPosition::Temp => self.currently_selected_temperature_position = 0, + ApplicationPosition::Disk => self.currently_selected_disk_position = 0, + ApplicationPosition::Cpu => self.currently_selected_cpu_table_position = 0, + + _ => {} + } + self.scroll_direction = ScrollDirection::UP; + self.reset_multi_tap_keys(); } - self.scroll_direction = ScrollDirection::UP; - self.reset_multi_tap_keys(); } pub fn skip_to_last(&mut self) { - match self.current_application_position { - ApplicationPosition::Process => self.currently_selected_process_position = self.data.list_of_processes.len() as i64 - 1, - ApplicationPosition::Temp => self.currently_selected_temperature_position = self.data.list_of_temperature_sensor.len() as i64 - 1, - ApplicationPosition::Disk => self.currently_selected_disk_position = self.data.list_of_disks.len() as i64 - 1, - _ => {} + if !self.is_in_dialog() { + match self.current_application_position { + ApplicationPosition::Process => self.currently_selected_process_position = self.data.list_of_processes.len() as i64 - 1, + ApplicationPosition::Temp => self.currently_selected_temperature_position = self.data.list_of_temperature_sensor.len() as i64 - 1, + ApplicationPosition::Disk => self.currently_selected_disk_position = self.data.list_of_disks.len() as i64 - 1, + ApplicationPosition::Cpu => { + if let Some(cpu_package) = self.data.list_of_cpu_packages.last() { + if self.show_average_cpu { + self.currently_selected_cpu_table_position = cpu_package.cpu_vec.len() as i64; + } else { + self.currently_selected_cpu_table_position = cpu_package.cpu_vec.len() as i64 - 1; + } + } + } + _ => {} + } + self.scroll_direction = ScrollDirection::DOWN; + self.reset_multi_tap_keys(); } - self.scroll_direction = ScrollDirection::DOWN; - self.reset_multi_tap_keys(); } pub fn decrement_position_count(&mut self) { - match self.current_application_position { - ApplicationPosition::Process => self.change_process_position(-1), - ApplicationPosition::Temp => self.change_temp_position(-1), - ApplicationPosition::Disk => self.change_disk_position(-1), - ApplicationPosition::Cpu => self.change_cpu_table_position(-1), // TODO: Temporary, may change if we add scaling - _ => {} + if !self.is_in_dialog() { + match self.current_application_position { + ApplicationPosition::Process => self.change_process_position(-1), + ApplicationPosition::Temp => self.change_temp_position(-1), + ApplicationPosition::Disk => self.change_disk_position(-1), + ApplicationPosition::Cpu => self.change_cpu_table_position(-1), // TODO: Temporary, may change if we add scaling + _ => {} + } + self.scroll_direction = ScrollDirection::UP; + self.reset_multi_tap_keys(); } - self.scroll_direction = ScrollDirection::UP; - self.reset_multi_tap_keys(); } pub fn increment_position_count(&mut self) { - match self.current_application_position { - ApplicationPosition::Process => self.change_process_position(1), - ApplicationPosition::Temp => self.change_temp_position(1), - ApplicationPosition::Disk => self.change_disk_position(1), - ApplicationPosition::Cpu => self.change_cpu_table_position(1), // TODO: Temporary, may change if we add scaling - _ => {} + if !self.is_in_dialog() { + match self.current_application_position { + ApplicationPosition::Process => self.change_process_position(1), + ApplicationPosition::Temp => self.change_temp_position(1), + ApplicationPosition::Disk => self.change_disk_position(1), + ApplicationPosition::Cpu => self.change_cpu_table_position(1), // TODO: Temporary, may change if we add scaling + _ => {} + } + self.scroll_direction = ScrollDirection::DOWN; + self.reset_multi_tap_keys(); } - self.scroll_direction = ScrollDirection::DOWN; - self.reset_multi_tap_keys(); } fn change_cpu_table_position(&mut self, num_to_change_by: i64) { diff --git a/src/app/process_killer.rs b/src/app/process_killer.rs index b6793f39..34ec0a99 100644 --- a/src/app/process_killer.rs +++ b/src/app/process_killer.rs @@ -1,8 +1,7 @@ /// This file is meant to house (OS specific) implementations on how to kill processes. +use crate::utils::error::{BottomError, Result}; use std::process::Command; -// TODO: Make it update process list on freeze. - // Copied from SO: https://stackoverflow.com/a/55231715 #[cfg(target_os = "windows")] use winapi::{ @@ -33,7 +32,7 @@ impl Process { } /// Kills a process, given a PID. -pub fn kill_process_given_pid(pid: u64) -> crate::utils::error::Result<()> { +pub fn kill_process_given_pid(pid: u32) -> Result<()> { if cfg!(target_os = "linux") { // Linux Command::new("kill").arg(pid.to_string()).output()?; @@ -45,10 +44,14 @@ pub fn kill_process_given_pid(pid: u64) -> crate::utils::error::Result<()> { } else if cfg!(target_os = "macos") { // TODO: macOS // See how sysinfo does it... https://docs.rs/sysinfo/0.9.5/sysinfo/trait.ProcessExt.html - debug!("Sorry, macOS support is not implemented yet!"); + return Err(BottomError::GenericError { + message: "Sorry, macOS support is not implemented yet!".to_string(), + }); } else { // TODO: Others? - debug!("Sorry, other support this is not implemented yet!"); + return Err(BottomError::GenericError { + message: "Sorry, support operating systems outside the main three is not implemented yet!".to_string(), + }); } Ok(()) diff --git a/src/canvas.rs b/src/canvas.rs index 9f3288d3..bdc1b46a 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -1,4 +1,4 @@ -use crate::{app, constants, utils::error, utils::gen_util::*}; +use crate::{app, constants, data_conversion::ConvertedProcessData, utils::error, utils::gen_util::*}; use tui::{ backend, layout::{Alignment, Constraint, Direction, Layout, Rect}, @@ -46,7 +46,7 @@ pub struct CanvasData { pub network_data_tx: Vec<(f64, f64)>, pub disk_data: Vec>, pub temp_sensor_data: Vec>, - pub process_data: Vec>, + pub process_data: Vec, pub memory_labels: Vec<(u64, u64)>, pub mem_data: Vec<(f64, f64)>, pub swap_data: Vec<(f64, f64)>, @@ -93,11 +93,11 @@ fn gen_n_colours(num_to_gen: i32) -> Vec { colour_vec } -pub fn draw_data(terminal: &mut Terminal, app_state: &mut app::App, canvas_data: &CanvasData) -> error::Result<()> { +pub fn draw_data(terminal: &mut Terminal, app_state: &mut app::App) -> error::Result<()> { terminal.autoresize()?; terminal.draw(|mut f| { if app_state.show_help { - // Only for the dialog (help, dd) menus + // Only for the help let vertical_dialog_chunk = Layout::default() .direction(Direction::Vertical) .margin(1) @@ -116,6 +116,52 @@ pub fn draw_data(terminal: &mut Terminal, app_state: &mu .alignment(Alignment::Left) .wrap(true) .render(&mut f, middle_dialog_chunk[1]); + } else if app_state.show_dd { + let vertical_dialog_chunk = Layout::default() + .direction(Direction::Vertical) + .margin(1) + .constraints([Constraint::Percentage(40), Constraint::Percentage(20), Constraint::Percentage(40)].as_ref()) + .split(f.size()); + + let middle_dialog_chunk = Layout::default() + .direction(Direction::Horizontal) + .margin(0) + .constraints([Constraint::Percentage(30), Constraint::Percentage(40), Constraint::Percentage(30)].as_ref()) + .split(vertical_dialog_chunk[1]); + + if let Some(dd_err) = app_state.dd_err.clone() { + let dd_text = [Text::raw(format!("\nFailure to properly kill the process - {}", dd_err))]; + + Paragraph::new(dd_text.iter()) + .block(Block::default().title("Kill Process Error (Press Esc to close)").borders(Borders::ALL)) + .style(Style::default().fg(Color::Gray)) + .alignment(Alignment::Center) + .wrap(true) + .render(&mut f, middle_dialog_chunk[1]); + } else if let Some(process) = app_state.get_current_highlighted_process() { + let dd_text = [ + Text::raw(format!( + "\nAre you sure you want to kill process {} with PID {}?", + process.name, process.pid + )), + Text::raw("\n\nPress ENTER to proceed, ESC to exit."), + Text::raw("\nNote that if bottom is frozen, it must be unfrozen for changes to be shown."), + ]; + + Paragraph::new(dd_text.iter()) + .block( + Block::default() + .title("Kill Process Confirmation (Press Esc to close)") + .borders(Borders::ALL), + ) + .style(Style::default().fg(Color::Gray)) + .alignment(Alignment::Center) + .wrap(true) + .render(&mut f, middle_dialog_chunk[1]); + } else { + // This is a bit nasty, but it works well... I guess. + app_state.show_dd = false; + } } else { let vertical_chunks = Layout::default() .direction(Direction::Vertical) @@ -174,27 +220,18 @@ pub fn draw_data(terminal: &mut Terminal, app_state: &mu // Set up blocks and their components // CPU graph - draw_cpu_graph(&mut f, &app_state, &canvas_data.cpu_data, cpu_chunk[graph_index]); + draw_cpu_graph(&mut f, &app_state, cpu_chunk[graph_index]); // CPU legend - draw_cpu_legend(&mut f, app_state, &canvas_data.cpu_data, cpu_chunk[legend_index]); + draw_cpu_legend(&mut f, app_state, cpu_chunk[legend_index]); //Memory usage graph - draw_memory_graph( - &mut f, - &app_state, - &canvas_data.memory_labels, - &canvas_data.mem_data, - &canvas_data.swap_data, - middle_chunks[0], - ); + draw_memory_graph(&mut f, &app_state, middle_chunks[0]); // Network graph draw_network_graph( &mut f, &app_state, - &canvas_data.network_data_rx, - &canvas_data.network_data_tx, if cfg!(not(target_os = "windows")) { network_chunk[0] } else { @@ -202,45 +239,26 @@ pub fn draw_data(terminal: &mut Terminal, app_state: &mu }, ); - if cfg!(not(target_os = "windows")) { - draw_network_labels( - &mut f, - app_state, - canvas_data.rx_display.clone(), - canvas_data.tx_display.clone(), - canvas_data.total_rx_display.clone(), - canvas_data.total_tx_display.clone(), - network_chunk[1], - ); - } else { - draw_network_labels( - &mut f, - app_state, - canvas_data.rx_display.clone(), - canvas_data.tx_display.clone(), - "N/A".to_string(), - "N/A".to_string(), - network_chunk[1], - ); - } + draw_network_labels(&mut f, app_state, network_chunk[1]); // Temperature table - draw_temp_table(&mut f, app_state, &canvas_data.temp_sensor_data, middle_divided_chunk_2[0]); + draw_temp_table(&mut f, app_state, middle_divided_chunk_2[0]); // Disk usage table - draw_disk_table(&mut f, app_state, &canvas_data.disk_data, middle_divided_chunk_2[1]); + draw_disk_table(&mut f, app_state, middle_divided_chunk_2[1]); // Processes table - draw_processes_table(&mut f, app_state, &canvas_data.process_data, bottom_chunks[1]); + draw_processes_table(&mut f, app_state, bottom_chunks[1]); } })?; Ok(()) } -fn draw_cpu_graph(f: &mut Frame, app_state: &app::App, cpu_data: &[(String, Vec<(f64, f64)>)], draw_loc: Rect) { - // CPU usage graph +fn draw_cpu_graph(f: &mut Frame, app_state: &app::App, draw_loc: Rect) { + let cpu_data: &[(String, Vec<(f64, f64)>)] = &app_state.canvas_data.cpu_data; + // CPU usage graph let x_axis: Axis = Axis::default() .style(Style::default().fg(GRAPH_COLOUR)) .bounds([0.0, constants::TIME_STARTS_FROM as f64 * 10.0]); @@ -296,7 +314,9 @@ fn draw_cpu_graph(f: &mut Frame, app_state: &app::App, c .render(f, draw_loc); } -fn draw_cpu_legend(f: &mut Frame, app_state: &mut app::App, cpu_data: &[(String, Vec<(f64, f64)>)], draw_loc: Rect) { +fn draw_cpu_legend(f: &mut Frame, app_state: &mut app::App, draw_loc: Rect) { + let cpu_data: &[(String, Vec<(f64, f64)>)] = &(app_state.canvas_data.cpu_data); + let num_rows = i64::from(draw_loc.height) - 4; let start_position = get_start_position( num_rows, @@ -345,9 +365,11 @@ fn draw_cpu_legend(f: &mut Frame, app_state: &mut app::A .render(f, draw_loc); } -fn draw_memory_graph( - f: &mut Frame, app_state: &app::App, memory_labels: &[(u64, u64)], mem_data: &[(f64, f64)], swap_data: &[(f64, f64)], draw_loc: Rect, -) { +fn draw_memory_graph(f: &mut Frame, app_state: &app::App, draw_loc: Rect) { + let mem_data: &[(f64, f64)] = &(app_state.canvas_data.mem_data); + let swap_data: &[(f64, f64)] = &(app_state.canvas_data.swap_data); + let memory_labels: &[(u64, u64)] = &(app_state.canvas_data.memory_labels); + let x_axis: Axis = Axis::default() .style(Style::default().fg(GRAPH_COLOUR)) .bounds([0.0, constants::TIME_STARTS_FROM as f64 * 10.0]); @@ -408,9 +430,10 @@ fn draw_memory_graph( .render(f, draw_loc); } -fn draw_network_graph( - f: &mut Frame, app_state: &app::App, network_data_rx: &[(f64, f64)], network_data_tx: &[(f64, f64)], draw_loc: Rect, -) { +fn draw_network_graph(f: &mut Frame, app_state: &app::App, draw_loc: Rect) { + let network_data_rx: &[(f64, f64)] = &(app_state.canvas_data.network_data_rx); + let network_data_tx: &[(f64, f64)] = &(app_state.canvas_data.network_data_tx); + let x_axis: Axis = 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)) @@ -441,10 +464,12 @@ fn draw_network_graph( .render(f, draw_loc); } -fn draw_network_labels( - f: &mut Frame, app_state: &mut app::App, rx_display: String, tx_display: String, total_rx_display: String, total_tx_display: String, - draw_loc: Rect, -) { +fn draw_network_labels(f: &mut Frame, app_state: &mut app::App, draw_loc: Rect) { + let rx_display: String = app_state.canvas_data.rx_display.clone(); + let tx_display: String = app_state.canvas_data.tx_display.clone(); + let total_rx_display: String = app_state.canvas_data.total_rx_display.clone(); + let total_tx_display: String = app_state.canvas_data.total_tx_display.clone(); + // Gross but I need it to work... let total_network = vec![vec![rx_display, tx_display, total_rx_display, total_tx_display]]; let mapped_network = total_network.iter().map(|val| Row::Data(val.iter())); @@ -468,7 +493,9 @@ fn draw_network_labels( .render(f, draw_loc); } -fn draw_temp_table(f: &mut Frame, app_state: &mut app::App, temp_sensor_data: &[Vec], draw_loc: Rect) { +fn draw_temp_table(f: &mut Frame, app_state: &mut app::App, draw_loc: Rect) { + let temp_sensor_data: &[Vec] = &(app_state.canvas_data.temp_sensor_data); + let num_rows = i64::from(draw_loc.height) - 4; let start_position = get_start_position( num_rows, @@ -511,7 +538,8 @@ fn draw_temp_table(f: &mut Frame, app_state: &mut app::A .render(f, draw_loc); } -fn draw_disk_table(f: &mut Frame, app_state: &mut app::App, disk_data: &[Vec], draw_loc: Rect) { +fn draw_disk_table(f: &mut Frame, app_state: &mut app::App, draw_loc: Rect) { + let disk_data: &[Vec] = &(app_state.canvas_data.disk_data); let num_rows = i64::from(draw_loc.height) - 4; let start_position = get_start_position( num_rows, @@ -563,7 +591,8 @@ fn draw_disk_table(f: &mut Frame, app_state: &mut app::A .render(f, draw_loc); } -fn draw_processes_table(f: &mut Frame, app_state: &mut app::App, process_data: &[Vec], draw_loc: Rect) { +fn draw_processes_table(f: &mut Frame, app_state: &mut app::App, draw_loc: Rect) { + let process_data: &[ConvertedProcessData] = &(app_state.canvas_data.process_data); let width = f64::from(draw_loc.width); // Admittedly this is kinda a hack... but we need to: @@ -580,12 +609,18 @@ fn draw_processes_table(f: &mut Frame, app_state: &mut a &mut app_state.currently_selected_process_position, ); - let sliced_vec: Vec> = (&process_data[start_position as usize..]).to_vec(); + let sliced_vec: Vec = (&process_data[start_position as usize..]).to_vec(); let mut process_counter = 0; let process_rows = sliced_vec.iter().map(|process| { + let stringified_process_vec: Vec = vec![ + process.pid.to_string(), + process.name.clone(), + process.cpu_usage.clone(), + process.mem_usage.clone(), + ]; Row::StyledData( - process.iter(), + stringified_process_vec.into_iter(), if process_counter == app_state.currently_selected_process_position - start_position { process_counter = -1; Style::default().fg(Color::Black).bg(Color::Cyan) diff --git a/src/data_conversion.rs b/src/data_conversion.rs index 2648b96a..7bf688f8 100644 --- a/src/data_conversion.rs +++ b/src/data_conversion.rs @@ -5,6 +5,7 @@ use crate::{ }; use constants::*; +#[derive(Default, Debug)] pub struct ConvertedNetworkData { pub rx: Vec<(f64, f64)>, pub tx: Vec<(f64, f64)>, @@ -14,6 +15,14 @@ pub struct ConvertedNetworkData { pub total_tx_display: String, } +#[derive(Clone, Default, Debug)] +pub struct ConvertedProcessData { + pub pid: u32, + pub name: String, + pub cpu_usage: String, + pub mem_usage: String, +} + pub fn update_temp_row(app_data: &data_collection::Data, temp_type: &data_collection::temperature::TemperatureType) -> Vec> { let mut sensor_vector: Vec> = Vec::new(); @@ -84,15 +93,15 @@ pub fn update_disk_row(app_data: &data_collection::Data) -> Vec> { disk_vector } -pub fn update_process_row(app_data: &data_collection::Data) -> Vec> { - let mut process_vector: Vec> = Vec::new(); +pub fn update_process_row(app_data: &data_collection::Data) -> Vec { + let mut process_vector: Vec = Vec::new(); for process in &app_data.list_of_processes { - process_vector.push(vec![ - process.pid.to_string(), - process.command.to_string(), - format!("{:.1}%", process.cpu_usage_percent), - format!( + process_vector.push(ConvertedProcessData { + pid: process.pid, + name: process.command.to_string(), + cpu_usage: format!("{:.1}%", process.cpu_usage_percent), + mem_usage: format!( "{:.1}%", if let Some(mem_usage) = process.mem_usage_percent { mem_usage @@ -106,7 +115,7 @@ pub fn update_process_row(app_data: &data_collection::Data) -> Vec> 0_f64 } ), - ]); + }); } process_vector @@ -300,7 +309,11 @@ pub fn convert_network_data_points(network_data: &[data_collection::network::Net total_rx_converted_result = get_exact_byte_values(0, false); } let rx_display = format!("{:.*}{}", 1, rx_converted_result.0, rx_converted_result.1); - let total_rx_display = format!("{:.*}{}", 1, total_rx_converted_result.0, total_rx_converted_result.1); + let total_rx_display = if cfg!(not(target_os = "windows")) { + format!("{:.*}{}", 1, total_rx_converted_result.0, total_rx_converted_result.1) + } else { + "N/A".to_string() + }; if let Some(last_num_bytes_entry) = network_data.last() { tx_converted_result = get_exact_byte_values(last_num_bytes_entry.tx, false); @@ -310,7 +323,11 @@ pub fn convert_network_data_points(network_data: &[data_collection::network::Net total_tx_converted_result = get_exact_byte_values(0, false); } let tx_display = format!("{:.*}{}", 1, tx_converted_result.0, tx_converted_result.1); - let total_tx_display = format!("{:.*}{}", 1, total_tx_converted_result.0, total_tx_converted_result.1); + let total_tx_display = if cfg!(not(target_os = "windows")) { + format!("{:.*}{}", 1, total_tx_converted_result.0, total_tx_converted_result.1) + } else { + "N/A".to_string() + }; ConvertedNetworkData { rx, diff --git a/src/main.rs b/src/main.rs index dc54281e..f24eca96 100644 --- a/src/main.rs +++ b/src/main.rs @@ -177,7 +177,7 @@ fn main() -> error::Result<()> { if let Ok(message) = rrx.try_recv() { match message { ResetEvent::Reset => { - debug!("Received reset message"); + //debug!("Received reset message"); first_run = true; data_state.data = app::data_collection::Data::default(); } @@ -197,7 +197,6 @@ fn main() -> error::Result<()> { }); } - let mut canvas_data = canvas::CanvasData::default(); loop { if let Ok(recv) = rx.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) { match recv { @@ -213,8 +212,9 @@ fn main() -> error::Result<()> { KeyCode::Char('j') => app.on_down(), KeyCode::Up => app.decrement_position_count(), KeyCode::Down => app.increment_position_count(), - KeyCode::Char(uncaught_char) => app.on_key(uncaught_char), - KeyCode::Esc => app.on_esc(), + KeyCode::Char(uncaught_char) => app.on_char_key(uncaught_char), + KeyCode::Esc => app.reset(), + KeyCode::Enter => app.on_enter(), _ => {} } } else { @@ -260,7 +260,7 @@ fn main() -> error::Result<()> { &app.process_sorting_type, app.process_sorting_reverse, ); - canvas_data.process_data = update_process_row(&app.data); + app.canvas_data.process_data = update_process_row(&app.data); app.to_be_resorted = false; } } @@ -270,6 +270,8 @@ fn main() -> error::Result<()> { _ => {} }, Event::Update(data) => { + // NOTE TO SELF - data is refreshed into app state HERE! That means, if it is + // frozen, then, app.data is never refreshed, until unfrozen! if !app.is_frozen { app.data = *data; @@ -280,28 +282,28 @@ fn main() -> error::Result<()> { ); // Convert all data into tui components + // TODO: Note that we might want to move this the canvas' side... consider. 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.total_rx_display = network_data.total_rx_display; - canvas_data.total_tx_display = network_data.total_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); - canvas_data.mem_data = update_mem_data_points(&app.data); - canvas_data.memory_labels = update_mem_data_values(&app.data); - canvas_data.swap_data = update_swap_data_points(&app.data); - canvas_data.cpu_data = update_cpu_data_points(app.show_average_cpu, &app.data); - + app.canvas_data.network_data_rx = network_data.rx; + app.canvas_data.network_data_tx = network_data.tx; + app.canvas_data.rx_display = network_data.rx_display; + app.canvas_data.tx_display = network_data.tx_display; + app.canvas_data.total_rx_display = network_data.total_rx_display; + app.canvas_data.total_tx_display = network_data.total_tx_display; + app.canvas_data.disk_data = update_disk_row(&app.data); + app.canvas_data.temp_sensor_data = update_temp_row(&app.data, &app.temperature_type); + app.canvas_data.process_data = update_process_row(&app.data); + app.canvas_data.mem_data = update_mem_data_points(&app.data); + app.canvas_data.memory_labels = update_mem_data_values(&app.data); + app.canvas_data.swap_data = update_swap_data_points(&app.data); + app.canvas_data.cpu_data = update_cpu_data_points(app.show_average_cpu, &app.data); //debug!("Update event complete."); } } } } // Draw! - if let Err(err) = canvas::draw_data(&mut terminal, &mut app, &canvas_data) { + if let Err(err) = canvas::draw_data(&mut terminal, &mut app) { disable_raw_mode()?; execute!(terminal.backend_mut(), LeaveAlternateScreen)?; terminal.show_cursor()?;