use sysinfo::{System, SystemExt, CpuExt};
use tui::{
backend::{Backend, CrosstermBackend},
widgets::{Block, Borders, Paragraph},
layout::{Constraint, Direction, Layout},
style::{Style, Color},
text::{Spans, Span},
Terminal,
};
use crossterm::{
event::{self, Event, KeyCode},
execute,
terminal::{EnterAlternateScreen, LeaveAlternateScreen},
};
use std::{io, time::{Duration, Instant}};
pub struct SystemInfo {
pub total_memory: u64,
pub used_memory: u64,
pub cpu_usage: Vec<f32>,
}
pub fn get_system_info() -> SystemInfo {
let mut sys = System::new_all();
sys.refresh_all();
let total_memory = sys.total_memory();
let used_memory = sys.used_memory();
let cpu_usage = sys.cpus().iter().map(|cpu| cpu.cpu_usage()).collect();
SystemInfo {
total_memory,
used_memory,
cpu_usage,
}
}
pub fn start_tui<B: Backend>(terminal: &mut Terminal<B>, system_info: &SystemInfo) -> io::Result<()> {
terminal.draw(|f| {
let size = f.size();
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(1)
.constraints(
[
Constraint::Percentage(50),
Constraint::Percentage(50),
].as_ref(),
)
.split(size);
let memory_block = Block::default()
.title("Memory Usage")
.borders(Borders::ALL);
let memory_usage = Paragraph::new(format!(
"Total Memory: {} MB\nUsed Memory: {} MB",
system_info.total_memory / 1024,
system_info.used_memory / 1024
))
.block(memory_block)
.style(Style::default().fg(Color::White));
f.render_widget(memory_usage, chunks[0]);
let cpu_block = Block::default()
.title("CPU Usage")
.borders(Borders::ALL);
let cpu_usage_text = system_info.cpu_usage.iter()
.enumerate()
.map(|(i, usage)| Spans::from(Span::raw(format!("CPU {}: {:.2}%", i, usage))))
.collect::<Vec<Spans>>();
let cpu_usage = Paragraph::new(cpu_usage_text)
.block(cpu_block)
.style(Style::default().fg(Color::White));
f.render_widget(cpu_usage, chunks[1]);
})?;
Ok(())
}
pub fn run() -> Result<(), io::Error> {
crossterm::terminal::enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let system_info = get_system_info();
let tick_rate = Duration::from_millis(1000);
let mut last_tick = Instant::now();
loop {
start_tui(&mut terminal, &system_info)?;
if event::poll(tick_rate - last_tick.elapsed())? {
if let Event::Key(key) = event::read()? {
if key.code == KeyCode::Char('q') {
break;
}
}
}
if last_tick.elapsed() >= tick_rate {
last_tick = Instant::now();
}
}
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
crossterm::terminal::disable_raw_mode()?;
Ok(())
}