summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO.md32
-rw-r--r--src/app.rs62
-rw-r--r--src/app/data_collection/processes.rs8
-rw-r--r--src/canvas.rs22
-rw-r--r--src/constants.rs3
-rw-r--r--src/convert_data.rs260
-rw-r--r--src/main.rs346
7 files changed, 428 insertions, 305 deletions
diff --git a/TODO.md b/TODO.md
index c0e2a653..0db24577 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,5 +1,7 @@
# To-Do List
+## Pre-release (bare minimum)
+
* ~~Get each function working as a POC~~
* ~~Separate each component for readability, finalize project structure~~
@@ -8,24 +10,36 @@
* ~~Write tui display, charting~~
-* Scaling in and out
+* ~~FIX PROCESSES AHHHHHH~~
-* Add custom error because it's really messy
+* Scrolling in at least processes
-* Remove any ``unwrap()``.
+* Keybindings
-* Scrolling event
+## After making public
-* Keybindings
+* Scaling in and out (zoom), may need to show zoom levels
+
+* It would be maybe a good idea to see if we can run the process calculation across ALL cpus...?
+
+* ~~Add custom error because it's really messy~~ Done, but need to implement across rest of app!
+
+* Remove any ``unwrap()``, ensure no crashing!
-~~* FIX PROCESSES AHHHHHH~~
+* Scrolling event in lists
+
+* Switching between panels
+
+* Truncate columns if needed for tables
* Refactor everything because it's a mess
-* Test for Windows support, mac support
+* Test for Windows support, mac support, other. May be doable, depends on sysinfo and how much I know about other OSes probably.
* Efficiency!!!
-* Potentially process managing? Depends on the libraries...
+* Filtering in processes (that is, allow searching)
-* Filtering in processes (ie: search)
+* Help screen
+
+* Potentially process managing? Depends on the libraries...
diff --git a/src/app.rs b/src/app.rs
index 743b1f2c..2461a188 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,15 +1,30 @@
pub mod data_collection;
use data_collection::{processes, temperature};
+#[allow(dead_code)]
+// Probably only use the list elements...
+pub enum ApplicationPosition {
+ CPU,
+ MEM,
+ DISK,
+ TEMP,
+ NETWORK,
+ PROCESS,
+}
+
pub struct App {
pub should_quit : bool,
pub process_sorting_type : processes::ProcessSorting,
pub process_sorting_reverse : bool,
pub to_be_resorted : bool,
- pub current_selected_process_position : u64,
+ pub currently_selected_process_position : u64,
+ pub currently_selected_disk_position : u64,
+ pub currently_selected_temperature_position : u64,
pub temperature_type : temperature::TemperatureType,
pub update_rate_in_milliseconds : u64,
pub show_average_cpu : bool,
+ pub current_application_position : ApplicationPosition,
+ pub current_zoom_level_percent : f64, // Make at most 200, least 50?
}
impl App {
@@ -19,10 +34,14 @@ impl App {
should_quit : false,
process_sorting_reverse : true,
to_be_resorted : false,
- current_selected_process_position : 0,
+ currently_selected_process_position : 0,
+ currently_selected_disk_position : 0,
+ currently_selected_temperature_position : 0,
temperature_type,
update_rate_in_milliseconds,
show_average_cpu,
+ current_application_position : ApplicationPosition::PROCESS,
+ current_zoom_level_percent : 100.0,
}
}
@@ -89,4 +108,43 @@ impl App {
pub fn on_down(&mut self) {
}
+
+ 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),
+ _ => {}
+ }
+ }
+
+ 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),
+ _ => {}
+ }
+ }
+
+ fn change_process_position(&mut self, num_to_change_by : i32) {
+ if self.currently_selected_process_position + num_to_change_by as u64 > 0 {
+ self.currently_selected_process_position += num_to_change_by as u64;
+ }
+ // else if self.currently_selected_process_position < // TODO: Need to finish this! This should never go PAST the number of elements
+ }
+
+ fn change_temp_position(&mut self, num_to_change_by : i32) {
+ if self.currently_selected_temperature_position + num_to_change_by as u64 > 0 {
+ self.currently_selected_temperature_position += num_to_change_by as u64;
+ }
+ // else if self.currently_selected_temperature_position < // TODO: Need to finish this! This should never go PAST the number of elements
+ }
+
+ fn change_disk_position(&mut self, num_to_change_by : i32) {
+ if self.currently_selected_disk_position + num_to_change_by as u64 > 0 {
+ self.currently_selected_disk_position += num_to_change_by as u64;
+ }
+ // else if self.currently_selected_disk_position < // TODO: Need to finish this! This should never go PAST the number of elements
+ }
}
diff --git a/src/app/data_collection/processes.rs b/src/app/data_collection/processes.rs
index 3f8512e0..e688b560 100644
--- a/src/app/data_collection/processes.rs
+++ b/src/app/data_collection/processes.rs
@@ -4,7 +4,6 @@ use heim_common::{
};
use std::{collections::HashMap, process::Command};
-#[allow(dead_code)]
#[derive(Clone)]
pub enum ProcessSorting {
CPU,
@@ -37,6 +36,9 @@ fn vangelis_cpu_usage_calculation(prev_idle : &mut f64, prev_non_idle : &mut f64
let stat_results = std::fs::read_to_string(path)?;
let first_line = stat_results.split('\n').collect::<Vec<&str>>()[0];
+
+ // TODO: Consider grabbing by number of threads instead, and summing the total?
+ // ie: 4 threads, so: (prev - curr) / cpu_0 + ... + (prev - curr) / cpu_n instead? This might be how top does it?
let val = first_line.split_whitespace().collect::<Vec<&str>>();
// SC in case that the parsing will fail due to length:
@@ -167,7 +169,9 @@ fn convert_ps(process : &str, cpu_usage_percentage : f64, prev_pid_stats : &mut
})
}
-pub async fn get_sorted_processes_list(prev_idle : &mut f64, prev_non_idle : &mut f64, prev_pid_stats : &mut HashMap<String, f64>) -> Result<Vec<ProcessData>, heim::Error> {
+pub async fn get_sorted_processes_list(
+ prev_idle : &mut f64, prev_non_idle : &mut f64, prev_pid_stats : &mut std::collections::HashMap<String, f64>,
+) -> Result<Vec<ProcessData>, heim::Error> {
let mut process_vector : Vec<ProcessData> = Vec::new();
if cfg!(target_os = "linux") {
diff --git a/src/canvas.rs b/src/canvas.rs
index 40f13ec0..c6154351 100644
--- a/src/canvas.rs
+++ b/src/canvas.rs
@@ -70,7 +70,7 @@ pub fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_dat
// 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.5, 100.0]).labels(&["0%", "100%"]);
+ let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([-0.5, 100.5]).labels(&["0%", "100%"]);
let mut dataset_vector : Vec<Dataset> = Vec::new();
@@ -116,7 +116,7 @@ pub fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_dat
//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.5, 100.0]).labels(&["0%", "100%"]); // Offset as the zero value isn't drawn otherwise...
+ let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([-0.5, 100.5]).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)
@@ -148,16 +148,20 @@ pub fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_dat
// Disk usage table
{
+ // TODO: We have to dynamically remove some of these table elements based on size...
let width = f64::from(middle_divided_chunk_2[1].width);
- Table::new(["Disk", "Mount", "Used", "Total", "Free"].iter(), disk_rows)
+ Table::new(["Disk", "Mount", "Used", "Total", "Free", "R/s", "W/s"].iter(), disk_rows)
.block(Block::default().title("Disk Usage").borders(Borders::ALL).border_style(border_style))
.header_style(Style::default().fg(Color::LightBlue).modifier(Modifier::BOLD))
.widths(&[
- (width * 0.25) as u16,
- (width * 0.2) as u16,
- (width * 0.15) as u16,
- (width * 0.15) as u16,
- (width * 0.15) as u16,
+ // Must make sure these are NEVER zero! It will fail to display! Seems to only be this...
+ (width * 0.2) as u16 + 1,
+ (width * 0.2) as u16 + 1,
+ (width * 0.1) as u16 + 1,
+ (width * 0.1) as u16 + 1,
+ (width * 0.1) as u16 + 1,
+ (width * 0.1) as u16 + 1,
+ (width * 0.1) as u16 + 1,
])
.render(&mut f, middle_divided_chunk_2[1]);
}
@@ -165,7 +169,7 @@ pub fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_dat
// 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.5, 1_000_000.0]).labels(&["0GB", "1GB"]);
+ let y_axis = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([-0.5, 1_000_000.5]).labels(&["0GB", "1GB"]);
Chart::default()
.block(Block::default().title("Network").borders(Borders::ALL).border_style(border_style))
.x_axis(x_axis)
diff --git a/src/constants.rs b/src/constants.rs
new file mode 100644
index 00000000..e6c6d17a
--- /dev/null
+++ b/src/constants.rs
@@ -0,0 +1,3 @@
+// TODO: Store like three minutes of data, then change how much is shown based on scaling!
+pub const STALE_MAX_MILLISECONDS : u64 = 60 * 1000; // We wish to store at most 60 seconds worth of data. This may change in the future, or be configurable.
+pub const TICK_RATE_IN_MILLISECONDS : u64 = 200; // We use this as it's a good value to work with.
diff --git a/src/convert_data.rs b/src/convert_data.rs
new file mode 100644
index 00000000..e3b70831
--- /dev/null
+++ b/src/convert_data.rs
@@ -0,0 +1,260 @@
+use crate::{app::data_collection, constants};
+use constants::*;
+
+pub fn update_temp_row(app_data : &data_collection::Data, temp_type : &data_collection::temperature::TemperatureType) -> Vec<Vec<String>> {
+ let mut sensor_vector : Vec<Vec<String>> = Vec::new();
+
+ for sensor in &app_data.list_of_temperature_sensor {
+ sensor_vector.push(vec![
+ sensor.component_name.to_string(),
+ (sensor.temperature.ceil() as u64).to_string()
+ + match temp_type {
+ data_collection::temperature::TemperatureType::Celsius => "C",
+ data_collection::temperature::TemperatureType::Kelvin => "K",
+ data_collection::temperature::TemperatureType::Fahrenheit => "F",
+ },
+ ]);
+ }
+
+ sensor_vector
+}
+
+// TODO: IO count NEEDS TO BE DONE!!!!!
+pub fn update_disk_row(app_data : &data_collection::Data) -> Vec<Vec<String>> {
+ let mut disk_vector : Vec<Vec<String>> = Vec::new();
+ for disk in &app_data.list_of_disks {
+ disk_vector.push(vec![
+ disk.name.to_string(),
+ disk.mount_point.to_string(),
+ format!("{:.1}%", disk.used_space as f64 / disk.total_space as f64 * 100_f64),
+ if disk.free_space < 1024 {
+ disk.free_space.to_string() + "MB"
+ }
+ else {
+ (disk.free_space / 1024).to_string() + "GB"
+ },
+ if disk.total_space < 1024 {
+ disk.total_space.to_string() + "MB"
+ }
+ else {
+ (disk.total_space / 1024).to_string() + "GB"
+ },
+ ]);
+ }
+
+ disk_vector
+}
+
+pub fn update_process_row(app_data : &data_collection::Data) -> Vec<Vec<String>> {
+ let mut process_vector : Vec<Vec<String>> = 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!(
+ "{:.1}%",
+ if let Some(mem_usage) = process.mem_usage_percent {
+ mem_usage
+ }
+ else if let Some(mem_usage_in_mb) = process.mem_usage_mb {
+ if let Some(mem_data) = app_data.memory.last() {
+ mem_usage_in_mb as f64 / mem_data.mem_total_in_mb as f64 * 100_f64
+ }
+ else {
+ 0_f64
+ }
+ }
+ else {
+ 0_f64
+ }
+ ),
+ ]);
+ }
+
+ process_vector
+}
+
+pub fn update_cpu_data_points(show_avg_cpu : bool, app_data : &data_collection::Data) -> Vec<(String, Vec<(f64, f64)>)> {
+ let mut cpu_data_vector : Vec<(String, Vec<(f64, f64)>)> = Vec::new();
+ let mut cpu_collection : Vec<Vec<(f64, f64)>> = Vec::new();
+
+ if !app_data.list_of_cpu_packages.is_empty() {
+ // 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();
+
+ 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;
+
+ 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..50 {
+ this_cpu_data.push((
+ previous_element_data.0 + ((new_entry.0 - previous_element_data.0) / 50.0 * f64::from(idx)),
+ previous_element_data.1 + ((new_entry.1 - previous_element_data.1) / 50.0 * f64::from(idx)),
+ ));
+ }
+ }
+
+ this_cpu_data.push(new_entry);
+ }
+
+ cpu_collection.push(this_cpu_data);
+ }
+
+ // Finally, add it all onto the end
+ for (i, data) in cpu_collection.iter().enumerate() {
+ cpu_data_vector.push((
+ // + 1 to skip total CPU if show_avg_cpu is false
+ format!(
+ "{:4}: ",
+ &*(app_data.list_of_cpu_packages.last().unwrap().cpu_vec[i + if show_avg_cpu { 0 } else { 1 }].cpu_name)
+ )
+ .to_uppercase() + &format!("{:3}%", (data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64)),
+ data.clone(),
+ ))
+ }
+ }
+
+ cpu_data_vector
+}
+
+pub fn update_mem_data_points(app_data : &data_collection::Data) -> Vec<(f64, f64)> {
+ convert_mem_data(&app_data.memory)
+}
+
+pub fn update_swap_data_points(app_data : &data_collection::Data) -> Vec<(f64, f64)> {
+ convert_mem_data(&app_data.swap)
+}
+
+pub fn convert_mem_data(mem_data : &[data_collection::mem::MemData]) -> Vec<(f64, f64)> {
+ let mut result : Vec<(f64, f64)> = Vec::new();
+
+ for data in mem_data {
+ let current_time = std::time::Instant::now();
+ 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..50 {
+ result.push((
+ previous_element_data.0 + ((new_entry.0 - previous_element_data.0) / 50.0 * f64::from(idx)),
+ previous_element_data.1 + ((new_entry.1 - previous_element_data.1) / 50.0 * f64::from(idx)),
+ ));
+ }
+ }
+
+ result.push(new_entry);
+ //debug!("Pushed: ({}, {})", result.last().unwrap().0, result.last().unwrap().1);
+ }
+
+ result
+}
+
+pub struct ConvertedNetworkData {
+ pub rx : Vec<(f64, f64)>,
+ pub tx : Vec<(f64, f64)>,
+ pub rx_display : String,
+ pub tx_display : String,
+}
+
+pub fn update_network_data_points(app_data : &data_collection::Data) -> ConvertedNetworkData {
+ convert_network_data_points(&app_data.network)
+}
+
+pub fn convert_network_data_points(network_data : &[data_collection::network::NetworkData]) -> ConvertedNetworkData {
+ let mut rx : Vec<(f64, f64)> = Vec::new();
+ let mut tx : Vec<(f64, f64)> = Vec::new();
+
+ for data in network_data {
+ let current_time = std::time::Instant::now();
+ 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,
+ );
+ 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..50 {
+ rx.push((
+ previous_element_data.0 + ((rx_data.0 - previous_element_data.0) / 50.0 * f64::from(idx)),
+ previous_element_data.1 + ((rx_data.1 - previous_element_data.1) / 50.0 * f64::from(idx)),
+ ));
+ }
+ }
+
+ // Now, inject our joining points...
+ if !tx.is_empty() {
+ let previous_element_data = *(tx.last().unwrap());
+ for idx in 0..50 {
+ tx.push((
+ previous_element_data.0 + ((tx_data.0 - previous_element_data.0) / 50.0 * f64::from(idx)),
+ previous_element_data.1 + ((tx_data.1 - previous_element_data.1) / 50.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);
+ }
+
+ 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 }
+}
diff --git a/src/main.rs b/src/main.rs
index 8c56d9da..d1c3c80f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,29 +7,32 @@ extern crate clap;
#[macro_use]
extern crate failure;
-use crossterm::{input, AlternateScreen, InputEvent, KeyEvent};
+use crossterm::{input, AlternateScreen, InputEvent, KeyEvent, MouseButton, MouseEvent};
use std::{sync::mpsc, thread, time::Duration};
use tui::{backend::CrosstermBackend, Terminal};
-mod app;
-use app::data_collection;
+pub mod app;
mod utils {
pub mod error;
pub mod logging;
}
-use utils::error::{self, RustopError};
mod canvas;
+mod constants;
+mod convert_data;
+
+use app::data_collection;
+use constants::{STALE_MAX_MILLISECONDS, TICK_RATE_IN_MILLISECONDS};
+use convert_data::*;
+use utils::error::{self, RustopError};
// End imports
-enum Event<I> {
- Input(I),
+enum Event<I, J> {
+ KeyInput(I),
+ MouseInput(J),
Update(Box<data_collection::Data>),
}
-const STALE_MAX_MILLISECONDS : u64 = 60 * 1000; // We wish to store at most 60 seconds worth of data. This may change in the future, or be configurable.
-const TICK_RATE_IN_MILLISECONDS : u64 = 200; // We use this as it's a good value to work with.
-
fn main() -> error::Result<()> {
let _log = utils::logging::init_logger(); // TODO: Error handling
@@ -79,20 +82,38 @@ fn main() -> error::Result<()> {
// Create "app" struct, which will control most of the program and store settings/state
let mut app = app::App::new(show_average_cpu, temperature_type, update_rate_in_milliseconds as u64);
+ // Set up up tui and crossterm
+ let screen = AlternateScreen::to_alternate(true)?;
+ let stdout = std::io::stdout();
+ let backend = CrosstermBackend::with_alternate_screen(stdout, screen)?;
+ let mut terminal = Terminal::new(backend)?;
+ terminal.hide_cursor()?;
+ terminal.clear()?;
+
// Set up input handling
let (tx, rx) = mpsc::channel();
{
let tx = tx.clone();
thread::spawn(move || {
let input = input();
+ input.enable_mouse_mode().unwrap();
let reader = input.read_sync();
for event in reader {
- if let InputEvent::Keyboard(key) = event {
- if tx.send(Event::Input(key.clone())).is_err() {
- return;
+ match event {
+ InputEvent::Keyboard(key) => {
+ if tx.send(Event::KeyInput(key.clone())).is_err() {
+ return;
+ }
}
+ InputEvent::Mouse(mouse) => {
+ if tx.send(Event::MouseInput(mouse)).is_err() {
+ return;
+ }
+ }
+ _ => {}
}
}
+ input.disable_mouse_mode().unwrap();
});
}
@@ -121,30 +142,21 @@ fn main() -> error::Result<()> {
});
}
- // Set up up tui and crossterm
- let screen = AlternateScreen::to_alternate(true)?;
- let stdout = std::io::stdout();
- let backend = CrosstermBackend::with_alternate_screen(stdout, screen)?;
- let mut terminal = Terminal::new(backend)?;
- terminal.hide_cursor()?;
- terminal.clear()?;
-
let mut app_data = data_collection::Data::default();
let mut canvas_data = canvas::CanvasData::default();
loop {
if let Ok(recv) = rx.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
match recv {
- Event::Input(event) => {
- debug!("Input event fired!");
+ Event::KeyInput(event) => {
+ debug!("Keyboard event fired!");
match event {
- KeyEvent::Char(c) => app.on_key(c),
+ KeyEvent::Ctrl('c') | KeyEvent::Esc => break,
+ KeyEvent::Char(c) => app.on_key(c), // TODO: We can remove the 'q' event and just move it to the quit?
KeyEvent::Left => app.on_left(),
KeyEvent::Right => app.on_right(),
KeyEvent::Up => app.on_up(),
KeyEvent::Down => app.on_down(),
- KeyEvent::Ctrl('c') => break,
- KeyEvent::Esc => break,
_ => {}
}
@@ -155,6 +167,32 @@ fn main() -> error::Result<()> {
}
debug!("Input event complete.");
}
+ Event::MouseInput(event) => {
+ debug!("Mouse event fired!");
+ match event {
+ MouseEvent::Press(e, _x, _y) => {
+ debug!("Mouse press!");
+ match e {
+ MouseButton::WheelUp => {
+ debug!("Wheel up!");
+ }
+ MouseButton::WheelDown => {
+ debug!("Wheel down!");
+ }
+ _ => {}
+ }
+ }
+ MouseEvent::Hold(_x, _y) => {
+ debug!("Mouse hold!");
+ }
+ MouseEvent::Release(_x, _y) => {
+ debug!("Mouse release!");
+ }
+ _ => {
+ debug!("Mouse unknown event...");
+ }
+ }
+ }
Event::Update(data) => {
debug!("Update event fired!");
app_data = *data;
@@ -187,261 +225,3 @@ fn main() -> error::Result<()> {
debug!("Terminating.");
Ok(())
}
-
-fn update_temp_row(app_data : &data_collection::Data, temp_type : &data_collection::temperature::TemperatureType) -> Vec<Vec<String>> {
- let mut sensor_vector : Vec<Vec<String>> = Vec::new();
-
- for sensor in &app_data.list_of_temperature_sensor {
- sensor_vector.push(vec![
- sensor.component_name.to_string(),
- (sensor.temperature.ceil() as u64).to_string()
- + match temp_type {
- data_collection::temperature::TemperatureType::Celsius => "C",
- data_collection::temperature::TemperatureType::Kelvin => "K",
- data_collection::temperature::TemperatureType::Fahrenheit => "F",
- },
- ]);
- }
-
- sensor_vector
-}
-
-// TODO: IO count
-fn update_disk_row(app_data : &data_collection::Data) -> Vec<Vec<String>> {
- let mut disk_vector : Vec<Vec<String>> = Vec::new();
- for disk in &app_data.list_of_disks {
- disk_vector.push(vec![
- disk.name.to_string(),
- disk.mount_point.to_string(),
- format!("{:.1}%", disk.used_space as f64 / disk.total_space as f64 * 100_f64),
- if disk.free_space < 1024 {
- disk.free_space.to_string() + "MB"
- }
- else {
- (disk.free_space / 1024).to_string() + "GB"
- },
- if disk.total_space < 1024 {
- disk.total_space.to_string() + "MB"
- }
- else {
- (disk.total_space / 1024).to_string() + "GB"
- },
- ]);
- }
-
- disk_vector
-}
-
-fn update_process_row(app_data : &data_collection::Data) -> Vec<Vec<String>> {
- let mut process_vector : Vec<Vec<String>> = 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!(
- "{:.1}%",
- if let Some(mem_usage) = process.mem_usage_percent {
- mem_usage
- }
- else if let Some(mem_usage_in_mb) = process.mem_usage_mb {
- if let Some(mem_data) = app_data.memory.last() {
- mem_usage_in_mb as f64 / mem_data.mem_total_in_mb as f64 * 100_f64
- }
- else {
- 0_f64
- }
- }
- else {
- 0_f64
- }
- ),
- ]);
- }
-
- process_vector
-}
-
-fn update_cpu_data_points(show_avg_cpu : bool, app_data : &data_collection::Data) -> Vec<(String, Vec<(f64, f64)>)> {
- let mut cpu_data_vector : Vec<(String, Vec<(f64, f64)>)> = Vec::new();
- let mut cpu_collection : Vec<Vec<(f64, f64)>> = Vec::new();
-
- if !app_data.list_of_cpu_packages.is_empty() {
- // 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();
-
- 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;
-
- 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);
- }
-
- // Finally, add it all onto the end
- for (i, data) in cpu_collection.iter().enumerate() {
- cpu_data_vector.push((
- // + 1 to skip total CPU if show_avg_cpu is false
- format!(
- "{:4}: ",
- &*(app_data.list_of_cpu_packages.last().unwrap().cpu_vec[i + if show_avg_cpu { 0 } else { 1 }].cpu_name)
- )
- .to_uppercase() + &format!("{:3}%", (data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64)),
- data.clone(),
- ))
- }
- }
-
- cpu_data_vector
-}
-
-fn update_mem_data_points(app_data : &data_collection::Data) -> Vec<(f64, f64)> {
- convert_mem_data(&app_data.memory)
-}
-
-fn update_swap_data_points(app_data : &data_collection::Data) -> Vec<(f64, f64)> {
- convert_mem_data(&app_data.swap)
-}
-
-fn convert_mem_data(mem_data : &[data_collection::mem::MemData]) -> Vec<(f64, f64)> {
- let mut result : Vec<(f64, f64)> = Vec::new();
-
- for data in mem_data {
- let current_time = std::time::Instant::now();
- 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);
- }
-
- result
-}
-
-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 {
- convert_network_data_points(&app_data.network)
-}
-
-fn convert_network_data_points(network_data : &[data_collection::network::NetworkData]) -> ConvertedNetworkData {
- let mut rx : Vec<(f64, f64)> = Vec::new();
- let mut tx : Vec<(f64, f64)> = Vec::new();
-
- for data in network_data {
- let current_time = std::time::Instant::now();
- 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,
- );
- 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);
- }
-
- 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 }
-}