diff options
author | ClementTsang <cjhtsang@uwaterloo.ca> | 2021-08-29 17:49:02 -0400 |
---|---|---|
committer | ClementTsang <cjhtsang@uwaterloo.ca> | 2021-08-29 19:33:13 -0400 |
commit | 1ec203caa23e2ff4ca3f4cd488d80ee32ee231e7 (patch) | |
tree | 8d04acc310d876469a1b2a2bc651d11c0121b2a6 | |
parent | 74293aa243b6e442c25619c62a85236871d20960 (diff) |
refactor: Add data updating to process widget
-rw-r--r-- | src/app.rs | 4 | ||||
-rw-r--r-- | src/app/data_farmer.rs | 15 | ||||
-rw-r--r-- | src/app/data_harvester/processes/unix.rs | 4 | ||||
-rw-r--r-- | src/app/widgets/base/sort_text_table.rs | 13 | ||||
-rw-r--r-- | src/app/widgets/base/text_table.rs | 8 | ||||
-rw-r--r-- | src/app/widgets/process.rs | 93 | ||||
-rw-r--r-- | src/data_conversion.rs | 49 |
7 files changed, 134 insertions, 52 deletions
@@ -123,9 +123,6 @@ pub struct AppState { pub is_expanded: bool, - #[cfg(target_family = "unix")] - pub user_table: processes::UserTable, - pub used_widgets: UsedWidgets, pub filters: DataFilters, pub app_config_fields: AppConfigFields, @@ -196,7 +193,6 @@ impl AppState { canvas_data: Default::default(), data_collection: Default::default(), is_expanded: Default::default(), - user_table: Default::default(), delete_dialog_state: Default::default(), help_dialog_state: Default::default(), cpu_state: Default::default(), diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index 931ab96f..f2d4c957 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -14,14 +14,17 @@ /// more points as this is used! use once_cell::sync::Lazy; -use std::{time::Instant, vec::Vec}; +use std::{cell::RefCell, collections::HashMap, time::Instant, vec::Vec}; use crate::{ data_harvester::{batteries, cpu, disks, memory, network, processes, temperature, Data}, utils::gen_util::{get_decimal_bytes, GIGA_LIMIT}, + Pid, }; use regex::Regex; +use super::data_harvester::processes::UserTable; + pub type TimeOffset = f64; pub type Value = f64; @@ -55,12 +58,15 @@ pub struct DataCollection { pub cpu_harvest: cpu::CpuHarvest, pub load_avg_harvest: cpu::LoadAvgHarvest, pub process_harvest: Vec<processes::ProcessHarvest>, + pub process_count_mapping: HashMap<String, Pid>, pub disk_harvest: Vec<disks::DiskHarvest>, pub io_harvest: disks::IoHarvest, pub io_labels_and_prev: Vec<((u64, u64), (u64, u64))>, pub io_labels: Vec<(String, String)>, pub temp_harvest: Vec<temperature::TempHarvest>, pub battery_harvest: Vec<batteries::BatteryHarvest>, + #[cfg(target_family = "unix")] + pub user_table: RefCell<UserTable>, } impl Default for DataCollection { @@ -75,12 +81,15 @@ impl Default for DataCollection { cpu_harvest: cpu::CpuHarvest::default(), load_avg_harvest: cpu::LoadAvgHarvest::default(), process_harvest: Vec::default(), + process_count_mapping: HashMap::default(), disk_harvest: Vec::default(), io_harvest: disks::IoHarvest::default(), io_labels_and_prev: Vec::default(), io_labels: Vec::default(), temp_harvest: Vec::default(), battery_harvest: Vec::default(), + #[cfg(target_family = "unix")] + user_table: RefCell::new(UserTable::default()), } } } @@ -98,6 +107,10 @@ impl DataCollection { self.io_labels_and_prev = Vec::default(); self.temp_harvest = Vec::default(); self.battery_harvest = Vec::default(); + #[cfg(target_family = "unix")] + { + *self.user_table.borrow_mut() = UserTable::default(); + } } pub fn set_frozen_time(&mut self) { diff --git a/src/app/data_harvester/processes/unix.rs b/src/app/data_harvester/processes/unix.rs index 8fadc590..a563c88a 100644 --- a/src/app/data_harvester/processes/unix.rs +++ b/src/app/data_harvester/processes/unix.rs @@ -1,10 +1,12 @@ //! Unix-specific parts of process collection. +use std::collections::HashMap; + use crate::utils::error; #[derive(Debug, Default)] pub struct UserTable { - pub uid_user_mapping: std::collections::HashMap<libc::uid_t, String>, + pub uid_user_mapping: HashMap<libc::uid_t, String>, } impl UserTable { diff --git a/src/app/widgets/base/sort_text_table.rs b/src/app/widgets/base/sort_text_table.rs index 4a60504a..e5d8c8a2 100644 --- a/src/app/widgets/base/sort_text_table.rs +++ b/src/app/widgets/base/sort_text_table.rs @@ -266,6 +266,14 @@ where self.table.current_index() } + pub fn columns(&self) -> &[S] { + &self.table.columns + } + + pub fn set_column(&mut self, column: S, index: usize) { + self.table.set_column(index, column) + } + fn set_sort_index(&mut self, new_index: usize) { if new_index == self.sort_index { if let Some(column) = self.table.columns.get_mut(self.sort_index) { @@ -313,11 +321,6 @@ where self.table .draw_tui_table(painter, f, data, block, block_area, show_selected_entry); } - - /// Creates a [`Table`] representing the sort list. - pub fn create_sort_list(&mut self) -> (Table<'_>, TableState) { - todo!() - } } impl<S> Component for SortableTextTable<S> diff --git a/src/app/widgets/base/text_table.rs b/src/app/widgets/base/text_table.rs index 3ce3092d..2eaf444c 100644 --- a/src/app/widgets/base/text_table.rs +++ b/src/app/widgets/base/text_table.rs @@ -169,18 +169,18 @@ where self } - pub fn displayed_column_names(&self) -> Vec<Cow<'static, str>> { + fn displayed_column_names(&self) -> Vec<Cow<'static, str>> { self.columns .iter() .map(|column| column.display_name()) .collect() } - pub fn update_num_items(&mut self, num_items: usize) { + pub fn set_num_items(&mut self, num_items: usize) { self.scrollable.update_num_items(num_items); } - pub fn update_single_column(&mut self, index: usize, column: C) { + pub fn set_column(&mut self, index: usize, column: C) { if let Some(c) = self.columns.get_mut(index) { *c = column; } @@ -360,7 +360,7 @@ where 1 }; - self.update_num_items(data.len()); + self.set_num_items(data.len()); self.set_bounds(inner_area); let table_extras = 1 + table_gap; let scrollable_height = inner_area.height.saturating_sub(table_extras); diff --git a/src/app/widgets/process.rs b/src/app/widgets/process.rs index 1d86f02c..c4c4651e 100644 --- a/src/app/widgets/process.rs +++ b/src/app/widgets/process.rs @@ -17,8 +17,10 @@ use crate::{ DataCollection, }, canvas::Painter, + data_conversion::{get_disk_io_strings, get_string_with_bytes}, data_harvester::processes::{self, ProcessSorting}, options::ProcessDefaults, + utils::gen_util::{get_binary_bytes, GIBI_LIMIT}, }; use ProcessSorting::*; @@ -706,7 +708,7 @@ impl ProcessSortType { match self { ProcessSortType::Pid => Hard(Some(7)), ProcessSortType::Count => Hard(Some(8)), - ProcessSortType::Name => Flex(0.3), + ProcessSortType::Name => Flex(0.4), ProcessSortType::Command => Flex(0.7), ProcessSortType::Cpu => Hard(Some(8)), ProcessSortType::Mem => Hard(Some(8)), @@ -715,8 +717,8 @@ impl ProcessSortType { ProcessSortType::Wps => Hard(Some(8)), ProcessSortType::TotalRead => Hard(Some(7)), ProcessSortType::TotalWrite => Hard(Some(8)), - ProcessSortType::User => Flex(0.1), - ProcessSortType::State => Flex(0.2), + ProcessSortType::User => Flex(0.075), + ProcessSortType::State => Hard(Some(1)), } } @@ -1078,5 +1080,88 @@ impl Widget for ProcessManager { .draw_tui_table(painter, f, &self.display_data, block, area, selected); } - fn update_data(&mut self, data_collection: &DataCollection) {} + fn update_data(&mut self, data_collection: &DataCollection) { + self.display_data = data_collection + .process_harvest + .iter() + .filter_map(|process| { + let row = self + .process_table + .columns() + .iter() + .map(|column| match &column.sort_type { + ProcessSortType::Pid => (process.pid.to_string().into(), None, None), + ProcessSortType::Count => ("".into(), None, None), + ProcessSortType::Name => (process.name.clone().into(), None, None), + ProcessSortType::Command => (process.command.clone().into(), None, None), + ProcessSortType::Cpu => ( + format!("{:.1}%", process.cpu_usage_percent).into(), + None, + None, + ), + ProcessSortType::Mem => ( + get_string_with_bytes(process.mem_usage_bytes).into(), + None, + None, + ), + ProcessSortType::MemPercent => ( + format!("{:.1}%", process.mem_usage_percent).into(), + None, + None, + ), + ProcessSortType::Rps => ( + get_string_with_bytes(process.read_bytes_per_sec).into(), + None, + None, + ), + ProcessSortType::Wps => ( + get_string_with_bytes(process.write_bytes_per_sec).into(), + None, + None, + ), + ProcessSortType::TotalRead => ( + get_string_with_bytes(process.total_read_bytes).into(), + None, + None, + ), + ProcessSortType::TotalWrite => ( + get_string_with_bytes(process.total_write_bytes).into(), + None, + None, + ), + ProcessSortType::User => { + let user = { + #[cfg(target_family = "unix")] + { + if let Some(uid) = process.uid { + data_collection + .user_table + .borrow_mut() + .get_uid_to_username_mapping(uid) + .map(|s| s.into()) + .unwrap_or("N/A".into()) + } else { + "N/A".into() + } + } + #[cfg(not(target_family = "unix"))] + { + "N/A".into() + } + }; + + (user, None, None) + } + ProcessSortType::State => ( + process.process_state.clone().into(), + Some(process.process_state_char.to_string().into()), + None, + ), + }) + .collect::<Vec<_>>(); + + Some(row) + }) + .collect::<Vec<_>>(); + } } diff --git a/src/data_conversion.rs b/src/data_conversion.rs index de593952..61422b66 100644 --- a/src/data_conversion.rs +++ b/src/data_conversion.rs @@ -573,45 +573,28 @@ pub enum ProcessNamingType { } /// Given read/s, write/s, total read, and total write values, return 4 strings that represent read/s, write/s, total read, and total write -fn get_disk_io_strings( +pub fn get_disk_io_strings( rps: u64, wps: u64, total_read: u64, total_write: u64, ) -> (String, String, String, String) { - // Note we always use bytes for total read/write here (for now). - let converted_rps = get_decimal_bytes(rps); - let converted_wps = get_decimal_bytes(wps); - let converted_total_read = get_decimal_bytes(total_read); - let converted_total_write = get_decimal_bytes(total_write); - ( - if rps >= GIGA_LIMIT { - format!("{:.*}{}/s", 1, converted_rps.0, converted_rps.1) - } else { - format!("{:.*}{}/s", 0, converted_rps.0, converted_rps.1) - }, - if wps >= GIGA_LIMIT { - format!("{:.*}{}/s", 1, converted_wps.0, converted_wps.1) - } else { - format!("{:.*}{}/s", 0, converted_wps.0, converted_wps.1) - }, - if total_read >= GIGA_LIMIT { - format!("{:.*}{}", 1, converted_total_read.0, converted_total_read.1) - } else { - format!("{:.*}{}", 0, converted_total_read.0, converted_total_read.1) - }, - if total_write >= GIGA_LIMIT { - format!( - "{:.*}{}", - 1, converted_total_write.0, converted_total_write.1 - ) - } else { - format!( - "{:.*}{}", - 0, converted_total_write.0, converted_total_write.1 - ) - }, + get_string_with_bytes(rps), + get_string_with_bytes(wps), + get_string_with_bytes(total_read), + get_string_with_bytes(total_write), ) } +/// Returns a string given a value that is converted to the closest SI-variant. +/// If the value is greater than a giga-X, then it will return a decimal place. +pub fn get_string_with_bytes(value: u64) -> String { + let converted_values = get_decimal_bytes(value); + if value >= GIGA_LIMIT { + format!("{:.*}{}/s", 1, converted_values.0, converted_values.1) + } else { + format!("{:.*}{}/s", 0, converted_values.0, converted_values.1) + } +} + /// Because we needed to UPDATE data entries rather than REPLACING entries, we instead update /// the existing vector. pub fn convert_process_data( |