-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "cores_cli" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
hardwareinfo = { path = "../unix/hardwareinfo" } | ||
ratatui = "0.27.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
use hardwareinfo::{refresh_hardware_info, Data, HardwareInfo, Networks, System}; | ||
use ratatui::{ | ||
backend::CrosstermBackend, | ||
crossterm::{ | ||
event::{self, KeyCode, KeyEventKind}, | ||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, | ||
ExecutableCommand, | ||
}, | ||
layout::{Alignment, Constraint, Direction, Layout}, | ||
style::{Color, Style, Stylize}, | ||
symbols::{self, border}, | ||
text::{Line, Text}, | ||
widgets::{ | ||
block::{Position, Title}, | ||
Block, Borders, Gauge, LineGauge, Paragraph, Tabs, | ||
}, | ||
Terminal, | ||
}; | ||
use std::io::{stdout, Result}; | ||
|
||
struct AppState { | ||
current_tab: usize, | ||
} | ||
|
||
fn main() -> Result<()> { | ||
stdout().execute(EnterAlternateScreen)?; | ||
enable_raw_mode()?; | ||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; | ||
terminal.clear()?; | ||
|
||
// get version from Cargo.toml | ||
let version = std::env!("CARGO_PKG_VERSION"); | ||
|
||
let mut data = Data { | ||
first_run: true, | ||
sys: System::new_all(), | ||
network: Networks::new_with_refreshed_list(), | ||
hw_info: HardwareInfo::default(), | ||
}; | ||
|
||
let mut app_state = AppState { current_tab: 0 }; | ||
|
||
loop { | ||
data.sys.refresh_all(); | ||
std::thread::sleep(hardwareinfo::MINIMUM_CPU_UPDATE_INTERVAL); | ||
data.sys.refresh_all(); | ||
data.network.refresh(); | ||
|
||
refresh_hardware_info(&mut data); | ||
|
||
let title = Title::from(format!(" Cores {} ", version)); | ||
let os = Title::from(format!( | ||
" {} ", | ||
data.hw_info.system.os.name.to_string().yellow() | ||
)); | ||
let instructions = Title::from(Line::from(vec![ | ||
" Navigate with ".into(), | ||
"<Left>".blue().bold(), | ||
" and ".into(), | ||
"<Right>".blue().bold(), | ||
" Quit ".into(), | ||
"<Q> ".blue().bold(), | ||
])); | ||
|
||
let cpu_name = Paragraph::new(Text::from(vec![Line::from(vec![ | ||
" CPU: ".into(), | ||
data.hw_info.cpu.name.to_string().bold(), | ||
format!( | ||
" ({}C/{}T)", | ||
data.hw_info.cpu.info.core_count, data.hw_info.cpu.info.thread_count | ||
) | ||
.into(), | ||
])])); | ||
|
||
let ram_name = Paragraph::new(Text::from(vec![Line::from(vec![ | ||
" RAM: ".into(), | ||
"Generic Memory".to_string().bold(), | ||
format!( | ||
" ({}GB)", | ||
(data.hw_info.ram.load[0].value + data.hw_info.ram.load[1].value) | ||
) | ||
.into(), | ||
])])); | ||
|
||
let interface_name = Paragraph::new(Text::from(vec![Line::from(vec![ | ||
" Network: ".into(), | ||
data.hw_info.system.network.interfaces[0] | ||
.name | ||
.to_string() | ||
.bold(), | ||
])])); | ||
|
||
let cpu_usage = Gauge::default() | ||
.block(Block::bordered().title("CPU Usage")) | ||
.gauge_style(Style::default().fg(Color::Cyan).bg(Color::Black)) | ||
.percent(data.hw_info.cpu.max_load as u16); | ||
|
||
let ram_usage = Gauge::default() | ||
.block(Block::bordered().title("Memory Usage")) | ||
.gauge_style(Style::default().fg(Color::Cyan).bg(Color::Black)) | ||
.percent(data.hw_info.ram.load[2].value as u16); | ||
|
||
let virtual_ram_usage = Gauge::default() | ||
.block(Block::bordered().title("Virtual Memory Usage")) | ||
.gauge_style(Style::default().fg(Color::Cyan).bg(Color::Black)) | ||
.percent(data.hw_info.ram.load[5].value as u16); | ||
|
||
let download_speed = Gauge::default() | ||
.block(Block::bordered().title("Download Speed")) | ||
.gauge_style(Style::default().fg(Color::Cyan).bg(Color::Black)) | ||
.percent(data.hw_info.system.network.interfaces[0].throughput_download as u16 / 5); | ||
|
||
let upload_speed = Gauge::default() | ||
.block(Block::bordered().title("Upload Speed")) | ||
.gauge_style(Style::default().fg(Color::Cyan).bg(Color::Black)) | ||
.percent(data.hw_info.system.network.interfaces[0].throughput_upload as u16 / 5); | ||
|
||
terminal.draw(|frame| { | ||
let main_container = Block::bordered() | ||
.title(title.alignment(Alignment::Left)) | ||
.title(os.alignment(Alignment::Right)) | ||
.title( | ||
instructions | ||
.alignment(Alignment::Center) | ||
.position(Position::Bottom), | ||
) | ||
.border_set(border::THICK); | ||
|
||
// Get the inner area of the outer block | ||
let inner_area = main_container.inner(frame.size()); | ||
|
||
// Render the main container | ||
frame.render_widget(main_container, frame.size()); | ||
|
||
let chunks = Layout::default() | ||
.direction(Direction::Vertical) | ||
.constraints([Constraint::Length(2), Constraint::Min(0)].as_ref()) | ||
.split(inner_area); | ||
|
||
let titles = vec!["Home", "Debug"]; | ||
let tabs = Tabs::new(titles) | ||
.block(Block::default().borders(ratatui::widgets::Borders::NONE)) | ||
.select(app_state.current_tab) | ||
.style(Style::default().fg(Color::White)) | ||
.highlight_style(Style::default().fg(Color::Cyan)); | ||
|
||
frame.render_widget(tabs, chunks[0]); | ||
|
||
match app_state.current_tab { | ||
0 => { | ||
// Main layout covering the inner area with 3-way split | ||
let layout = Layout::default() | ||
.direction(Direction::Horizontal) | ||
.constraints([ | ||
Constraint::Percentage(33), | ||
Constraint::Percentage(34), | ||
Constraint::Percentage(33), | ||
]) | ||
.split(chunks[1]); | ||
|
||
let cpu_layout = Layout::default() | ||
.direction(Direction::Vertical) | ||
.constraints([ | ||
Constraint::Length(1), | ||
Constraint::Length(3), | ||
Constraint::Fill(100), | ||
]) | ||
.split(layout[0]); | ||
|
||
let ram_layout = Layout::default() | ||
.direction(Direction::Vertical) | ||
.constraints([ | ||
Constraint::Length(1), | ||
Constraint::Length(3), | ||
Constraint::Length(3), | ||
Constraint::Length(1), | ||
Constraint::Length(3), | ||
Constraint::Length(3), | ||
]) | ||
.split(layout[1]); | ||
|
||
frame.render_widget(cpu_name.clone(), cpu_layout[0]); | ||
frame.render_widget(cpu_usage.clone(), cpu_layout[1]); | ||
|
||
frame.render_widget(ram_name.clone(), ram_layout[0]); | ||
frame.render_widget(ram_usage.clone(), ram_layout[1]); | ||
frame.render_widget(virtual_ram_usage.clone(), ram_layout[2]); | ||
|
||
frame.render_widget(interface_name.clone(), ram_layout[3]); | ||
frame.render_widget(download_speed.clone(), ram_layout[4]); | ||
frame.render_widget(upload_speed.clone(), ram_layout[5]); | ||
|
||
// Create a layout for core gauges | ||
let num_cores = data.hw_info.cpu.load.len(); | ||
let core_constraints = vec![Constraint::Length(3); num_cores]; | ||
let core_layout = Layout::default() | ||
.direction(Direction::Vertical) | ||
.constraints(core_constraints) | ||
.split(cpu_layout[2]); | ||
|
||
// Render a gauge for each core | ||
for (i, core) in data.hw_info.cpu.load.iter().enumerate() { | ||
let core_gauge = LineGauge::default() | ||
.block( | ||
Block::default() | ||
.borders(Borders::ALL) | ||
.title(format!("Core #{}", i)) | ||
.title_alignment(Alignment::Left), | ||
) | ||
.filled_style(Style::default().fg(Color::Cyan).bg(Color::Black)) | ||
.line_set(symbols::line::THICK) | ||
.ratio(core.value as f64 / 100.0); | ||
|
||
frame.render_widget(core_gauge, core_layout[i]); | ||
} | ||
} | ||
1 => { | ||
let layout = Layout::default() | ||
.direction(Direction::Horizontal) | ||
.constraints([Constraint::Percentage(100)]) | ||
.split(chunks[1]); | ||
|
||
let debug = Paragraph::new(Text::from(vec![format!( | ||
"CPU: {} Load: {}%", | ||
data.hw_info.cpu.name, | ||
data.hw_info.cpu.max_load.floor() | ||
) | ||
.into()])); | ||
|
||
frame.render_widget(debug, layout[0]); | ||
} | ||
_ => {} | ||
} | ||
})?; | ||
|
||
if event::poll(std::time::Duration::from_secs(5))? { | ||
if let event::Event::Key(key) = event::read()? { | ||
match key.code { | ||
KeyCode::Char('q') => break, | ||
KeyCode::Left => app_state.current_tab = (app_state.current_tab + 2) % 3, | ||
KeyCode::Right => app_state.current_tab = (app_state.current_tab + 1) % 3, | ||
_ => {} | ||
} | ||
} | ||
} | ||
} | ||
|
||
stdout().execute(LeaveAlternateScreen)?; | ||
disable_raw_mode()?; | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters