summaryrefslogtreecommitdiffstats
path: root/src/display/ui.rs
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2019-10-13 19:01:23 +0200
committerAram Drevekenin <aram@poor.dev>2019-10-13 19:01:23 +0200
commitf23d5b9bb709024dff4634220a2271a23ea38970 (patch)
tree7349d60533ea15f3f97a44a69d829053894fcfc7 /src/display/ui.rs
parent3e1b6d18bcc0a678c1da1be4a8bf53c19fbb98bd (diff)
feat(ui): components, new details and responsive layout
Diffstat (limited to 'src/display/ui.rs')
-rw-r--r--src/display/ui.rs169
1 files changed, 14 insertions, 155 deletions
diff --git a/src/display/ui.rs b/src/display/ui.rs
index a3f9b58..e603601 100644
--- a/src/display/ui.rs
+++ b/src/display/ui.rs
@@ -1,159 +1,14 @@
use ::std::collections::HashMap;
-use ::std::fmt;
+
use ::tui::backend::Backend;
-use ::tui::layout::{Constraint, Direction, Layout, Rect};
-use ::tui::style::{Color, Style};
-use ::tui::terminal::Frame;
-use ::tui::widgets::{Block, Borders, Row, Table, Widget};
use ::tui::Terminal;
-use crate::display::{Bandwidth, UIState};
+use crate::display::UIState;
use crate::network::{Connection, Utilization};
+use crate::display::components::{Table, Layout, TotalBandwidth};
use ::std::net::Ipv4Addr;
-struct DisplayBandwidth(f64);
-
-impl fmt::Display for DisplayBandwidth {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- if self.0 > 999_999_999.0 {
- write!(f, "{:.2}GBps", self.0 / 1_000_000_000.0)
- } else if self.0 > 999_999.0 {
- write!(f, "{:.2}MBps", self.0 / 1_000_000.0)
- } else if self.0 > 999.0 {
- write!(f, "{:.2}KBps", self.0 / 1000.0)
- } else {
- write!(f, "{}Bps", self.0)
- }
- }
-}
-
-fn display_ip_or_host(ip: Ipv4Addr, ip_to_host: &HashMap<Ipv4Addr, String>) -> String {
- match ip_to_host.get(&ip) {
- Some(host) => host.clone(),
- None => ip.to_string(),
- }
-}
-
-fn create_table<'a>(
- title: &'a str,
- column_names: &'a [&'a str],
- rows: impl Iterator<Item = Vec<String>> + 'a,
- widths: &'a [u16],
-) -> impl Widget + 'a {
- let table_rows =
- rows.map(|row| Row::StyledData(row.into_iter(), Style::default().fg(Color::White)));
- Table::new(column_names.iter(), table_rows)
- .block(Block::default().title(title).borders(Borders::ALL))
- .header_style(Style::default().fg(Color::Yellow))
- .widths(widths)
- .style(Style::default().fg(Color::White))
- .column_spacing(1)
-}
-
-fn format_row_data(
- first_cell: String,
- second_cell: String,
- bandwidth: &impl Bandwidth,
-) -> Vec<String> {
- vec![
- first_cell,
- second_cell,
- format!(
- "{}/{}",
- DisplayBandwidth(bandwidth.get_total_bytes_uploaded() as f64),
- DisplayBandwidth(bandwidth.get_total_bytes_downloaded() as f64)
- ),
- ]
-}
-
-fn split(direction: Direction, rect: Rect) -> Vec<Rect> {
- Layout::default()
- .direction(direction)
- .margin(0)
- .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
- .split(rect)
-}
-
-fn render_process_table(state: &UIState, frame: &mut Frame<impl Backend>, rect: Rect) {
- let rows = state
- .processes
- .iter()
- .map(|(process_name, data_for_process)| {
- format_row_data(
- process_name.to_string(),
- data_for_process.connection_count.to_string(),
- data_for_process,
- )
- });
- let mut table = create_table(
- "Utilization by process name",
- &["Process", "Connection Count", "Total Bytes"],
- rows,
- &[30, 30, 30],
- );
- table.render(frame, rect);
-}
-
-fn render_connections_table(
- state: &UIState,
- frame: &mut Frame<impl Backend>,
- rect: Rect,
- ip_to_host: &HashMap<Ipv4Addr, String>,
-) {
- let rows = state
- .connections
- .iter()
- .map(|(connection, connection_data)| {
- let connection_string = format!(
- "{}:{} => {}:{} ({})",
- display_ip_or_host(connection.local_socket.ip, ip_to_host),
- connection.local_socket.port,
- display_ip_or_host(connection.remote_socket.ip, ip_to_host),
- connection.remote_socket.port,
- connection.protocol,
- );
- format_row_data(
- connection_string,
- connection_data.process_name.to_string(),
- connection_data,
- )
- });
- let mut table = create_table(
- "Utilization by connection",
- &["Connection", "Processes", "Total Bytes Up/Down"],
- rows,
- &[50, 20, 20],
- );
- table.render(frame, rect);
-}
-
-fn render_remote_ip_table(
- state: &UIState,
- frame: &mut Frame<impl Backend>,
- rect: Rect,
- ip_to_host: &HashMap<Ipv4Addr, String>,
-) {
- let rows = state
- .remote_ips
- .iter()
- .map(|(remote_ip, data_for_remote_ip)| {
- let remote_ip = display_ip_or_host(*remote_ip, &ip_to_host);
- format_row_data(
- remote_ip,
- data_for_remote_ip.connection_count.to_string(),
- data_for_remote_ip,
- )
- });
- let mut table = create_table(
- "Utilization by remote ip",
- &["Remote Address", "Connection Count", "Total Bytes"],
- rows,
- &[50, 20, 20],
- );
- table.render(frame, rect);
-}
-
pub struct Ui<B>
where
B: Backend,
@@ -181,13 +36,17 @@ where
let state = &self.state;
let ip_to_host = &self.ip_to_host;
self.terminal
- .draw(|mut f| {
- let screen_horizontal_halves = split(Direction::Horizontal, f.size());
- let right_side_vertical_halves =
- split(Direction::Vertical, screen_horizontal_halves[1]);
- render_connections_table(state, &mut f, screen_horizontal_halves[0], ip_to_host);
- render_process_table(state, &mut f, right_side_vertical_halves[0]);
- render_remote_ip_table(state, &mut f, right_side_vertical_halves[1], ip_to_host);
+ .draw(|mut frame| {
+ let size = frame.size();
+ let connections = Table::create_connections_table(&state, &ip_to_host);
+ let processes = Table::create_processes_table(&state);
+ let remote_ips = Table::create_remote_ips_table(&state, &ip_to_host);
+ let total_bandwidth = TotalBandwidth { state: &state };
+ let layout = Layout {
+ header: total_bandwidth,
+ children: vec![connections, processes, remote_ips],
+ };
+ layout.render(&mut frame, size);
})
.unwrap();
}