mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-23 13:45:12 +02:00
Refactoring. Lots of it.
This commit is contained in:
parent
50d3be05dd
commit
ae6cd3aa77
@ -11,6 +11,7 @@ pub struct App<'a> {
|
|||||||
pub process_sorting_type : processes::ProcessSorting,
|
pub process_sorting_type : processes::ProcessSorting,
|
||||||
pub process_sorting_reverse : bool,
|
pub process_sorting_reverse : bool,
|
||||||
pub to_be_resorted : bool,
|
pub to_be_resorted : bool,
|
||||||
|
pub current_selected_process_position : u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_if_valid<T : std::clone::Clone>(result : &Result<T, heim::Error>, value_to_set : &mut T) {
|
fn set_if_valid<T : std::clone::Clone>(result : &Result<T, heim::Error>, value_to_set : &mut T) {
|
||||||
@ -32,7 +33,7 @@ pub struct Data {
|
|||||||
pub list_of_physical_io : Vec<disks::IOPackage>,
|
pub list_of_physical_io : Vec<disks::IOPackage>,
|
||||||
pub memory : Vec<mem::MemData>,
|
pub memory : Vec<mem::MemData>,
|
||||||
pub swap : Vec<mem::MemData>,
|
pub swap : Vec<mem::MemData>,
|
||||||
pub list_of_temperature : Vec<temperature::TempData>,
|
pub list_of_temperature_sensor : Vec<temperature::TempData>,
|
||||||
pub network : Vec<network::NetworkData>,
|
pub network : Vec<network::NetworkData>,
|
||||||
pub list_of_processes : Vec<processes::ProcessData>, // Only need to keep a list of processes...
|
pub list_of_processes : Vec<processes::ProcessData>, // Only need to keep a list of processes...
|
||||||
pub list_of_disks : Vec<disks::DiskData>, // Only need to keep a list of disks and their data
|
pub list_of_disks : Vec<disks::DiskData>, // Only need to keep a list of disks and their data
|
||||||
@ -90,7 +91,7 @@ impl DataState {
|
|||||||
set_if_valid(&disks::get_disk_usage_list().await, &mut self.data.list_of_disks);
|
set_if_valid(&disks::get_disk_usage_list().await, &mut self.data.list_of_disks);
|
||||||
push_if_valid(&disks::get_io_usage_list(false).await, &mut self.data.list_of_io);
|
push_if_valid(&disks::get_io_usage_list(false).await, &mut self.data.list_of_io);
|
||||||
push_if_valid(&disks::get_io_usage_list(true).await, &mut self.data.list_of_physical_io);
|
push_if_valid(&disks::get_io_usage_list(true).await, &mut self.data.list_of_physical_io);
|
||||||
set_if_valid(&temperature::get_temperature_data().await, &mut self.data.list_of_temperature);
|
set_if_valid(&temperature::get_temperature_data().await, &mut self.data.list_of_temperature_sensor);
|
||||||
|
|
||||||
// Filter out stale timed entries
|
// Filter out stale timed entries
|
||||||
// TODO: ideally make this a generic function!
|
// TODO: ideally make this a generic function!
|
||||||
@ -155,6 +156,7 @@ impl<'a> App<'a> {
|
|||||||
should_quit : false,
|
should_quit : false,
|
||||||
process_sorting_reverse : true,
|
process_sorting_reverse : true,
|
||||||
to_be_resorted : false,
|
to_be_resorted : false,
|
||||||
|
current_selected_process_position : 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,154 @@
|
|||||||
|
use std::io;
|
||||||
use tui::{
|
use tui::{
|
||||||
layout::{Constraint, Direction, Layout},
|
layout::{Constraint, Direction, Layout},
|
||||||
style::{Color, Style},
|
style::{Color, Style},
|
||||||
widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Row, Table, Widget},
|
widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Row, Table, Widget},
|
||||||
Terminal,
|
Terminal,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const COLOUR_LIST : [Color; 6] = [Color::LightCyan, Color::LightMagenta, Color::LightRed, Color::LightGreen, Color::LightYellow, Color::LightBlue];
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct CanvasData {
|
||||||
|
pub disk_data : Vec<Vec<String>>,
|
||||||
|
pub temp_sensor_data : Vec<Vec<String>>,
|
||||||
|
pub process_data : Vec<Vec<String>>,
|
||||||
|
pub mem_data : Vec<(f64, f64)>,
|
||||||
|
pub swap_data : Vec<(f64, f64)>,
|
||||||
|
pub cpu_data : Vec<(String, Vec<(f64, f64)>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Change the error
|
||||||
|
pub fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, canvas_data : &CanvasData) -> Result<(), io::Error> {
|
||||||
|
let temperature_rows = canvas_data.temp_sensor_data.iter().map(|sensor| {
|
||||||
|
Row::StyledData(
|
||||||
|
sensor.iter(), // TODO: Change this based on temperature type
|
||||||
|
Style::default().fg(Color::White),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let disk_rows = canvas_data.disk_data.iter().map(|disk| {
|
||||||
|
Row::StyledData(
|
||||||
|
disk.iter(), // TODO: Change this based on temperature type
|
||||||
|
Style::default().fg(Color::White),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let process_rows = canvas_data.process_data.iter().map(|process| Row::StyledData(process.iter(), Style::default().fg(Color::White)));
|
||||||
|
|
||||||
|
// TODO: Convert this into a separate func!
|
||||||
|
terminal.draw(|mut f| {
|
||||||
|
let vertical_chunks = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.margin(1)
|
||||||
|
.constraints([Constraint::Percentage(35), Constraint::Percentage(30), Constraint::Percentage(35)].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_1 = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.margin(0)
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||||
|
.split(middle_chunks[0]);
|
||||||
|
let middle_divided_chunk_2 = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.margin(0)
|
||||||
|
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||||
|
.split(middle_chunks[1]);
|
||||||
|
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
|
||||||
|
{
|
||||||
|
debug!("Drawing CPU...");
|
||||||
|
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 mut dataset_vector : Vec<Dataset> = Vec::new();
|
||||||
|
for (i, cpu) in canvas_data.cpu_data.iter().enumerate() {
|
||||||
|
dataset_vector.push(
|
||||||
|
Dataset::default()
|
||||||
|
.name(&cpu.0)
|
||||||
|
.marker(Marker::Braille)
|
||||||
|
.style(Style::default().fg(COLOUR_LIST[i % COLOUR_LIST.len()]))
|
||||||
|
.data(&(cpu.1)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Chart::default()
|
||||||
|
.block(Block::default().title("CPU Usage").borders(Borders::ALL))
|
||||||
|
.x_axis(x_axis)
|
||||||
|
.y_axis(y_axis)
|
||||||
|
.datasets(&dataset_vector)
|
||||||
|
.render(&mut f, top_chunks[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Memory usage graph
|
||||||
|
{
|
||||||
|
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"]);
|
||||||
|
Chart::default()
|
||||||
|
.block(Block::default().title("Memory Usage").borders(Borders::ALL))
|
||||||
|
.x_axis(x_axis)
|
||||||
|
.y_axis(y_axis)
|
||||||
|
.datasets(&[
|
||||||
|
Dataset::default()
|
||||||
|
.name(&("MEM :".to_string() + &format!("{:3}%", (canvas_data.mem_data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64))))
|
||||||
|
.marker(Marker::Braille)
|
||||||
|
.style(Style::default().fg(Color::Cyan))
|
||||||
|
.data(&canvas_data.mem_data),
|
||||||
|
Dataset::default()
|
||||||
|
.name(&("SWAP:".to_string() + &format!("{:3}%", (canvas_data.swap_data.last().unwrap_or(&(0_f64, 0_f64)).1.round() as u64))))
|
||||||
|
.marker(Marker::Braille)
|
||||||
|
.style(Style::default().fg(Color::LightGreen))
|
||||||
|
.data(&canvas_data.swap_data),
|
||||||
|
])
|
||||||
|
.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(&[15, 5])
|
||||||
|
.render(&mut f, middle_divided_chunk_1[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(&[15, 10, 5, 5, 5])
|
||||||
|
.render(&mut f, middle_divided_chunk_1[1]);
|
||||||
|
|
||||||
|
// Temp graph
|
||||||
|
Block::default().title("Temperatures").borders(Borders::ALL).render(&mut f, middle_divided_chunk_2[0]);
|
||||||
|
|
||||||
|
// IO graph
|
||||||
|
Block::default().title("IO Usage").borders(Borders::ALL).render(&mut f, middle_divided_chunk_2[1]);
|
||||||
|
|
||||||
|
// Network graph
|
||||||
|
Block::default().title("Network").borders(Borders::ALL).render(&mut f, bottom_chunks[0]);
|
||||||
|
|
||||||
|
// Processes table
|
||||||
|
Table::new(["PID", "Name", "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(())
|
||||||
|
}
|
||||||
|
252
src/main.rs
252
src/main.rs
@ -1,17 +1,13 @@
|
|||||||
#![feature(async_closure)]
|
#![feature(async_closure)]
|
||||||
use crossterm::{input, AlternateScreen, InputEvent, KeyEvent};
|
use crossterm::{input, AlternateScreen, InputEvent, KeyEvent};
|
||||||
use std::{io, sync::mpsc, thread, time::Duration};
|
use std::{io, sync::mpsc, thread, time::Duration};
|
||||||
use tui::{
|
use tui::{backend::CrosstermBackend, Terminal};
|
||||||
backend::CrosstermBackend,
|
|
||||||
layout::{Constraint, Direction, Layout},
|
|
||||||
style::{Color, Modifier, Style},
|
|
||||||
widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Row, Table, Widget},
|
|
||||||
Terminal,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
use app::data_collection;
|
use app::data_collection;
|
||||||
|
|
||||||
|
mod canvas;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
@ -72,8 +68,7 @@ async fn main() -> Result<(), io::Error> {
|
|||||||
terminal.clear()?;
|
terminal.clear()?;
|
||||||
|
|
||||||
let mut app_data = app::Data::default();
|
let mut app_data = app::Data::default();
|
||||||
let mut swap_data : Vec<(f64, f64)> = Vec::new();
|
let mut canvas_data = canvas::CanvasData::default();
|
||||||
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)) {
|
||||||
@ -105,8 +100,12 @@ async fn main() -> Result<(), io::Error> {
|
|||||||
try_debug(&log, "Update event complete.");
|
try_debug(&log, "Update event complete.");
|
||||||
|
|
||||||
// Convert all data into tui components
|
// Convert all data into tui components
|
||||||
mem_data = update_mem_data_points(&app_data);
|
canvas_data.disk_data = update_disk_row(&app_data);
|
||||||
swap_data = update_swap_data_points(&app_data);
|
canvas_data.temp_sensor_data = update_temp_row(&app_data);
|
||||||
|
canvas_data.process_data = update_process_row(&app_data);
|
||||||
|
canvas_data.mem_data = update_mem_data_points(&app_data);
|
||||||
|
canvas_data.swap_data = update_swap_data_points(&app_data);
|
||||||
|
canvas_data.cpu_data = update_cpu_data_points(&app_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if app.should_quit {
|
if app.should_quit {
|
||||||
@ -116,54 +115,70 @@ async fn main() -> Result<(), io::Error> {
|
|||||||
|
|
||||||
// Draw!
|
// Draw!
|
||||||
// TODO: We should change this btw! It should not redraw everything on every tick!
|
// TODO: We should change this btw! It should not redraw everything on every tick!
|
||||||
draw_data(&mut terminal, &app_data, &mem_data, &swap_data)?;
|
canvas::draw_data(&mut terminal, &canvas_data)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_temp_row(app_data : &app::Data) {
|
fn update_temp_row(app_data : &app::Data) -> 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.to_string() + "C"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor_vector
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_process_row(app_data : &app::Data) {
|
fn update_disk_row(app_data : &app::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),
|
||||||
|
(disk.free_space / 1024).to_string() + "GB",
|
||||||
|
(disk.total_space / 1024).to_string() + "GB",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
disk_vector
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_cpu_data_points(app_data : &app::Data) {
|
fn update_process_row(app_data : &app::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_mem_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
|
fn update_cpu_data_points(app_data : &app::Data) -> Vec<(String, Vec<(f64, f64)>)> {
|
||||||
convert_mem_data(&app_data.memory)
|
let mut cpu_vector : Vec<(String, Vec<(f64, f64)>)> = Vec::new();
|
||||||
}
|
|
||||||
|
|
||||||
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| {
|
|
||||||
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!("{:.1}%", 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 mut dataset_vector : Vec<Dataset> = Vec::new();
|
|
||||||
let mut data_vector : Vec<Vec<(f64, f64)>> = Vec::new();
|
let mut data_vector : Vec<Vec<(f64, f64)>> = Vec::new();
|
||||||
|
|
||||||
if !app_data.list_of_cpu_packages.is_empty() {
|
if !app_data.list_of_cpu_packages.is_empty() {
|
||||||
@ -179,141 +194,22 @@ fn draw_data<B : tui::backend::Backend>(terminal : &mut Terminal<B>, app_data :
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i, data) in data_vector.iter().enumerate() {
|
for (i, data) in data_vector.iter().enumerate() {
|
||||||
dataset_vector.push(
|
cpu_vector.push((
|
||||||
Dataset::default()
|
(&*(app_data.list_of_cpu_packages.last().unwrap().cpu_vec[i].cpu_name)).to_string() + " " + &format!("{:.2}", data.last().unwrap_or(&(0_f64, 0_f64)).1.to_string()),
|
||||||
.name(&*(app_data.list_of_cpu_packages.last().unwrap().cpu_vec[i].cpu_name))
|
data.clone(),
|
||||||
.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| {
|
cpu_vector
|
||||||
Row::StyledData(
|
}
|
||||||
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
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]
|
|
||||||
.into_iter(),
|
|
||||||
Style::default().fg(Color::LightGreen),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Convert this into a separate func!
|
fn update_mem_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
|
||||||
terminal.draw(|mut f| {
|
convert_mem_data(&app_data.memory)
|
||||||
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_1 = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.margin(0)
|
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
|
||||||
.split(middle_chunks[0]);
|
|
||||||
let middle_divided_chunk_2 = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.margin(0)
|
|
||||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
|
||||||
.split(middle_chunks[1]);
|
|
||||||
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
|
fn update_swap_data_points(app_data : &app::Data) -> Vec<(f64, f64)> {
|
||||||
|
convert_mem_data(&app_data.swap)
|
||||||
// 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 y_axis = Axis::default().style(Style::default().fg(Color::White)).bounds([0.0, 100.0]).labels(&["0.0", "50.0", "100.0"]);
|
|
||||||
|
|
||||||
Chart::default()
|
|
||||||
.block(Block::default().title("CPU Usage").borders(Borders::ALL))
|
|
||||||
.x_axis(x_axis)
|
|
||||||
.y_axis(y_axis)
|
|
||||||
.datasets(&dataset_vector)
|
|
||||||
.render(&mut f, top_chunks[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Memory usage graph
|
|
||||||
{
|
|
||||||
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"]);
|
|
||||||
Chart::default()
|
|
||||||
.block(Block::default().title("Memory Usage").borders(Borders::ALL))
|
|
||||||
.x_axis(x_axis)
|
|
||||||
.y_axis(y_axis)
|
|
||||||
.datasets(&[
|
|
||||||
Dataset::default().name("MEM").marker(Marker::Braille).style(Style::default().fg(Color::Cyan)).data(&mem_data),
|
|
||||||
Dataset::default().name("SWAP").marker(Marker::Braille).style(Style::default().fg(Color::LightGreen)).data(&swap_data),
|
|
||||||
])
|
|
||||||
.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(&[15, 5])
|
|
||||||
.render(&mut f, middle_divided_chunk_1[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(&[15, 10, 5, 5, 5])
|
|
||||||
.render(&mut f, middle_divided_chunk_1[1]);
|
|
||||||
|
|
||||||
// Temp graph
|
|
||||||
Block::default().title("Temperatures").borders(Borders::ALL).render(&mut f, middle_divided_chunk_2[0]);
|
|
||||||
|
|
||||||
// IO graph
|
|
||||||
Block::default().title("IO Usage").borders(Borders::ALL).render(&mut f, middle_divided_chunk_2[1]);
|
|
||||||
|
|
||||||
// Network graph
|
|
||||||
Block::default().title("Network").borders(Borders::ALL).render(&mut f, bottom_chunks[0]);
|
|
||||||
|
|
||||||
// Processes table
|
|
||||||
Table::new(["PID", "Name", "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 convert_mem_data(mem_data : &[app::data_collection::mem::MemData]) -> Vec<(f64, f64)> {
|
fn convert_mem_data(mem_data : &[app::data_collection::mem::MemData]) -> Vec<(f64, f64)> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user