Add a table helper type to make it easier to display data. Migrate the flows view to the new system.

This commit is contained in:
Herbert Wolverson 2024-03-21 13:46:05 -05:00
parent 205066b54d
commit 2cc5973ce7
3 changed files with 91 additions and 46 deletions

View File

@ -1,4 +1,5 @@
mod stats_ringbuffer;
mod table_helper;
mod cpu;
pub use cpu::cpu_display;
mod network_sparkline;

View File

@ -0,0 +1,67 @@
use ratatui::{style::{Color, Style}, text::Text, widgets::{Block, Borders, Cell, Row, Table}};
/// A helper for building Ratatui tables
pub struct TableHelper<const N_COLS: usize> {
headers: [String; N_COLS],
rows: Vec<[String; N_COLS]>,
}
impl <const N: usize> TableHelper<N> {
pub fn new<S: ToString>(raw_headers: [S; N]) -> Self {
const ARRAY_REPEAT_VALUE: String = String::new();
let mut headers = [ARRAY_REPEAT_VALUE; N];
for i in 0..N {
headers[i] = raw_headers[i].to_string();
}
let headers = headers.try_into().unwrap();
Self {
headers,
rows: Vec::new(),
}
}
pub fn add_row(&mut self, row: [String; N]) {
self.rows.push(row);
}
pub fn to_table(&self) -> Table {
let header_cells: Vec<_> = self.headers.
iter()
.map(|h| Cell::from(Text::from(h.clone())))
.collect();
let rows: Vec<_> = self.rows
.iter()
.map(|row| {
let cells = row.iter()
.map(|cell| Cell::from(Text::from(cell.clone())))
.collect::<Vec<Cell>>();
Row::new(cells)
})
.collect();
let mut widths = [0u16; N];
for (i, heading) in self.headers.iter().enumerate() {
widths[i] = (heading.len() + 2) as u16;
}
for row in self.rows.iter() {
for (j, cell) in row.iter().enumerate() {
if cell.len() + 2 > widths[j] as usize {
widths[j] = (cell.len() + 2) as u16;
}
}
}
Table::new(rows, widths)
.header(Row::new(header_cells).style(Style::default().fg(Color::White).bg(Color::Blue)))
}
pub fn to_block(&self) -> Table {
let block = Block::default()
//.title("Top Downloaders")
.borders(Borders::NONE)
.style(Style::default().fg(Color::Green));
self.to_table().block(block)
}
}

View File

@ -1,7 +1,7 @@
use super::TopWidget;
use super::{table_helper::TableHelper, TopWidget};
use lqos_bus::{BusResponse, FlowbeeSummaryData};
use lqos_utils::packet_scale::scale_bits;
use ratatui::{prelude::*, widgets::*};
use ratatui::prelude::*;
pub struct TopFlows {
bus_link: tokio::sync::mpsc::Sender<crate::bus::BusMessage>,
@ -37,52 +37,29 @@ impl TopWidget for TopFlows {
}
fn render_to_frame(&mut self, frame: &mut Frame) {
let block = Block::default()
//.title("Top Downloaders")
.borders(Borders::NONE)
.style(Style::default().fg(Color::Green));
let mut rows = Vec::new();
let mut t = TableHelper::new([
"Src IP",
"Dst IP",
"Type",
"Upload",
"Download",
"Retransmits",
"RTT (ms)",
"ASN",
]);
for flow in self.flows.iter() {
rows.push(
Row::new(vec![
Cell::from(Text::from(flow.local_ip.to_string())),
Cell::from(Text::from(flow.remote_ip.to_string())),
Cell::from(Text::from(flow.analysis.to_string())),
Cell::from(Text::from(scale_bits(flow.bytes_sent[0]))),
Cell::from(Text::from(scale_bits(flow.bytes_sent[1]))),
Cell::from(Text::from(format!(
"{}/{}",
flow.tcp_retransmits[0], flow.tcp_retransmits[1]
))),
Cell::from(Text::from(format!(
"{:.1}/{:.1}",
flow.rtt_nanos[0] as f64 / 1000000.,
flow.tcp_retransmits[1] as f64 / 1000000.
))),
Cell::from(Text::from(flow.remote_asn_name.to_string())),
])
.style(style::Style::default().fg(Color::White)),
);
t.add_row([
flow.local_ip.to_string(),
flow.remote_ip.to_string(),
flow.analysis.to_string(),
scale_bits(flow.bytes_sent[0]),
scale_bits(flow.bytes_sent[1]),
format!("{}/{}", flow.tcp_retransmits[0], flow.tcp_retransmits[1]),
format!("{:.1}/{:.1}", flow.rtt_nanos[0] as f64 / 1000000., flow.tcp_retransmits[1] as f64 / 1000000.),
flow.remote_asn_name.to_string(),
]);
}
let header = Row::new(vec![
Cell::from(Text::from("Src IP")),
Cell::from(Text::from("Dst IP")),
Cell::from(Text::from("Type")),
Cell::from(Text::from("Upload")),
Cell::from(Text::from("Download")),
Cell::from(Text::from("Retransmits")),
Cell::from(Text::from("RTT (ms)")),
Cell::from(Text::from("ASN")),
])
.style(style::Style::default().fg(Color::Yellow).bg(Color::Blue));
let table = Table::new(rows, [15, 15, 20, 14, 14, 10, 15, 20])
.block(block)
.header(header);
let table = t.to_block();
frame.render_widget(table, self.size);
}
}