use std::time::Duration;
use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, MouseEvent};
use tokio::sync::mpsc;
use crate::error::TuiError;
use muxtop_core::system::SystemSnapshot;
pub const TICK_RATE: Duration = Duration::from_millis(16);
#[derive(Debug)]
pub enum Event {
Tick,
Key(KeyEvent),
Mouse(MouseEvent),
Resize(u16, u16),
Snapshot(SystemSnapshot),
}
pub struct EventHandler {
rx: mpsc::Receiver<SystemSnapshot>,
}
impl EventHandler {
pub fn new(rx: mpsc::Receiver<SystemSnapshot>) -> Self {
Self { rx }
}
pub fn poll_event(&mut self) -> Result<Event, TuiError> {
let mut latest_snapshot = None;
while let Ok(snapshot) = self.rx.try_recv() {
latest_snapshot = Some(snapshot);
}
if let Some(snapshot) = latest_snapshot {
return Ok(Event::Snapshot(snapshot));
}
if event::poll(TICK_RATE)? {
match event::read()? {
CrosstermEvent::Key(key) => Ok(Event::Key(key)),
CrosstermEvent::Mouse(mouse) => Ok(Event::Mouse(mouse)),
CrosstermEvent::Resize(w, h) => Ok(Event::Resize(w, h)),
_ => Ok(Event::Tick),
}
} else {
Ok(Event::Tick)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crossterm::event::{KeyCode, KeyModifiers};
#[test]
fn test_event_variants_constructible() {
let tick = Event::Tick;
assert!(!format!("{tick:?}").is_empty());
let key = Event::Key(KeyEvent::new(KeyCode::Char('q'), KeyModifiers::NONE));
assert!(!format!("{key:?}").is_empty());
let mouse = Event::Mouse(MouseEvent {
kind: crossterm::event::MouseEventKind::Down(crossterm::event::MouseButton::Left),
column: 0,
row: 0,
modifiers: KeyModifiers::NONE,
});
assert!(!format!("{mouse:?}").is_empty());
let resize = Event::Resize(80, 24);
assert!(!format!("{resize:?}").is_empty());
use muxtop_core::system::{CpuSnapshot, LoadSnapshot, MemorySnapshot};
use std::time::Instant;
let snap = SystemSnapshot {
cpu: CpuSnapshot {
global_usage: 0.0,
cores: vec![],
},
memory: MemorySnapshot {
total: 0,
used: 0,
available: 0,
swap_total: 0,
swap_used: 0,
},
load: LoadSnapshot {
one: 0.0,
five: 0.0,
fifteen: 0.0,
uptime_secs: 0,
},
processes: vec![],
timestamp: Instant::now(),
};
let snapshot_event = Event::Snapshot(snap);
assert!(!format!("{snapshot_event:?}").is_empty());
}
#[test]
fn test_event_handler_new() {
let (_tx, rx) = mpsc::channel::<SystemSnapshot>(1);
let _handler = EventHandler::new(rx);
}
#[test]
fn test_tick_rate_is_16ms() {
assert_eq!(TICK_RATE, Duration::from_millis(16));
}
}