mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-23 05:34:57 +02:00
Ironed out as many kinks as possible in terms of smoothness.
This commit is contained in:
parent
ff89f1187f
commit
d9a0d32c1f
@ -7,12 +7,15 @@ edition = "2018"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = "0.4.9"
|
||||||
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"
|
||||||
futures-timer = "0.3"
|
futures-timer = "0.3"
|
||||||
futures-util = "0.2.1"
|
futures-util = "0.2.1"
|
||||||
heim = "0.0.7"
|
heim = "0.0.7"
|
||||||
heim-common = "0.0.7"
|
heim-common = "0.0.7"
|
||||||
|
log = "0.4"
|
||||||
sysinfo = "0.9.4"
|
sysinfo = "0.9.4"
|
||||||
tokio = "0.2.0-alpha.4"
|
tokio = "0.2.0-alpha.4"
|
||||||
|
|
||||||
|
314
src/main.rs
314
src/main.rs
@ -11,9 +11,12 @@ use tui::{
|
|||||||
|
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
enum Event<I> {
|
enum Event<I> {
|
||||||
Input(I),
|
Input(I),
|
||||||
Tick,
|
Update(widgets::Data),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@ -22,7 +25,10 @@ async fn main() -> Result<(), io::Error> {
|
|||||||
let backend = CrosstermBackend::with_alternate_screen(screen)?;
|
let backend = CrosstermBackend::with_alternate_screen(screen)?;
|
||||||
let mut terminal = Terminal::new(backend)?;
|
let mut terminal = Terminal::new(backend)?;
|
||||||
|
|
||||||
let update_rate_in_milliseconds : u64 = 500;
|
let tick_rate_in_milliseconds : u64 = 220;
|
||||||
|
let update_rate_in_milliseconds : u64 = 1000;
|
||||||
|
|
||||||
|
let log = init_logger();
|
||||||
|
|
||||||
terminal.hide_cursor()?;
|
terminal.hide_cursor()?;
|
||||||
// Setup input handling
|
// Setup input handling
|
||||||
@ -41,35 +47,51 @@ async fn main() -> Result<(), io::Error> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Event loop
|
||||||
|
let mut data_state = widgets::DataState::default();
|
||||||
{
|
{
|
||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
loop {
|
loop {
|
||||||
tx.send(Event::Tick).unwrap();
|
futures::executor::block_on(data_state.update_data()); // TODO: Fix
|
||||||
|
tx.send(Event::Update(data_state.data.clone())).unwrap();
|
||||||
thread::sleep(Duration::from_millis(update_rate_in_milliseconds));
|
thread::sleep(Duration::from_millis(update_rate_in_milliseconds));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut app : widgets::App = widgets::App::new("rustop");
|
let mut app = widgets::App::new("rustop");
|
||||||
|
|
||||||
terminal.clear()?;
|
terminal.clear()?;
|
||||||
|
|
||||||
|
let mut app_data = widgets::Data::default();
|
||||||
loop {
|
loop {
|
||||||
if let Ok(recv) = rx.recv() {
|
if let Ok(recv) = rx.recv_timeout(Duration::from_millis(tick_rate_in_milliseconds)) {
|
||||||
match recv {
|
match recv {
|
||||||
Event::Input(event) => match event {
|
Event::Input(event) => {
|
||||||
KeyEvent::Char(c) => app.on_key(c),
|
try_debug(&log, "Input event fired!");
|
||||||
KeyEvent::Left => {}
|
match event {
|
||||||
KeyEvent::Right => {}
|
KeyEvent::Char(c) => app.on_key(c),
|
||||||
KeyEvent::Up => {}
|
KeyEvent::Left => app.on_left(),
|
||||||
KeyEvent::Down => {}
|
KeyEvent::Right => app.on_right(),
|
||||||
KeyEvent::Ctrl('c') => break,
|
KeyEvent::Up => app.on_up(),
|
||||||
_ => {}
|
KeyEvent::Down => app.on_down(),
|
||||||
},
|
KeyEvent::Ctrl('c') => break,
|
||||||
Event::Tick => {
|
_ => {}
|
||||||
app.update_data().await; // TODO: This await is causing slow responsiveness... perhaps make drawing another thread?
|
}
|
||||||
|
|
||||||
|
if app.to_be_resorted {
|
||||||
|
widgets::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse);
|
||||||
|
app.to_be_resorted = false;
|
||||||
|
}
|
||||||
|
try_debug(&log, "Input event complete.");
|
||||||
|
}
|
||||||
|
Event::Update(data) => {
|
||||||
|
try_debug(&log, "Update event fired!");
|
||||||
|
app_data = data;
|
||||||
|
widgets::processes::sort_processes(&mut app_data.list_of_processes, &app.process_sorting_type, app.process_sorting_reverse);
|
||||||
|
try_debug(&log, "Update event complete.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if app.should_quit {
|
if app.should_quit {
|
||||||
@ -77,122 +99,152 @@ async fn main() -> Result<(), io::Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert data into tui components
|
|
||||||
let temperature_rows = app.list_of_temperature.iter().map(|sensor| {
|
|
||||||
Row::StyledData(
|
|
||||||
vec![sensor.component_name.to_string(), sensor.temperature.to_string() + "C"].into_iter(), // TODO: Change this based on temperature type
|
|
||||||
Style::default().fg(Color::LightGreen),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let disk_rows = app.list_of_disks.iter().map(|disk| {
|
|
||||||
Row::StyledData(
|
|
||||||
vec![
|
|
||||||
disk.name.to_string(),
|
|
||||||
disk.mount_point.to_string(),
|
|
||||||
format!("{:.2}%", disk.used_space as f64 / disk.total_space as f64 * 100_f64),
|
|
||||||
(disk.free_space / 1024).to_string() + "GB",
|
|
||||||
(disk.total_space / 1024).to_string() + "GB",
|
|
||||||
]
|
|
||||||
.into_iter(), // TODO: Change this based on temperature type
|
|
||||||
Style::default().fg(Color::LightGreen),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mem_total_mb = app.memory.mem_total_in_mb as f64;
|
|
||||||
let process_rows = app.list_of_processes.iter().map(|process| {
|
|
||||||
Row::StyledData(
|
|
||||||
vec![
|
|
||||||
process.pid.to_string(),
|
|
||||||
process.command.to_string(),
|
|
||||||
format!("{:.2}%", process.cpu_usage_percent),
|
|
||||||
format!("{:.2}%", process.mem_usage_in_mb as f64 / mem_total_mb * 100_f64),
|
|
||||||
]
|
|
||||||
.into_iter(),
|
|
||||||
Style::default().fg(Color::LightGreen),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Draw!
|
// Draw!
|
||||||
terminal.draw(|mut f| {
|
draw_data(&mut terminal, &app_data)?;
|
||||||
let vertical_chunks = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.margin(1)
|
|
||||||
.constraints([Constraint::Percentage(30), Constraint::Percentage(40), Constraint::Percentage(30)].as_ref())
|
|
||||||
.split(f.size());
|
|
||||||
let top_chunks = Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.margin(0)
|
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
|
||||||
.split(vertical_chunks[0]);
|
|
||||||
let middle_chunks = Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.margin(0)
|
|
||||||
.constraints([Constraint::Percentage(40), Constraint::Percentage(60)].as_ref())
|
|
||||||
.split(vertical_chunks[1]);
|
|
||||||
let middle_divided_chunk = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.margin(0)
|
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
|
||||||
.split(middle_chunks[0]);
|
|
||||||
let bottom_chunks = Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.margin(0)
|
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
|
||||||
.split(vertical_chunks[2]);
|
|
||||||
|
|
||||||
// Set up blocks and their components
|
|
||||||
|
|
||||||
// CPU usage graph
|
|
||||||
Chart::default()
|
|
||||||
.block(Block::default().title("CPU Usage").borders(Borders::ALL))
|
|
||||||
.x_axis(Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 10.0]).labels(&["0.0", "10.0"]))
|
|
||||||
.y_axis(Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 10.0]).labels(&["0.0", "10.0"]))
|
|
||||||
.datasets(&[
|
|
||||||
Dataset::default()
|
|
||||||
.name("data1")
|
|
||||||
.marker(Marker::Dot)
|
|
||||||
.style(Style::default().fg(Color::Cyan))
|
|
||||||
.data(&[(0.0, 5.0), (1.0, 6.0), (1.5, 6.434)]),
|
|
||||||
Dataset::default()
|
|
||||||
.name("data2")
|
|
||||||
.marker(Marker::Braille)
|
|
||||||
.style(Style::default().fg(Color::Magenta))
|
|
||||||
.data(&[(4.0, 5.0), (5.0, 8.0), (7.66, 13.5)]),
|
|
||||||
])
|
|
||||||
.render(&mut f, top_chunks[0]);
|
|
||||||
|
|
||||||
//Memory usage graph
|
|
||||||
Block::default().title("Memory Usage").borders(Borders::ALL).render(&mut f, top_chunks[1]);
|
|
||||||
|
|
||||||
// Temperature table
|
|
||||||
Table::new(["Sensor", "Temperature"].iter(), temperature_rows)
|
|
||||||
.block(Block::default().title("Temperatures").borders(Borders::ALL))
|
|
||||||
.header_style(Style::default().fg(Color::LightBlue))
|
|
||||||
.widths(&[25, 25])
|
|
||||||
.render(&mut f, middle_divided_chunk[0]);
|
|
||||||
|
|
||||||
// Disk usage table
|
|
||||||
Table::new(["Disk", "Mount", "Used", "Total", "Free"].iter(), disk_rows)
|
|
||||||
.block(Block::default().title("Disk Usage").borders(Borders::ALL))
|
|
||||||
.header_style(Style::default().fg(Color::LightBlue))
|
|
||||||
.widths(&[25, 25, 10, 10, 10])
|
|
||||||
.render(&mut f, middle_divided_chunk[1]);
|
|
||||||
|
|
||||||
// IO graph
|
|
||||||
Block::default().title("IO Usage").borders(Borders::ALL).render(&mut f, middle_chunks[1]);
|
|
||||||
|
|
||||||
// Network graph
|
|
||||||
Block::default().title("Network").borders(Borders::ALL).render(&mut f, bottom_chunks[0]);
|
|
||||||
|
|
||||||
// Processes table
|
|
||||||
Table::new(["PID", "Command", "CPU%", "Mem%"].iter(), process_rows)
|
|
||||||
.block(Block::default().title("Processes").borders(Borders::ALL))
|
|
||||||
.header_style(Style::default().fg(Color::LightBlue))
|
|
||||||
.widths(&[5, 15, 10, 10])
|
|
||||||
.render(&mut f, bottom_chunks[1]);
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data : &widgets::Data) -> Result<(), io::Error> {
|
||||||
|
// Convert data into tui components
|
||||||
|
let temperature_rows = app_data.list_of_temperature.iter().map(|sensor| {
|
||||||
|
Row::StyledData(
|
||||||
|
vec![sensor.component_name.to_string(), sensor.temperature.to_string() + "C"].into_iter(), // TODO: Change this based on temperature type
|
||||||
|
Style::default().fg(Color::LightGreen),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let disk_rows = app_data.list_of_disks.iter().map(|disk| {
|
||||||
|
Row::StyledData(
|
||||||
|
vec![
|
||||||
|
disk.name.to_string(),
|
||||||
|
disk.mount_point.to_string(),
|
||||||
|
format!("{:.2}%", disk.used_space as f64 / disk.total_space as f64 * 100_f64),
|
||||||
|
(disk.free_space / 1024).to_string() + "GB",
|
||||||
|
(disk.total_space / 1024).to_string() + "GB",
|
||||||
|
]
|
||||||
|
.into_iter(), // TODO: Change this based on temperature type
|
||||||
|
Style::default().fg(Color::LightGreen),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mem_total_mb = app_data.memory.mem_total_in_mb as f64;
|
||||||
|
let process_rows = app_data.list_of_processes.iter().map(|process| {
|
||||||
|
Row::StyledData(
|
||||||
|
vec![
|
||||||
|
process.pid.to_string(),
|
||||||
|
process.command.to_string(),
|
||||||
|
format!("{:.2}%", process.cpu_usage_percent),
|
||||||
|
format!("{:.2}%", process.mem_usage_in_mb as f64 / mem_total_mb * 100_f64),
|
||||||
|
]
|
||||||
|
.into_iter(),
|
||||||
|
Style::default().fg(Color::LightGreen),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
terminal.draw(|mut f| {
|
||||||
|
let vertical_chunks = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.margin(1)
|
||||||
|
.constraints([Constraint::Percentage(30), Constraint::Percentage(40), Constraint::Percentage(30)].as_ref())
|
||||||
|
.split(f.size());
|
||||||
|
let top_chunks = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.margin(0)
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||||
|
.split(vertical_chunks[0]);
|
||||||
|
let middle_chunks = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.margin(0)
|
||||||
|
.constraints([Constraint::Percentage(40), Constraint::Percentage(60)].as_ref())
|
||||||
|
.split(vertical_chunks[1]);
|
||||||
|
let middle_divided_chunk = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.margin(0)
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||||
|
.split(middle_chunks[0]);
|
||||||
|
let bottom_chunks = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.margin(0)
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||||
|
.split(vertical_chunks[2]);
|
||||||
|
|
||||||
|
// Set up blocks and their components
|
||||||
|
|
||||||
|
// CPU usage graph
|
||||||
|
Chart::default()
|
||||||
|
.block(Block::default().title("CPU Usage").borders(Borders::ALL))
|
||||||
|
.x_axis(Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 10.0]).labels(&["0.0", "10.0"]))
|
||||||
|
.y_axis(Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 10.0]).labels(&["0.0", "10.0"]))
|
||||||
|
.datasets(&[
|
||||||
|
Dataset::default()
|
||||||
|
.name("data1")
|
||||||
|
.marker(Marker::Dot)
|
||||||
|
.style(Style::default().fg(Color::Cyan))
|
||||||
|
.data(&[(0.0, 5.0), (1.0, 6.0), (1.5, 6.434)]),
|
||||||
|
Dataset::default()
|
||||||
|
.name("data2")
|
||||||
|
.marker(Marker::Braille)
|
||||||
|
.style(Style::default().fg(Color::Magenta))
|
||||||
|
.data(&[(4.0, 5.0), (5.0, 8.0), (7.66, 13.5)]),
|
||||||
|
])
|
||||||
|
.render(&mut f, top_chunks[0]);
|
||||||
|
|
||||||
|
//Memory usage graph
|
||||||
|
Block::default().title("Memory Usage").borders(Borders::ALL).render(&mut f, top_chunks[1]);
|
||||||
|
|
||||||
|
// Temperature table
|
||||||
|
Table::new(["Sensor", "Temperature"].iter(), temperature_rows)
|
||||||
|
.block(Block::default().title("Temperatures").borders(Borders::ALL))
|
||||||
|
.header_style(Style::default().fg(Color::LightBlue))
|
||||||
|
.widths(&[25, 25])
|
||||||
|
.render(&mut f, middle_divided_chunk[0]);
|
||||||
|
|
||||||
|
// Disk usage table
|
||||||
|
Table::new(["Disk", "Mount", "Used", "Total", "Free"].iter(), disk_rows)
|
||||||
|
.block(Block::default().title("Disk Usage").borders(Borders::ALL))
|
||||||
|
.header_style(Style::default().fg(Color::LightBlue))
|
||||||
|
.widths(&[25, 25, 10, 10, 10])
|
||||||
|
.render(&mut f, middle_divided_chunk[1]);
|
||||||
|
|
||||||
|
// IO graph
|
||||||
|
Block::default().title("IO Usage").borders(Borders::ALL).render(&mut f, middle_chunks[1]);
|
||||||
|
|
||||||
|
// Network graph
|
||||||
|
Block::default().title("Network").borders(Borders::ALL).render(&mut f, bottom_chunks[0]);
|
||||||
|
|
||||||
|
// Processes table
|
||||||
|
Table::new(["PID", "Command", "CPU%", "Mem%"].iter(), process_rows)
|
||||||
|
.block(Block::default().title("Processes").borders(Borders::ALL))
|
||||||
|
.header_style(Style::default().fg(Color::LightBlue))
|
||||||
|
.widths(&[5, 15, 10, 10])
|
||||||
|
.render(&mut f, bottom_chunks[1]);
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_logger() -> Result<(), fern::InitError> {
|
||||||
|
fern::Dispatch::new()
|
||||||
|
.format(|out, message, record| {
|
||||||
|
out.finish(format_args!(
|
||||||
|
"{}[{}][{}] {}",
|
||||||
|
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
|
||||||
|
record.target(),
|
||||||
|
record.level(),
|
||||||
|
message
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.level(log::LevelFilter::Debug)
|
||||||
|
.chain(fern::log_file("debug.log")?)
|
||||||
|
.apply()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_debug(result_log : &Result<(), fern::InitError>, message : &str) {
|
||||||
|
if result_log.is_ok() {
|
||||||
|
debug!("{}", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,8 +7,23 @@ pub mod temperature;
|
|||||||
|
|
||||||
use sysinfo::{System, SystemExt};
|
use sysinfo::{System, SystemExt};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct App<'a> {
|
pub struct App<'a> {
|
||||||
|
title : &'a str,
|
||||||
pub should_quit : bool,
|
pub should_quit : bool,
|
||||||
|
pub process_sorting_type : processes::ProcessSorting,
|
||||||
|
pub process_sorting_reverse : bool,
|
||||||
|
pub to_be_resorted : bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_if_valid<T : std::clone::Clone>(result : &Result<T, heim::Error>, value_to_set : &mut T) {
|
||||||
|
if let Ok(result) = result {
|
||||||
|
*value_to_set = (*result).clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct Data {
|
||||||
pub list_of_cpu_packages : Vec<cpu::CPUData>,
|
pub list_of_cpu_packages : Vec<cpu::CPUData>,
|
||||||
pub list_of_io : Vec<disks::IOData>,
|
pub list_of_io : Vec<disks::IOData>,
|
||||||
pub list_of_physical_io : Vec<disks::IOData>,
|
pub list_of_physical_io : Vec<disks::IOData>,
|
||||||
@ -18,15 +33,39 @@ pub struct App<'a> {
|
|||||||
pub network : network::NetworkData,
|
pub network : network::NetworkData,
|
||||||
pub list_of_processes : Vec<processes::ProcessData>,
|
pub list_of_processes : Vec<processes::ProcessData>,
|
||||||
pub list_of_disks : Vec<disks::DiskData>,
|
pub list_of_disks : Vec<disks::DiskData>,
|
||||||
pub title : &'a str,
|
}
|
||||||
process_sorting_type : processes::ProcessSorting,
|
|
||||||
process_sorting_reverse : bool,
|
pub struct DataState {
|
||||||
|
pub data : Data,
|
||||||
sys : System,
|
sys : System,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_if_valid<T : std::clone::Clone>(result : &Result<T, heim::Error>, value_to_set : &mut T) {
|
impl Default for DataState {
|
||||||
if let Ok(result) = result {
|
fn default() -> Self {
|
||||||
*value_to_set = (*result).clone();
|
DataState {
|
||||||
|
data : Data::default(),
|
||||||
|
sys : System::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataState {
|
||||||
|
pub async fn update_data(&mut self) {
|
||||||
|
self.sys.refresh_system();
|
||||||
|
self.sys.refresh_network();
|
||||||
|
|
||||||
|
// What we want to do: For timed data, if there is an error, just do not add. For other data, just don't update!
|
||||||
|
set_if_valid(&network::get_network_data(&self.sys), &mut self.data.network);
|
||||||
|
set_if_valid(&cpu::get_cpu_data_list(&self.sys), &mut self.data.list_of_cpu_packages);
|
||||||
|
|
||||||
|
// TODO: We can convert this to a multi-threaded task...
|
||||||
|
set_if_valid(&processes::get_sorted_processes_list().await, &mut self.data.list_of_processes);
|
||||||
|
set_if_valid(&disks::get_disk_usage_list().await, &mut self.data.list_of_disks);
|
||||||
|
set_if_valid(&disks::get_io_usage_list(false).await, &mut self.data.list_of_io);
|
||||||
|
set_if_valid(&disks::get_io_usage_list(true).await, &mut self.data.list_of_physical_io);
|
||||||
|
set_if_valid(&mem::get_mem_data_list().await, &mut self.data.memory);
|
||||||
|
set_if_valid(&mem::get_swap_data_list().await, &mut self.data.swap);
|
||||||
|
set_if_valid(&temperature::get_temperature_data().await, &mut self.data.list_of_temperature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,18 +74,9 @@ impl<'a> App<'a> {
|
|||||||
App {
|
App {
|
||||||
title,
|
title,
|
||||||
process_sorting_type : processes::ProcessSorting::NAME, // TODO: Change this based on input args...
|
process_sorting_type : processes::ProcessSorting::NAME, // TODO: Change this based on input args...
|
||||||
sys : System::new(), // TODO: Evaluate whether this will cause efficiency issues...
|
|
||||||
list_of_cpu_packages : Vec::new(),
|
|
||||||
list_of_disks : Vec::new(),
|
|
||||||
list_of_physical_io : Vec::new(),
|
|
||||||
list_of_io : Vec::new(),
|
|
||||||
list_of_processes : Vec::new(),
|
|
||||||
list_of_temperature : Vec::new(),
|
|
||||||
network : network::NetworkData::default(),
|
|
||||||
memory : mem::MemData::default(),
|
|
||||||
swap : mem::MemData::default(),
|
|
||||||
should_quit : false,
|
should_quit : false,
|
||||||
process_sorting_reverse : false,
|
process_sorting_reverse : false,
|
||||||
|
to_be_resorted : false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,48 +84,38 @@ impl<'a> App<'a> {
|
|||||||
match c {
|
match c {
|
||||||
'q' => self.should_quit = true,
|
'q' => self.should_quit = true,
|
||||||
'c' => {
|
'c' => {
|
||||||
self.process_sorting_type = processes::ProcessSorting::CPU;
|
self.process_sorting_type = processes::ProcessSorting::CPU; // TODO: Change this such that reversing can be done by just hitting "c" twice...
|
||||||
//processes::sort_processes(&self.process_sorting_type, &mut self.list_of_processes, self.process_sorting_reverse);
|
self.to_be_resorted = true;
|
||||||
// TODO: This CANNOT run while it is updating...
|
|
||||||
}
|
}
|
||||||
'm' => {
|
'm' => {
|
||||||
self.process_sorting_type = processes::ProcessSorting::MEM;
|
self.process_sorting_type = processes::ProcessSorting::MEM;
|
||||||
//processes::sort_processes(&self.process_sorting_type, &mut self.list_of_processes, self.process_sorting_reverse);
|
self.to_be_resorted = true;
|
||||||
}
|
}
|
||||||
'p' => {
|
'p' => {
|
||||||
self.process_sorting_type = processes::ProcessSorting::PID;
|
self.process_sorting_type = processes::ProcessSorting::PID;
|
||||||
//processes::sort_processes(&self.process_sorting_type, &mut self.list_of_processes, self.process_sorting_reverse);
|
self.to_be_resorted = true;
|
||||||
}
|
}
|
||||||
'n' => {
|
'n' => {
|
||||||
self.process_sorting_type = processes::ProcessSorting::NAME;
|
self.process_sorting_type = processes::ProcessSorting::NAME;
|
||||||
//processes::sort_processes(&self.process_sorting_type, &mut self.list_of_processes, self.process_sorting_reverse);
|
self.to_be_resorted = true;
|
||||||
}
|
}
|
||||||
'r' => {
|
'r' => {
|
||||||
self.process_sorting_reverse = !self.process_sorting_reverse;
|
self.process_sorting_reverse = !self.process_sorting_reverse;
|
||||||
//processes::sort_processes(&self.process_sorting_type, &mut self.list_of_processes, self.process_sorting_reverse);
|
self.to_be_resorted = true;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_data(&mut self) {
|
pub fn on_left(&mut self) {
|
||||||
self.sys.refresh_system();
|
}
|
||||||
self.sys.refresh_network();
|
|
||||||
|
|
||||||
// What we want to do: For timed data, if there is an error, just do not add. For other data, just don't update!
|
pub fn on_right(&mut self) {
|
||||||
set_if_valid(&network::get_network_data(&self.sys), &mut self.network);
|
}
|
||||||
set_if_valid(&cpu::get_cpu_data_list(&self.sys), &mut self.list_of_cpu_packages);
|
|
||||||
|
|
||||||
// TODO: Joining all futures would be better...
|
pub fn on_up(&mut self) {
|
||||||
set_if_valid(
|
}
|
||||||
&processes::get_sorted_processes_list(&self.process_sorting_type, self.process_sorting_reverse).await,
|
|
||||||
&mut self.list_of_processes,
|
pub fn on_down(&mut self) {
|
||||||
);
|
|
||||||
set_if_valid(&disks::get_disk_usage_list().await, &mut self.list_of_disks);
|
|
||||||
set_if_valid(&disks::get_io_usage_list(false).await, &mut self.list_of_io);
|
|
||||||
set_if_valid(&disks::get_io_usage_list(true).await, &mut self.list_of_physical_io);
|
|
||||||
set_if_valid(&mem::get_mem_data_list().await, &mut self.memory);
|
|
||||||
set_if_valid(&mem::get_swap_data_list().await, &mut self.swap);
|
|
||||||
set_if_valid(&temperature::get_temperature_data().await, &mut self.list_of_temperature);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use heim_common::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum ProcessSorting {
|
pub enum ProcessSorting {
|
||||||
CPU,
|
CPU,
|
||||||
MEM,
|
MEM,
|
||||||
@ -44,13 +45,13 @@ fn get_ordering<T : std::cmp::PartialOrd>(a_val : T, b_val : T, reverse_order :
|
|||||||
|
|
||||||
async fn cpu_usage(process : heim::process::Process) -> heim::process::ProcessResult<(heim::process::Process, heim_common::units::Ratio)> {
|
async fn cpu_usage(process : heim::process::Process) -> heim::process::ProcessResult<(heim::process::Process, heim_common::units::Ratio)> {
|
||||||
let usage_1 = process.cpu_usage().await?;
|
let usage_1 = process.cpu_usage().await?;
|
||||||
futures_timer::Delay::new(std::time::Duration::from_millis(100)).await?; // TODO: This is causing MASSIVE PROBLEMS WITH THE EVENT LOOP!
|
futures_timer::Delay::new(std::time::Duration::from_millis(100)).await?;
|
||||||
let usage_2 = process.cpu_usage().await?;
|
let usage_2 = process.cpu_usage().await?;
|
||||||
|
|
||||||
Ok((process, usage_2 - usage_1))
|
Ok((process, usage_2 - usage_1))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_sorted_processes_list(sorting_method : &ProcessSorting, reverse_order : bool) -> Result<Vec<ProcessData>, heim::Error> {
|
pub async fn get_sorted_processes_list() -> Result<Vec<ProcessData>, heim::Error> {
|
||||||
let mut process_stream = heim::process::processes().map_ok(cpu_usage).try_buffer_unordered(std::usize::MAX);
|
let mut process_stream = heim::process::processes().map_ok(cpu_usage).try_buffer_unordered(std::usize::MAX);
|
||||||
|
|
||||||
let mut process_vector : Vec<ProcessData> = Vec::new();
|
let mut process_vector : Vec<ProcessData> = Vec::new();
|
||||||
@ -78,12 +79,11 @@ pub async fn get_sorted_processes_list(sorting_method : &ProcessSorting, reverse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort_processes(&sorting_method, &mut process_vector, reverse_order);
|
|
||||||
|
|
||||||
Ok(process_vector)
|
Ok(process_vector)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort_processes(sorting_method : &ProcessSorting, process_vector : &mut Vec<ProcessData>, reverse_order : bool) {
|
pub fn sort_processes(process_vector : &mut Vec<ProcessData>, sorting_method : &ProcessSorting, reverse_order : bool) {
|
||||||
match sorting_method {
|
match sorting_method {
|
||||||
ProcessSorting::CPU => process_vector.sort_by(|a, b| get_ordering(a.cpu_usage_percent, b.cpu_usage_percent, reverse_order)),
|
ProcessSorting::CPU => process_vector.sort_by(|a, b| get_ordering(a.cpu_usage_percent, b.cpu_usage_percent, reverse_order)),
|
||||||
ProcessSorting::MEM => process_vector.sort_by(|a, b| get_ordering(a.mem_usage_in_mb, b.mem_usage_in_mb, reverse_order)),
|
ProcessSorting::MEM => process_vector.sort_by(|a, b| get_ordering(a.mem_usage_in_mb, b.mem_usage_in_mb, reverse_order)),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user