More refactoring.

This commit is contained in:
ClementTsang 2019-09-11 20:41:11 -04:00
parent b7081dd0e4
commit 50d3be05dd
11 changed files with 102 additions and 64 deletions

View File

@ -8,6 +8,7 @@ edition = "2018"
[dependencies] [dependencies]
chrono = "0.4.9" chrono = "0.4.9"
clap = "2.33.0"
crossterm = "0.10.2" crossterm = "0.10.2"
futures-preview = "0.3.0-alpha.18" futures-preview = "0.3.0-alpha.18"
fern = "0.5" fern = "0.5"

View File

@ -10,9 +10,11 @@
* Add custom error because it's really messy * Add custom error because it's really messy
* Scrolling event
* Keybindings * Keybindings
* FIX PROCESSES AHHHHHH ~~* FIX PROCESSES AHHHHHH~~
* Refactor everything because it's a mess * Refactor everything because it's a mess

View File

@ -4,7 +4,7 @@ use sysinfo::{ProcessorExt, System, SystemExt};
#[derive(Clone)] #[derive(Clone)]
pub struct CPUData { pub struct CPUData {
pub cpu_name : Box<str>, pub cpu_name : Box<str>,
pub cpu_usage : u32, pub cpu_usage : f64,
} }
#[derive(Clone)] #[derive(Clone)]
@ -20,7 +20,7 @@ pub fn get_cpu_data_list(sys : &System) -> Result<CPUPackage, heim::Error> {
for cpu in cpu_data { for cpu in cpu_data {
cpu_vec.push(CPUData { cpu_vec.push(CPUData {
cpu_name : Box::from(cpu.get_name()), cpu_name : Box::from(cpu.get_name()),
cpu_usage : (cpu.get_cpu_usage() * 100_f32).ceil() as u32, cpu_usage : f64::from(cpu.get_cpu_usage()) * 100_f64,
}) })
} }

View File

@ -0,0 +1,6 @@
pub mod cpu;
pub mod disks;
pub mod mem;
pub mod network;
pub mod processes;
pub mod temperature;

View File

@ -5,6 +5,8 @@ use sysinfo::{NetworkExt, System, SystemExt};
pub struct NetworkData { pub struct NetworkData {
pub rx : u64, pub rx : u64,
pub tx : u64, pub tx : u64,
pub total_rx : u64,
pub total_tx : u64,
pub instant : Instant, pub instant : Instant,
} }
@ -13,6 +15,8 @@ pub fn get_network_data(sys : &System) -> Result<NetworkData, heim::Error> {
Ok(NetworkData { Ok(NetworkData {
rx : network_data.get_income(), rx : network_data.get_income(),
tx : network_data.get_outcome(), tx : network_data.get_outcome(),
total_rx : 0,
total_tx : 0,
instant : Instant::now(), instant : Instant::now(),
}) })
} }

View File

@ -52,10 +52,14 @@ fn vangelis_cpu_usage_calculation(prev_idle : &mut f64, prev_non_idle : &mut f64
let total_delta : f64 = total - prev_total; let total_delta : f64 = total - prev_total;
let idle_delta : f64 = idle - *prev_idle; let idle_delta : f64 = idle - *prev_idle;
debug!("Vangelis function: CPU PERCENT: {}", (total_delta - idle_delta) / total_delta * 100_f64);
*prev_idle = idle; *prev_idle = idle;
*prev_non_idle = non_idle; *prev_non_idle = non_idle;
Ok(total_delta - idle_delta) let result = if total_delta - idle_delta != 0_f64 { total_delta - idle_delta } else { 1_f64 };
Ok(result) // This works, REALLY damn well. The percentage check is within like 2% of the sysinfo one.
} }
fn get_ordering<T : std::cmp::PartialOrd>(a_val : T, b_val : T, reverse_order : bool) -> std::cmp::Ordering { fn get_ordering<T : std::cmp::PartialOrd>(a_val : T, b_val : T, reverse_order : bool) -> std::cmp::Ordering {
@ -96,16 +100,18 @@ fn get_process_cpu_stats(pid : u32) -> std::io::Result<f64> {
let stat_results = std::fs::read_to_string(path)?; let stat_results = std::fs::read_to_string(path)?;
let val = stat_results.split_whitespace().collect::<Vec<&str>>(); let val = stat_results.split_whitespace().collect::<Vec<&str>>();
let utime = val[13].parse::<f64>().unwrap_or(-1_f64); let utime = val[13].parse::<f64>().unwrap_or(0_f64);
let stime = val[14].parse::<f64>().unwrap_or(-1_f64); let stime = val[14].parse::<f64>().unwrap_or(0_f64);
Ok(utime + stime) debug!("PID: {}, utime: {}, stime: {}", pid, utime, stime);
Ok(utime + stime) // This seems to match top...
} }
fn linux_cpu_usage(pid : u32, cpu_usage : f64, previous_pid_stats : &mut HashMap<String, f64>) -> std::io::Result<f64> { fn linux_cpu_usage(pid : u32, cpu_usage : f64, previous_pid_stats : &mut HashMap<String, f64>) -> std::io::Result<f64> {
// Based heavily on https://stackoverflow.com/a/23376195 and https://stackoverflow.com/a/1424556 // Based heavily on https://stackoverflow.com/a/23376195 and https://stackoverflow.com/a/1424556
let before_proc_val : f64 = if previous_pid_stats.contains_key(&pid.to_string()) { let before_proc_val : f64 = if previous_pid_stats.contains_key(&pid.to_string()) {
*previous_pid_stats.get(&pid.to_string()).unwrap_or(&-1_f64) *previous_pid_stats.get(&pid.to_string()).unwrap_or(&0_f64)
} }
else { else {
0_f64 0_f64

View File

@ -1,9 +1,5 @@
pub mod cpu; pub mod data_collection;
pub mod disks; use data_collection::{cpu, disks, mem, network, processes, temperature};
pub mod mem;
pub mod network;
pub mod processes;
pub mod temperature;
use std::collections::HashMap; use std::collections::HashMap;
use sysinfo::{System, SystemExt}; use sysinfo::{System, SystemExt};
@ -46,7 +42,7 @@ pub struct DataState {
pub data : Data, pub data : Data,
sys : System, sys : System,
stale_max_seconds : u64, stale_max_seconds : u64,
prev_pid_stats : HashMap<String, f64>, prev_pid_stats : HashMap<String, f64>, // TODO: Purge list?
prev_idle : f64, prev_idle : f64,
prev_non_idle : f64, prev_non_idle : f64,
} }

View File

@ -4,19 +4,20 @@ use std::{io, sync::mpsc, thread, time::Duration};
use tui::{ use tui::{
backend::CrosstermBackend, backend::CrosstermBackend,
layout::{Constraint, Direction, Layout}, layout::{Constraint, Direction, Layout},
style::{Color, Style}, style::{Color, Modifier, Style},
widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Row, Table, Widget}, widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Row, Table, Widget},
Terminal, Terminal,
}; };
mod widgets; mod app;
use app::data_collection;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
enum Event<I> { enum Event<I> {
Input(I), Input(I),
Update(Box<widgets::Data>), Update(Box<app::Data>),
} }
const STALE_MAX_SECONDS : u64 = 60; const STALE_MAX_SECONDS : u64 = 60;
@ -30,7 +31,7 @@ async fn main() -> Result<(), io::Error> {
let tick_rate_in_milliseconds : u64 = 250; let tick_rate_in_milliseconds : u64 = 250;
let update_rate_in_milliseconds : u64 = 1000; // TODO: Must set a check to prevent this from going into negatives! let update_rate_in_milliseconds : u64 = 1000; // TODO: Must set a check to prevent this from going into negatives!
let mut app = widgets::App::new("rustop"); let mut app = app::App::new("rustop");
let log = init_logger(); let log = init_logger();
@ -53,7 +54,7 @@ async fn main() -> Result<(), io::Error> {
} }
// Event loop // Event loop
let mut data_state = widgets::DataState::default(); let mut data_state = app::DataState::default();
data_state.init(); data_state.init();
data_state.set_stale_max_seconds(STALE_MAX_SECONDS); data_state.set_stale_max_seconds(STALE_MAX_SECONDS);
{ {
@ -70,7 +71,10 @@ async fn main() -> Result<(), io::Error> {
terminal.clear()?; terminal.clear()?;
let mut app_data = widgets::Data::default(); let mut app_data = app::Data::default();
let mut swap_data : Vec<(f64, f64)> = Vec::new();
let mut mem_data : Vec<(f64, f64)> = Vec::new();
loop { loop {
if let Ok(recv) = rx.recv_timeout(Duration::from_millis(tick_rate_in_milliseconds)) { if let Ok(recv) = rx.recv_timeout(Duration::from_millis(tick_rate_in_milliseconds)) {
match recv { match recv {
@ -87,16 +91,22 @@ async fn main() -> Result<(), io::Error> {
} }
if app.to_be_resorted { if app.to_be_resorted {
widgets::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse); data_collection::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse);
app.to_be_resorted = false; app.to_be_resorted = false;
} }
try_debug(&log, "Input event complete."); try_debug(&log, "Input event complete.");
// Only update processes
} }
Event::Update(data) => { Event::Update(data) => {
try_debug(&log, "Update event fired!"); try_debug(&log, "Update event fired!");
app_data = *data; app_data = *data;
widgets::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse); data_collection::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse);
try_debug(&log, "Update event complete."); try_debug(&log, "Update event complete.");
// Convert all data into tui components
mem_data = update_mem_data_points(&app_data);
swap_data = update_swap_data_points(&app_data);
} }
} }
if app.should_quit { if app.should_quit {
@ -105,14 +115,33 @@ async fn main() -> Result<(), io::Error> {
} }
// Draw! // Draw!
draw_data(&mut terminal, &app_data)?; // TODO: We should change this btw! It should not redraw everything on every tick!
draw_data(&mut terminal, &app_data, &mem_data, &swap_data)?;
} }
Ok(()) Ok(())
} }
fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data : &widgets::Data) -> Result<(), io::Error> { fn update_temp_row(app_data : &app::Data) {
// Convert data into tui components }
fn update_process_row(app_data : &app::Data) {
}
fn update_cpu_data_points(app_data : &app::Data) {
}
fn update_mem_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
convert_mem_data(&app_data.memory)
}
fn update_swap_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
convert_mem_data(&app_data.swap)
}
fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data : &app::Data, mem_data : &[(f64, f64)], swap_data : &[(f64, f64)]) -> Result<(), io::Error> {
const COLOUR_LIST : [Color; 6] = [Color::LightCyan, Color::LightMagenta, Color::LightRed, Color::LightGreen, Color::LightYellow, Color::LightBlue];
let temperature_rows = app_data.list_of_temperature.iter().map(|sensor| { let temperature_rows = app_data.list_of_temperature.iter().map(|sensor| {
Row::StyledData( Row::StyledData(
vec![sensor.component_name.to_string(), sensor.temperature.to_string() + "C"].into_iter(), // TODO: Change this based on temperature type vec![sensor.component_name.to_string(), sensor.temperature.to_string() + "C"].into_iter(), // TODO: Change this based on temperature type
@ -134,6 +163,32 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
) )
}); });
let mut dataset_vector : Vec<Dataset> = Vec::new();
let mut data_vector : Vec<Vec<(f64, f64)>> = Vec::new();
if !app_data.list_of_cpu_packages.is_empty() {
for cpu_num in 0..app_data.list_of_cpu_packages.last().unwrap().cpu_vec.len() {
let mut this_cpu_data : Vec<(f64, f64)> = Vec::new();
let current_time = std::time::Instant::now();
for cpu in &app_data.list_of_cpu_packages {
this_cpu_data.push((STALE_MAX_SECONDS as f64 - current_time.duration_since(cpu.instant).as_secs_f64(), cpu.cpu_vec[cpu_num].cpu_usage));
}
data_vector.push(this_cpu_data);
}
for (i, data) in data_vector.iter().enumerate() {
dataset_vector.push(
Dataset::default()
.name(&*(app_data.list_of_cpu_packages.last().unwrap().cpu_vec[i].cpu_name))
.marker(Marker::Braille)
.style(Style::default().fg(COLOUR_LIST[i % COLOUR_LIST.len()]))
.data(&data),
)
}
}
let process_rows = app_data.list_of_processes.iter().map(|process| { let process_rows = app_data.list_of_processes.iter().map(|process| {
Row::StyledData( Row::StyledData(
vec![ vec![
@ -200,24 +255,15 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
// CPU usage graph // CPU usage graph
{ {
debug!("Drawing CPU...");
let x_axis : Axis<String> = Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 60.0]); let x_axis : Axis<String> = Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 60.0]);
let y_axis = Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 100.0]).labels(&["0.0", "50.0", "100.0"]); let y_axis = Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 100.0]).labels(&["0.0", "50.0", "100.0"]);
Chart::default() Chart::default()
.block(Block::default().title("CPU Usage").borders(Borders::ALL)) .block(Block::default().title("CPU Usage").borders(Borders::ALL))
.x_axis(x_axis) .x_axis(x_axis)
.y_axis(y_axis) .y_axis(y_axis)
.datasets(&[ .datasets(&dataset_vector)
Dataset::default()
.name("CPU0")
.marker(Marker::Braille)
.style(Style::default().fg(Color::Cyan))
.data(&convert_cpu_data(0, &app_data.list_of_cpu_packages)),
Dataset::default()
.name("CPU1")
.marker(Marker::Braille)
.style(Style::default().fg(Color::LightMagenta))
.data(&convert_cpu_data(1, &app_data.list_of_cpu_packages)),
])
.render(&mut f, top_chunks[0]); .render(&mut f, top_chunks[0]);
} }
@ -230,16 +276,8 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
.x_axis(x_axis) .x_axis(x_axis)
.y_axis(y_axis) .y_axis(y_axis)
.datasets(&[ .datasets(&[
Dataset::default() Dataset::default().name("MEM").marker(Marker::Braille).style(Style::default().fg(Color::Cyan)).data(&mem_data),
.name("MEM") Dataset::default().name("SWAP").marker(Marker::Braille).style(Style::default().fg(Color::LightGreen)).data(&swap_data),
.marker(Marker::Braille)
.style(Style::default().fg(Color::Cyan))
.data(&convert_mem_data(&app_data.memory)),
Dataset::default()
.name("SWAP")
.marker(Marker::Braille)
.style(Style::default().fg(Color::LightGreen))
.data(&convert_mem_data(&app_data.swap)),
]) ])
.render(&mut f, top_chunks[1]); .render(&mut f, top_chunks[1]);
} }
@ -278,22 +316,7 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
Ok(()) Ok(())
} }
// TODO: Remove this count, this is for testing, lol fn convert_mem_data(mem_data : &[app::data_collection::mem::MemData]) -> Vec<(f64, f64)> {
fn convert_cpu_data(count : usize, cpu_data : &[widgets::cpu::CPUPackage]) -> Vec<(f64, f64)> {
let mut result : Vec<(f64, f64)> = Vec::new();
let current_time = std::time::Instant::now();
for data in cpu_data {
result.push((
STALE_MAX_SECONDS as f64 - current_time.duration_since(data.instant).as_secs() as f64,
f64::from(data.cpu_vec[count + 1].cpu_usage),
));
}
result
}
fn convert_mem_data(mem_data : &[widgets::mem::MemData]) -> Vec<(f64, f64)> {
let mut result : Vec<(f64, f64)> = Vec::new(); let mut result : Vec<(f64, f64)> = Vec::new();
let current_time = std::time::Instant::now(); let current_time = std::time::Instant::now();