From 274a485f8d5c824cdaddaef0080d9017f6f52d10 Mon Sep 17 00:00:00 2001 From: jasonwitty Date: Fri, 8 Aug 2025 17:25:15 -0700 Subject: [PATCH] fmt: apply rustfmt --- socktop/src/app.rs | 45 ++++++++++++--- socktop/src/history.rs | 7 ++- socktop/src/main.rs | 4 +- socktop/src/types.rs | 2 +- socktop/src/ui/cpu.rs | 54 ++++++++++++----- socktop/src/ui/disks.rs | 36 +++++++++--- socktop/src/ui/header.rs | 26 ++++++--- socktop/src/ui/mem.rs | 16 +++-- socktop/src/ui/mod.rs | 8 +-- socktop/src/ui/net.rs | 10 +++- socktop/src/ui/processes.rs | 109 +++++++++++++++++++++-------------- socktop/src/ui/swap.rs | 16 +++-- socktop/src/ui/util.rs | 44 +++++++++----- socktop/src/ws.rs | 2 +- socktop_agent/src/main.rs | 32 +++++----- socktop_agent/src/metrics.rs | 7 ++- socktop_agent/src/sampler.rs | 9 ++- socktop_agent/src/state.rs | 6 +- socktop_agent/src/types.rs | 2 +- socktop_agent/src/ws.rs | 2 +- 20 files changed, 298 insertions(+), 139 deletions(-) diff --git a/socktop/src/app.rs b/socktop/src/app.rs index 7d831ec..e58bf10 100644 --- a/socktop/src/app.rs +++ b/socktop/src/app.rs @@ -1,6 +1,10 @@ //! App state and main loop: input handling, fetching metrics, updating history, and drawing. -use std::{collections::VecDeque, io, time::{Duration, Instant}}; +use std::{ + collections::VecDeque, + io, + time::{Duration, Instant}, +}; use crossterm::{ event::{self, Event, KeyCode}, @@ -16,7 +20,15 @@ use tokio::time::sleep; use crate::history::{push_capped, PerCoreHistory}; use crate::types::Metrics; -use crate::ui::{header::draw_header, cpu::{draw_cpu_avg_graph, draw_per_core_bars}, mem::draw_mem, swap::draw_swap, disks::draw_disks, net::draw_net_spark, processes::draw_top_processes}; +use crate::ui::{ + cpu::{draw_cpu_avg_graph, draw_per_core_bars}, + disks::draw_disks, + header::draw_header, + mem::draw_mem, + net::draw_net_spark, + processes::draw_top_processes, + swap::draw_swap, +}; use crate::ws::{connect, request_metrics}; pub struct App { @@ -88,7 +100,10 @@ impl App { // Input (non-blocking) while event::poll(Duration::from_millis(10))? { if let Event::Key(k) = event::read()? { - if matches!(k.code, KeyCode::Char('q') | KeyCode::Char('Q') | KeyCode::Esc) { + if matches!( + k.code, + KeyCode::Char('q') | KeyCode::Char('Q') | KeyCode::Esc + ) { self.should_quit = true; } } @@ -130,7 +145,9 @@ impl App { let rx = ((rx_total.saturating_sub(prx)) as f64 / dt / 1024.0).round() as u64; let tx = ((tx_total.saturating_sub(ptx)) as f64 / dt / 1024.0).round() as u64; (rx, tx) - } else { (0, 0) }; + } else { + (0, 0) + }; self.last_net_totals = Some((rx_total, tx_total, now)); push_capped(&mut self.rx_hist, rx_kb, 600); push_capped(&mut self.tx_hist, tx_kb, 600); @@ -174,25 +191,37 @@ impl App { let left_stack = ratatui::layout::Layout::default() .direction(Direction::Vertical) - .constraints([Constraint::Min(6), Constraint::Length(4), Constraint::Length(4)]) + .constraints([ + Constraint::Min(6), + Constraint::Length(4), + Constraint::Length(4), + ]) .split(bottom[0]); draw_disks(f, left_stack[0], self.last_metrics.as_ref()); draw_net_spark( f, left_stack[1], - &format!("Download (KB/s) — now: {} | peak: {}", self.rx_hist.back().copied().unwrap_or(0), self.rx_peak), + &format!( + "Download (KB/s) — now: {} | peak: {}", + self.rx_hist.back().copied().unwrap_or(0), + self.rx_peak + ), &self.rx_hist, ratatui::style::Color::Green, ); draw_net_spark( f, left_stack[2], - &format!("Upload (KB/s) — now: {} | peak: {}", self.tx_hist.back().copied().unwrap_or(0), self.tx_peak), + &format!( + "Upload (KB/s) — now: {} | peak: {}", + self.tx_hist.back().copied().unwrap_or(0), + self.tx_peak + ), &self.tx_hist, ratatui::style::Color::Blue, ); draw_top_processes(f, bottom[1], self.last_metrics.as_ref()); } -} \ No newline at end of file +} diff --git a/socktop/src/history.rs b/socktop/src/history.rs index 27d3232..64babff 100644 --- a/socktop/src/history.rs +++ b/socktop/src/history.rs @@ -17,7 +17,10 @@ pub struct PerCoreHistory { impl PerCoreHistory { pub fn new(cap: usize) -> Self { - Self { deques: Vec::new(), cap } + Self { + deques: Vec::new(), + cap, + } } // Ensure we have one deque per core; resize on CPU topology changes @@ -36,4 +39,4 @@ impl PerCoreHistory { push_capped(&mut self.deques[i], val, self.cap); } } -} \ No newline at end of file +} diff --git a/socktop/src/main.rs b/socktop/src/main.rs index 27126fa..dd447dd 100644 --- a/socktop/src/main.rs +++ b/socktop/src/main.rs @@ -6,8 +6,8 @@ mod types; mod ui; mod ws; -use std::env; use app::App; +use std::env; #[tokio::main] async fn main() -> Result<(), Box> { @@ -27,4 +27,4 @@ async fn main() -> Result<(), Box> { let mut app = App::new(); app.run(&url).await -} \ No newline at end of file +} diff --git a/socktop/src/types.rs b/socktop/src/types.rs index 8a4093f..d5386ec 100644 --- a/socktop/src/types.rs +++ b/socktop/src/types.rs @@ -38,4 +38,4 @@ pub struct Metrics { pub disks: Vec, pub networks: Vec, pub top_processes: Vec, -} \ No newline at end of file +} diff --git a/socktop/src/ui/cpu.rs b/socktop/src/ui/cpu.rs index 84082d3..99c65dd 100644 --- a/socktop/src/ui/cpu.rs +++ b/socktop/src/ui/cpu.rs @@ -1,12 +1,12 @@ //! CPU average sparkline + per-core mini bars. +use ratatui::style::Modifier; use ratatui::{ layout::{Constraint, Direction, Layout, Rect}, style::{Color, Style}, text::{Line, Span}, widgets::{Block, Borders, Paragraph, Sparkline}, }; -use ratatui::style::Modifier; use crate::history::PerCoreHistory; use crate::types::Metrics; @@ -17,7 +17,11 @@ pub fn draw_cpu_avg_graph( hist: &std::collections::VecDeque, m: Option<&Metrics>, ) { - let title = if let Some(mm) = m { format!("CPU avg (now: {:>5.1}%)", mm.cpu_total) } else { "CPU avg".into() }; + let title = if let Some(mm) = m { + format!("CPU avg (now: {:>5.1}%)", mm.cpu_total) + } else { + "CPU avg".into() + }; let max_points = area.width.saturating_sub(2) as usize; let start = hist.len().saturating_sub(max_points); let data: Vec = hist.iter().skip(start).cloned().collect(); @@ -35,16 +39,31 @@ pub fn draw_per_core_bars( m: Option<&Metrics>, per_core_hist: &PerCoreHistory, ) { - f.render_widget(Block::default().borders(Borders::ALL).title("Per-core"), area); - let Some(mm) = m else { return; }; + f.render_widget( + Block::default().borders(Borders::ALL).title("Per-core"), + area, + ); + let Some(mm) = m else { + return; + }; - let inner = Rect { x: area.x + 1, y: area.y + 1, width: area.width.saturating_sub(2), height: area.height.saturating_sub(2) }; - if inner.height == 0 { return; } + let inner = Rect { + x: area.x + 1, + y: area.y + 1, + width: area.width.saturating_sub(2), + height: area.height.saturating_sub(2), + }; + if inner.height == 0 { + return; + } let rows = inner.height as usize; let show_n = rows.min(mm.cpu_per_core.len()); let constraints: Vec = (0..show_n).map(|_| Constraint::Length(1)).collect(); - let vchunks = Layout::default().direction(Direction::Vertical).constraints(constraints).split(inner); + let vchunks = Layout::default() + .direction(Direction::Vertical) + .constraints(constraints) + .split(inner); for i in 0..show_n { let rect = vchunks[i]; @@ -54,13 +73,19 @@ pub fn draw_per_core_bars( .split(rect); let curr = mm.cpu_per_core[i].clamp(0.0, 100.0); - let older = per_core_hist.deques.get(i) + let older = per_core_hist + .deques + .get(i) .and_then(|d| d.iter().rev().nth(20).copied()) .map(|v| v as f32) .unwrap_or(curr); - let trend = if curr > older + 0.2 { "↑" } - else if curr + 0.2 < older { "↓" } - else { "╌" }; + let trend = if curr > older + 0.2 { + "↑" + } else if curr + 0.2 < older { + "↓" + } else { + "╌" + }; let fg = match curr { x if x < 25.0 => Color::Green, @@ -85,7 +110,10 @@ pub fn draw_per_core_bars( f.render_widget(spark, hchunks[0]); let label = format!("cpu{:<2}{}{:>5.1}%", i, trend, curr); - let line = Line::from(Span::styled(label, Style::default().fg(fg).add_modifier(Modifier::BOLD))); + let line = Line::from(Span::styled( + label, + Style::default().fg(fg).add_modifier(Modifier::BOLD), + )); f.render_widget(Paragraph::new(line).right_aligned(), hchunks[1]); } -} \ No newline at end of file +} diff --git a/socktop/src/ui/disks.rs b/socktop/src/ui/disks.rs index 1da594c..d549b87 100644 --- a/socktop/src/ui/disks.rs +++ b/socktop/src/ui/disks.rs @@ -1,16 +1,18 @@ //! Disk cards with per-device gauge and title line. +use crate::types::Metrics; +use crate::ui::util::{disk_icon, human, truncate_middle}; use ratatui::{ layout::{Constraint, Direction, Layout, Rect}, style::Style, widgets::{Block, Borders, Gauge}, }; -use crate::types::Metrics; -use crate::ui::util::{human, truncate_middle, disk_icon}; pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { f.render_widget(Block::default().borders(Borders::ALL).title("Disks"), area); - let Some(mm) = m else { return; }; + let Some(mm) = m else { + return; + }; let inner = Rect { x: area.x + 1, @@ -18,12 +20,16 @@ pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { width: area.width.saturating_sub(2), height: area.height.saturating_sub(2), }; - if inner.height < 3 { return; } + if inner.height < 3 { + return; + } let per_disk_h = 3u16; let max_cards = (inner.height / per_disk_h).min(mm.disks.len() as u16) as usize; - let constraints: Vec = (0..max_cards).map(|_| Constraint::Length(per_disk_h)).collect(); + let constraints: Vec = (0..max_cards) + .map(|_| Constraint::Length(per_disk_h)) + .collect(); let rows = Layout::default() .direction(Direction::Vertical) .constraints(constraints) @@ -32,10 +38,20 @@ pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { for (i, slot) in rows.iter().enumerate() { let d = &mm.disks[i]; let used = d.total.saturating_sub(d.available); - let ratio = if d.total > 0 { used as f64 / d.total as f64 } else { 0.0 }; + let ratio = if d.total > 0 { + used as f64 / d.total as f64 + } else { + 0.0 + }; let pct = (ratio * 100.0).round() as u16; - let color = if pct < 70 { ratatui::style::Color::Green } else if pct < 90 { ratatui::style::Color::Yellow } else { ratatui::style::Color::Red }; + let color = if pct < 70 { + ratatui::style::Color::Green + } else if pct < 90 { + ratatui::style::Color::Yellow + } else { + ratatui::style::Color::Red + }; let title = format!( "{} {} {} / {} ({}%)", @@ -55,7 +71,9 @@ pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { width: slot.width.saturating_sub(2), height: slot.height.saturating_sub(2), }; - if inner_card.height == 0 { continue; } + if inner_card.height == 0 { + continue; + } let gauge_rect = Rect { x: inner_card.x, @@ -70,4 +88,4 @@ pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { f.render_widget(g, gauge_rect); } -} \ No newline at end of file +} diff --git a/socktop/src/ui/header.rs b/socktop/src/ui/header.rs index bd255ab..b3b7df0 100644 --- a/socktop/src/ui/header.rs +++ b/socktop/src/ui/header.rs @@ -1,20 +1,32 @@ //! Top header with hostname and CPU temperature indicator. +use crate::types::Metrics; use ratatui::{ layout::Rect, widgets::{Block, Borders}, }; -use crate::types::Metrics; pub fn draw_header(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { let title = if let Some(mm) = m { - let temp = mm.cpu_temp_c.map(|t| { - let icon = if t < 50.0 { "😎" } else if t < 85.0 { "⚠️" } else { "🔥" }; - format!("CPU Temp: {:.1}°C {}", t, icon) - }).unwrap_or_else(|| "CPU Temp: N/A".into()); - format!("socktop — host: {} | {} (press 'q' to quit)", mm.hostname, temp) + let temp = mm + .cpu_temp_c + .map(|t| { + let icon = if t < 50.0 { + "😎" + } else if t < 85.0 { + "⚠️" + } else { + "🔥" + }; + format!("CPU Temp: {:.1}°C {}", t, icon) + }) + .unwrap_or_else(|| "CPU Temp: N/A".into()); + format!( + "socktop — host: {} | {} (press 'q' to quit)", + mm.hostname, temp + ) } else { "socktop — connecting... (press 'q' to quit)".into() }; f.render_widget(Block::default().title(title).borders(Borders::BOTTOM), area); -} \ No newline at end of file +} diff --git a/socktop/src/ui/mem.rs b/socktop/src/ui/mem.rs index f873e92..77bd351 100644 --- a/socktop/src/ui/mem.rs +++ b/socktop/src/ui/mem.rs @@ -1,18 +1,24 @@ //! Memory gauge. +use crate::types::Metrics; +use crate::ui::util::human; use ratatui::{ layout::Rect, style::{Color, Style}, widgets::{Block, Borders, Gauge}, }; -use crate::types::Metrics; -use crate::ui::util::human; pub fn draw_mem(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { let (used, total, pct) = if let Some(mm) = m { - let pct = if mm.mem_total > 0 { (mm.mem_used as f64 / mm.mem_total as f64 * 100.0) as u16 } else { 0 }; + let pct = if mm.mem_total > 0 { + (mm.mem_used as f64 / mm.mem_total as f64 * 100.0) as u16 + } else { + 0 + }; (mm.mem_used, mm.mem_total, pct) - } else { (0, 0, 0) }; + } else { + (0, 0, 0) + }; let g = Gauge::default() .block(Block::default().borders(Borders::ALL).title("Memory")) @@ -20,4 +26,4 @@ pub fn draw_mem(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { .percent(pct) .label(format!("{} / {}", human(used), human(total))); f.render_widget(g, area); -} \ No newline at end of file +} diff --git a/socktop/src/ui/mod.rs b/socktop/src/ui/mod.rs index 1ef9fb0..b72a25a 100644 --- a/socktop/src/ui/mod.rs +++ b/socktop/src/ui/mod.rs @@ -1,10 +1,10 @@ //! UI module root: exposes drawing functions for individual panels. -pub mod header; pub mod cpu; -pub mod mem; -pub mod swap; pub mod disks; +pub mod header; +pub mod mem; pub mod net; pub mod processes; -pub mod util; \ No newline at end of file +pub mod swap; +pub mod util; diff --git a/socktop/src/ui/net.rs b/socktop/src/ui/net.rs index adf048c..1e6665a 100644 --- a/socktop/src/ui/net.rs +++ b/socktop/src/ui/net.rs @@ -1,11 +1,11 @@ //! Network sparklines (download/upload). -use std::collections::VecDeque; use ratatui::{ layout::Rect, style::{Color, Style}, widgets::{Block, Borders, Sparkline}, }; +use std::collections::VecDeque; pub fn draw_net_spark( f: &mut ratatui::Frame<'_>, @@ -19,8 +19,12 @@ pub fn draw_net_spark( let data: Vec = hist.iter().skip(start).cloned().collect(); let spark = Sparkline::default() - .block(Block::default().borders(Borders::ALL).title(title.to_string())) + .block( + Block::default() + .borders(Borders::ALL) + .title(title.to_string()), + ) .data(&data) .style(Style::default().fg(color)); f.render_widget(spark, area); -} \ No newline at end of file +} diff --git a/socktop/src/ui/processes.rs b/socktop/src/ui/processes.rs index 5826309..7af347d 100644 --- a/socktop/src/ui/processes.rs +++ b/socktop/src/ui/processes.rs @@ -1,71 +1,94 @@ //! Top processes table with per-cell coloring and zebra striping. +use ratatui::style::Modifier; use ratatui::{ layout::{Constraint, Rect}, style::{Color, Style}, widgets::{Block, Borders, Cell, Row, Table}, }; -use ratatui::style::Modifier; use crate::types::Metrics; use crate::ui::util::human; pub fn draw_top_processes(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { let Some(mm) = m else { - f.render_widget(Block::default().borders(Borders::ALL).title("Top Processes"), area); + f.render_widget( + Block::default() + .borders(Borders::ALL) + .title("Top Processes"), + area, + ); return; }; let total_mem_bytes = mm.mem_total.max(1); let title = format!("Top Processes ({} total)", mm.process_count); - let peak_cpu = mm.top_processes.iter().map(|p| p.cpu_usage).fold(0.0_f32, f32::max); + let peak_cpu = mm + .top_processes + .iter() + .map(|p| p.cpu_usage) + .fold(0.0_f32, f32::max); - let rows: Vec = mm.top_processes.iter().enumerate().map(|(i, p)| { - let mem_pct = (p.mem_bytes as f64 / total_mem_bytes as f64) * 100.0; + let rows: Vec = mm + .top_processes + .iter() + .enumerate() + .map(|(i, p)| { + let mem_pct = (p.mem_bytes as f64 / total_mem_bytes as f64) * 100.0; - let cpu_fg = match p.cpu_usage { - x if x < 25.0 => Color::Green, - x if x < 60.0 => Color::Yellow, - _ => Color::Red, - }; - let mem_fg = match mem_pct { - x if x < 5.0 => Color::Blue, - x if x < 20.0 => Color::Magenta, - _ => Color::Red, - }; + let cpu_fg = match p.cpu_usage { + x if x < 25.0 => Color::Green, + x if x < 60.0 => Color::Yellow, + _ => Color::Red, + }; + let mem_fg = match mem_pct { + x if x < 5.0 => Color::Blue, + x if x < 20.0 => Color::Magenta, + _ => Color::Red, + }; - let zebra = if i % 2 == 0 { Style::default().fg(Color::Gray) } else { Style::default() }; + let zebra = if i % 2 == 0 { + Style::default().fg(Color::Gray) + } else { + Style::default() + }; - let emphasis = if (p.cpu_usage - peak_cpu).abs() < f32::EPSILON { - Style::default().add_modifier(Modifier::BOLD) - } else { Style::default() }; + let emphasis = if (p.cpu_usage - peak_cpu).abs() < f32::EPSILON { + Style::default().add_modifier(Modifier::BOLD) + } else { + Style::default() + }; - Row::new(vec![ - Cell::from(p.pid.to_string()).style(Style::default().fg(Color::DarkGray)), - Cell::from(p.name.clone()), - Cell::from(format!("{:.1}%", p.cpu_usage)).style(Style::default().fg(cpu_fg)), - Cell::from(human(p.mem_bytes)), - Cell::from(format!("{:.2}%", mem_pct)).style(Style::default().fg(mem_fg)), - ]) - .style(zebra.patch(emphasis)) - }).collect(); + Row::new(vec![ + Cell::from(p.pid.to_string()).style(Style::default().fg(Color::DarkGray)), + Cell::from(p.name.clone()), + Cell::from(format!("{:.1}%", p.cpu_usage)).style(Style::default().fg(cpu_fg)), + Cell::from(human(p.mem_bytes)), + Cell::from(format!("{:.2}%", mem_pct)).style(Style::default().fg(mem_fg)), + ]) + .style(zebra.patch(emphasis)) + }) + .collect(); - let header = Row::new(vec!["PID", "Name", "CPU %", "Mem", "Mem %"]) - .style(Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD)); + let header = Row::new(vec!["PID", "Name", "CPU %", "Mem", "Mem %"]).style( + Style::default() + .fg(Color::Cyan) + .add_modifier(Modifier::BOLD), + ); let table = Table::new( - rows, - vec![ - Constraint::Length(8), - Constraint::Percentage(40), - Constraint::Length(8), - Constraint::Length(12), - Constraint::Length(8), - ], - ) - .header(header) - .column_spacing(1) - .block(Block::default().borders(Borders::ALL).title(title)); + rows, + vec![ + Constraint::Length(8), + Constraint::Percentage(40), + Constraint::Length(8), + Constraint::Length(12), + Constraint::Length(8), + ], + ) + .header(header) + .column_spacing(1) + .block(Block::default().borders(Borders::ALL).title(title)); f.render_widget(table, area); -} \ No newline at end of file +} diff --git a/socktop/src/ui/swap.rs b/socktop/src/ui/swap.rs index a077296..fcd2a85 100644 --- a/socktop/src/ui/swap.rs +++ b/socktop/src/ui/swap.rs @@ -1,18 +1,24 @@ //! Swap gauge. +use crate::types::Metrics; +use crate::ui::util::human; use ratatui::{ layout::Rect, style::{Color, Style}, widgets::{Block, Borders, Gauge}, }; -use crate::types::Metrics; -use crate::ui::util::human; pub fn draw_swap(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { let (used, total, pct) = if let Some(mm) = m { - let pct = if mm.swap_total > 0 { (mm.swap_used as f64 / mm.swap_total as f64 * 100.0) as u16 } else { 0 }; + let pct = if mm.swap_total > 0 { + (mm.swap_used as f64 / mm.swap_total as f64 * 100.0) as u16 + } else { + 0 + }; (mm.swap_used, mm.swap_total, pct) - } else { (0, 0, 0) }; + } else { + (0, 0, 0) + }; let g = Gauge::default() .block(Block::default().borders(Borders::ALL).title("Swap")) @@ -20,4 +26,4 @@ pub fn draw_swap(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { .percent(pct) .label(format!("{} / {}", human(used), human(total))); f.render_widget(g, area); -} \ No newline at end of file +} diff --git a/socktop/src/ui/util.rs b/socktop/src/ui/util.rs index c78afde..a0437cb 100644 --- a/socktop/src/ui/util.rs +++ b/socktop/src/ui/util.rs @@ -3,31 +3,49 @@ pub fn human(b: u64) -> String { const K: f64 = 1024.0; let b = b as f64; - if b < K { return format!("{b:.0}B"); } + if b < K { + return format!("{b:.0}B"); + } let kb = b / K; - if kb < K { return format!("{kb:.1}KB"); } + if kb < K { + return format!("{kb:.1}KB"); + } let mb = kb / K; - if mb < K { return format!("{mb:.1}MB"); } + if mb < K { + return format!("{mb:.1}MB"); + } let gb = mb / K; - if gb < K { return format!("{gb:.1}GB"); } + if gb < K { + return format!("{gb:.1}GB"); + } let tb = gb / K; format!("{tb:.2}TB") } pub fn truncate_middle(s: &str, max: usize) -> String { - if s.len() <= max { return s.to_string(); } - if max <= 3 { return "...".into(); } + if s.len() <= max { + return s.to_string(); + } + if max <= 3 { + return "...".into(); + } let keep = max - 3; let left = keep / 2; let right = keep - left; - format!("{}...{}", &s[..left], &s[s.len()-right..]) + format!("{}...{}", &s[..left], &s[s.len() - right..]) } pub fn disk_icon(name: &str) -> &'static str { let n = name.to_ascii_lowercase(); - if n.contains(':') { "🗄️" } - else if n.contains("nvme") { "⚡" } - else if n.starts_with("sd") { "💽" } - else if n.contains("overlay") { "📦" } - else { "🖴" } -} \ No newline at end of file + if n.contains(':') { + "🗄️" + } else if n.contains("nvme") { + "⚡" + } else if n.starts_with("sd") { + "💽" + } else if n.contains("overlay") { + "📦" + } else { + "🖴" + } +} diff --git a/socktop/src/ws.rs b/socktop/src/ws.rs index d032f2d..c9bfb34 100644 --- a/socktop/src/ws.rs +++ b/socktop/src/ws.rs @@ -25,4 +25,4 @@ pub async fn request_metrics(ws: &mut WsStream) -> Option { } // Re-export SinkExt/StreamExt for call sites -use futures_util::{SinkExt, StreamExt}; \ No newline at end of file +use futures_util::{SinkExt, StreamExt}; diff --git a/socktop_agent/src/main.rs b/socktop_agent/src/main.rs index 14a940d..efef2ca 100644 --- a/socktop_agent/src/main.rs +++ b/socktop_agent/src/main.rs @@ -4,25 +4,26 @@ mod metrics; mod sampler; mod state; -mod ws; mod types; +mod ws; use axum::{routing::get, Router}; -use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration, sync::atomic::AtomicUsize}; -use sysinfo::{ - Components, CpuRefreshKind, Disks, MemoryRefreshKind, Networks, ProcessRefreshKind, RefreshKind, - System, +use std::{ + collections::HashMap, net::SocketAddr, sync::atomic::AtomicUsize, sync::Arc, time::Duration, }; -use tokio::sync::{Mutex, RwLock, Notify}; +use sysinfo::{ + Components, CpuRefreshKind, Disks, MemoryRefreshKind, Networks, ProcessRefreshKind, + RefreshKind, System, +}; +use tokio::sync::{Mutex, Notify, RwLock}; use tracing_subscriber::EnvFilter; -use state::{AppState, SharedTotals}; use sampler::spawn_sampler; +use state::{AppState, SharedTotals}; use ws::ws_handler; #[tokio::main] async fn main() { - // Init logging; configure with RUST_LOG (e.g., RUST_LOG=info). tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env()) @@ -60,7 +61,9 @@ async fn main() { // new: adaptive sampling controls client_count: Arc::new(AtomicUsize::new(0)), wake_sampler: Arc::new(Notify::new()), - auth_token: std::env::var("SOCKTOP_TOKEN").ok().filter(|s| !s.is_empty()), + auth_token: std::env::var("SOCKTOP_TOKEN") + .ok() + .filter(|s| !s.is_empty()), }; // Start background sampler (adjust cadence as needed) @@ -68,7 +71,9 @@ async fn main() { // Web app let port = resolve_port(); - let app = Router::new().route("/ws", get(ws_handler)).with_state(state); + let app = Router::new() + .route("/ws", get(ws_handler)) + .with_state(state); let addr = SocketAddr::from(([0, 0, 0, 0], port)); @@ -82,7 +87,6 @@ async fn main() { let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); - } // Resolve the listening port from CLI args/env with a 3000 default. @@ -97,7 +101,10 @@ fn resolve_port() -> u16 { return p; } } - eprintln!("Warning: invalid SOCKTOP_PORT='{}'; using default {}", s, DEFAULT); + eprintln!( + "Warning: invalid SOCKTOP_PORT='{}'; using default {}", + s, DEFAULT + ); } let mut args = std::env::args().skip(1); @@ -133,4 +140,3 @@ fn resolve_port() -> u16 { DEFAULT } - diff --git a/socktop_agent/src/metrics.rs b/socktop_agent/src/metrics.rs index 751889f..e55f25c 100644 --- a/socktop_agent/src/metrics.rs +++ b/socktop_agent/src/metrics.rs @@ -121,8 +121,11 @@ pub fn best_cpu_temp(components: &Components) -> Option { .iter() .filter(|c| { let label = c.label().to_lowercase(); - label.contains("cpu") || label.contains("package") || label.contains("tctl") || label.contains("tdie") + label.contains("cpu") + || label.contains("package") + || label.contains("tctl") + || label.contains("tdie") }) .filter_map(|c| c.temperature()) .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)) -} \ No newline at end of file +} diff --git a/socktop_agent/src/sampler.rs b/socktop_agent/src/sampler.rs index 3ce3843..0cc69be 100644 --- a/socktop_agent/src/sampler.rs +++ b/socktop_agent/src/sampler.rs @@ -5,13 +5,16 @@ use crate::metrics::collect_metrics; use crate::state::AppState; //use serde_json::to_string; use tokio::task::JoinHandle; -use tokio::time::{Duration, interval, MissedTickBehavior}; +use tokio::time::{interval, Duration, MissedTickBehavior}; pub fn spawn_sampler(state: AppState, period: Duration) -> JoinHandle<()> { tokio::spawn(async move { let idle_period = Duration::from_secs(10); loop { - let active = state.client_count.load(std::sync::atomic::Ordering::Relaxed) > 0; + let active = state + .client_count + .load(std::sync::atomic::Ordering::Relaxed) + > 0; let mut ticker = interval(if active { period } else { idle_period }); ticker.set_missed_tick_behavior(MissedTickBehavior::Skip); ticker.tick().await; @@ -33,4 +36,4 @@ pub fn spawn_sampler(state: AppState, period: Duration) -> JoinHandle<()> { } } }) -} \ No newline at end of file +} diff --git a/socktop_agent/src/state.rs b/socktop_agent/src/state.rs index eb4000d..8832dac 100644 --- a/socktop_agent/src/state.rs +++ b/socktop_agent/src/state.rs @@ -1,9 +1,9 @@ //! Shared agent state: sysinfo handles and hot JSON cache. -use std::{collections::HashMap, sync::Arc}; use std::sync::atomic::AtomicUsize; +use std::{collections::HashMap, sync::Arc}; use sysinfo::{Components, Disks, Networks, System}; -use tokio::sync::{Mutex, RwLock, Notify}; +use tokio::sync::{Mutex, Notify, RwLock}; pub type SharedSystem = Arc>; pub type SharedNetworks = Arc>; @@ -27,4 +27,4 @@ pub struct AppState { pub client_count: Arc, pub wake_sampler: Arc, pub auth_token: Option, -} \ No newline at end of file +} diff --git a/socktop_agent/src/types.rs b/socktop_agent/src/types.rs index b5fc602..5b0410c 100644 --- a/socktop_agent/src/types.rs +++ b/socktop_agent/src/types.rs @@ -40,4 +40,4 @@ pub struct Metrics { pub disks: Vec, pub networks: Vec, pub top_processes: Vec, -} \ No newline at end of file +} diff --git a/socktop_agent/src/ws.rs b/socktop_agent/src/ws.rs index ecbf7eb..bbba649 100644 --- a/socktop_agent/src/ws.rs +++ b/socktop_agent/src/ws.rs @@ -63,4 +63,4 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) { _ => {} } } -} \ No newline at end of file +}