Fix TUI borrow checker and generic type issues
This commit is contained in:
@@ -180,7 +180,8 @@ impl App {
|
|||||||
let mut suspicious_count = 0;
|
let mut suspicious_count = 0;
|
||||||
let mut malicious_count = 0;
|
let mut malicious_count = 0;
|
||||||
|
|
||||||
for proc in &self.processes {
|
let processes = self.processes.clone();
|
||||||
|
for proc in &processes {
|
||||||
if Self::should_skip_process(proc) {
|
if Self::should_skip_process(proc) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,14 +20,14 @@ use ratatui::{
|
|||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
io,
|
io,
|
||||||
sync::{Arc, Mutex},
|
sync::Arc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use tokio::time;
|
use tokio::{sync::Mutex, time};
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod ui;
|
|
||||||
mod events;
|
mod events;
|
||||||
|
mod ui;
|
||||||
|
|
||||||
use app::{App, TabIndex};
|
use app::{App, TabIndex};
|
||||||
|
|
||||||
@@ -78,15 +78,12 @@ async fn main() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_app<B: Backend>(
|
async fn run_app<B: Backend>(terminal: &mut Terminal<B>, app: Arc<Mutex<App>>) -> Result<()> {
|
||||||
terminal: &mut Terminal<B>,
|
|
||||||
app: Arc<Mutex<App>>,
|
|
||||||
) -> Result<()> {
|
|
||||||
loop {
|
loop {
|
||||||
// Draw the UI
|
// Draw the UI
|
||||||
terminal.draw(|f| {
|
terminal.draw(|f| {
|
||||||
if let Ok(app) = app.try_lock() {
|
if let Ok(app) = app.try_lock() {
|
||||||
ui::draw(f, &app);
|
ui::draw::<CrosstermBackend<std::io::Stdout>>(f, &app);
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|||||||
@@ -44,19 +44,20 @@ pub fn draw<B: Backend>(f: &mut Frame, app: &App) {
|
|||||||
.split(size);
|
.split(size);
|
||||||
|
|
||||||
// Draw header
|
// Draw header
|
||||||
draw_header(f, chunks[0], app);
|
draw_header::<B>(f, chunks[0], app);
|
||||||
|
|
||||||
// Draw main content based on selected tab
|
// Draw main content based on selected tab
|
||||||
match app.current_tab {
|
match app.current_tab {
|
||||||
TabIndex::Overview => draw_overview(f, chunks[1], app),
|
TabIndex::Overview => draw_overview::<B>(f, chunks[1], app),
|
||||||
TabIndex::Processes => draw_processes(f, chunks[1], app),
|
TabIndex::Processes => draw_processes::<B>(f, chunks[1], app),
|
||||||
TabIndex::Detections => draw_detections(f, chunks[1], app),
|
TabIndex::Detections => draw_detections::<B>(f, chunks[1], app),
|
||||||
TabIndex::Memory => draw_memory(f, chunks[1], app),
|
TabIndex::Memory => draw_memory::<B>(f, chunks[1], app),
|
||||||
TabIndex::Logs => draw_logs(f, chunks[1], app),
|
TabIndex::Logs => draw_logs::<B>(f, chunks[1], app),
|
||||||
|
TabIndex::ThreatIntel => {} // TODO: Implement threat intel view
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw footer
|
// Draw footer
|
||||||
draw_footer(f, chunks[2], app);
|
draw_footer::<B>(f, chunks[2], app);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_header<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
fn draw_header<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
||||||
@@ -83,11 +84,18 @@ fn draw_header<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
|||||||
|
|
||||||
fn draw_footer<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
fn draw_footer<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
||||||
let help_text = match app.current_tab {
|
let help_text = match app.current_tab {
|
||||||
TabIndex::Overview => "Up/Down: Navigate | Tab: Switch tabs | R: Refresh | C: Clear | Q: Quit",
|
TabIndex::Overview => {
|
||||||
TabIndex::Processes => "Up/Down: Select process | Enter: View details | Tab: Switch tabs | Q: Quit",
|
"Up/Down: Navigate | Tab: Switch tabs | R: Refresh | C: Clear | Q: Quit"
|
||||||
TabIndex::Detections => "Up/Down: Navigate detections | C: Clear history | Tab: Switch tabs | Q: Quit",
|
}
|
||||||
|
TabIndex::Processes => {
|
||||||
|
"Up/Down: Select process | Enter: View details | Tab: Switch tabs | Q: Quit"
|
||||||
|
}
|
||||||
|
TabIndex::Detections => {
|
||||||
|
"Up/Down: Navigate detections | C: Clear history | Tab: Switch tabs | Q: Quit"
|
||||||
|
}
|
||||||
TabIndex::Memory => "Up/Down: Navigate | Tab: Switch tabs | R: Refresh | Q: Quit",
|
TabIndex::Memory => "Up/Down: Navigate | Tab: Switch tabs | R: Refresh | Q: Quit",
|
||||||
TabIndex::Logs => "Up/Down: Navigate logs | C: Clear logs | Tab: Switch tabs | Q: Quit",
|
TabIndex::Logs => "Up/Down: Navigate logs | C: Clear logs | Tab: Switch tabs | Q: Quit",
|
||||||
|
TabIndex::ThreatIntel => "Up/Down: Navigate threats | Tab: Switch tabs | Q: Quit",
|
||||||
};
|
};
|
||||||
|
|
||||||
let footer = Paragraph::new(help_text)
|
let footer = Paragraph::new(help_text)
|
||||||
@@ -106,20 +114,20 @@ fn draw_overview<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
|||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([
|
.constraints([
|
||||||
Constraint::Length(8), // Stats
|
Constraint::Length(8), // Stats
|
||||||
Constraint::Length(8), // Threat level gauge
|
Constraint::Length(8), // Threat level gauge
|
||||||
Constraint::Min(0), // Recent detections
|
Constraint::Min(0), // Recent detections
|
||||||
])
|
])
|
||||||
.split(area);
|
.split(area);
|
||||||
|
|
||||||
// Statistics panel
|
// Statistics panel
|
||||||
draw_stats_panel(f, chunks[0], app);
|
draw_stats_panel::<B>(f, chunks[0], app);
|
||||||
|
|
||||||
// Threat level gauge
|
// Threat level gauge
|
||||||
draw_threat_gauge(f, chunks[1], app);
|
draw_threat_gauge::<B>(f, chunks[1], app);
|
||||||
|
|
||||||
// Recent detections
|
// Recent detections
|
||||||
draw_recent_detections(f, chunks[2], app);
|
draw_recent_detections::<B>(f, chunks[2], app);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_stats_panel<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
fn draw_stats_panel<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
||||||
@@ -280,24 +288,28 @@ fn draw_processes<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
|||||||
|
|
||||||
let header = Row::new(header_cells).height(1).bottom_margin(1);
|
let header = Row::new(header_cells).height(1).bottom_margin(1);
|
||||||
|
|
||||||
let rows: Vec<Row> = app.processes.iter().map(|proc| {
|
let rows: Vec<Row> = app
|
||||||
let status = match app.detections.iter().find(|d| d.process.pid == proc.pid) {
|
.processes
|
||||||
Some(detection) => match detection.threat_level {
|
.iter()
|
||||||
ThreatLevel::Malicious => "MALICIOUS",
|
.map(|proc| {
|
||||||
ThreatLevel::Suspicious => "SUSPICIOUS",
|
let status = match app.detections.iter().find(|d| d.process.pid == proc.pid) {
|
||||||
ThreatLevel::Clean => "CLEAN",
|
Some(detection) => match detection.threat_level {
|
||||||
},
|
ThreatLevel::Malicious => "MALICIOUS",
|
||||||
None => "CLEAN",
|
ThreatLevel::Suspicious => "SUSPICIOUS",
|
||||||
};
|
ThreatLevel::Clean => "CLEAN",
|
||||||
|
},
|
||||||
|
None => "CLEAN",
|
||||||
|
};
|
||||||
|
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
Cell::from(proc.pid.to_string()),
|
Cell::from(proc.pid.to_string()),
|
||||||
Cell::from(proc.ppid.to_string()),
|
Cell::from(proc.ppid.to_string()),
|
||||||
Cell::from(proc.name.as_str()),
|
Cell::from(proc.name.as_str()),
|
||||||
Cell::from(proc.thread_count.to_string()),
|
Cell::from(proc.thread_count.to_string()),
|
||||||
Cell::from(status),
|
Cell::from(status),
|
||||||
])
|
])
|
||||||
}).collect();
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let table = Table::new(rows)
|
let table = Table::new(rows)
|
||||||
.header(header)
|
.header(header)
|
||||||
@@ -320,7 +332,7 @@ fn draw_processes<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
|||||||
f.render_stateful_widget(table, chunks[0], &mut state);
|
f.render_stateful_widget(table, chunks[0], &mut state);
|
||||||
|
|
||||||
// Process details panel
|
// Process details panel
|
||||||
draw_process_details(f, chunks[1], app);
|
draw_process_details::<B>(f, chunks[1], app);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_process_details<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
fn draw_process_details<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
||||||
@@ -394,7 +406,10 @@ fn draw_detections<B: Backend>(f: &mut Frame, area: Rect, app: &App) {
|
|||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.title(format!("Detection History ({} total)", app.detections.len()))
|
.title(format!(
|
||||||
|
"Detection History ({} total)",
|
||||||
|
app.detections.len()
|
||||||
|
))
|
||||||
.border_style(Style::default().fg(DANGER)),
|
.border_style(Style::default().fg(DANGER)),
|
||||||
)
|
)
|
||||||
.style(Style::default().fg(TEXT));
|
.style(Style::default().fg(TEXT));
|
||||||
|
|||||||
Reference in New Issue
Block a user