diff options
author | Aram Drevekenin <aram@poor.dev> | 2019-11-05 20:33:12 +0100 |
---|---|---|
committer | Aram Drevekenin <aram@poor.dev> | 2019-11-05 20:33:12 +0100 |
commit | 53d165b2a033615e2cce7ab5cc42ff2bf85e50da (patch) | |
tree | 1506e6e227d2d2fe622a73539480ec38bfb61c2d | |
parent | db0f4d109403da54574a6469fe676f167c97e2c6 (diff) |
feat(raw): machine friendly output
85 files changed, 5638 insertions, 1490 deletions
@@ -1217,6 +1217,7 @@ name = "what" version = "0.1.0" dependencies = [ "cargo-insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "dns-lookup 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1225,6 +1226,7 @@ dependencies = [ "pnet 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "pnet_base 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", "procfs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -22,9 +22,11 @@ structopt = "0.3" dns-lookup = "1.0.1" signal-hook = "0.1.10" failure = "0.1.6" +chrono = "0.4" [dev-dependencies] insta = "0.11.0" cargo-insta = "0.11.0" packet-builder = "0.3.0" pnet_base = "0.22.0" +regex = "1" diff --git a/src/display/components/table.rs b/src/display/components/table.rs index 6f22ea5..f59536e 100644 --- a/src/display/components/table.rs +++ b/src/display/components/table.rs @@ -7,7 +7,7 @@ use ::tui::terminal::Frame; use ::tui::widgets::{Block, Borders, Row, Widget}; use crate::display::{Bandwidth, DisplayBandwidth, UIState}; -use crate::network::Connection; +use crate::network::{display_connection_string, display_ip_or_host}; use ::std::net::Ipv4Addr; use std::iter::FromIterator; @@ -28,13 +28,6 @@ fn display_upload_and_download(bandwidth: &impl Bandwidth) -> String { ) } -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 sort_by_bandwidth<'a, T>( list: &'a mut Vec<(T, &impl Bandwidth)>, ) -> &'a Vec<(T, &'a impl Bandwidth)> { @@ -54,19 +47,6 @@ fn sort_by_bandwidth<'a, T>( list } -fn display_connection_string( - connection: &Connection, - ip_to_host: &HashMap<Ipv4Addr, String>, -) -> String { - format!( - ":{} => {}:{} ({})", - connection.local_port, - display_ip_or_host(connection.remote_socket.ip, ip_to_host), - connection.remote_socket.port, - connection.protocol, - ) -} - pub struct Table<'a> { title: &'a str, column_names: &'a [&'a str], @@ -119,29 +99,29 @@ impl<'a> Table<'a> { rows: processes_rows, } } - pub fn create_remote_ips_table( + pub fn create_remote_addresses_table( state: &UIState, ip_to_host: &HashMap<Ipv4Addr, String>, ) -> Self { - let mut remote_ips_list = Vec::from_iter(&state.remote_ips); - sort_by_bandwidth(&mut remote_ips_list); - let remote_ips_rows = remote_ips_list + let mut remote_addresses_list = Vec::from_iter(&state.remote_addresses); + sort_by_bandwidth(&mut remote_addresses_list); + let remote_addresses_rows = remote_addresses_list .iter() - .map(|(remote_ip, data_for_remote_ip)| { - let remote_ip = display_ip_or_host(**remote_ip, &ip_to_host); + .map(|(remote_address, data_for_remote_address)| { + let remote_address = display_ip_or_host(**remote_address, &ip_to_host); vec![ - remote_ip, - data_for_remote_ip.connection_count.to_string(), - display_upload_and_download(*data_for_remote_ip), + remote_address, + data_for_remote_address.connection_count.to_string(), + display_upload_and_download(*data_for_remote_address), ] }) .collect(); - let remote_ips_title = "Utilization by remote ip"; - let remote_ips_column_names = &["Remote Address", "Connection Count", "Rate Up/Down"]; + let remote_addresses_title = "Utilization by remote address"; + let remote_addresses_column_names = &["Remote Address", "Connection Count", "Rate Up/Down"]; Table { - title: remote_ips_title, - column_names: remote_ips_column_names, - rows: remote_ips_rows, + title: remote_addresses_title, + column_names: remote_addresses_column_names, + rows: remote_addresses_rows, } } pub fn render(&self, frame: &mut Frame<impl Backend>, rect: Rect) { diff --git a/src/display/mod.rs b/src/display/mod.rs index 8d24159..396b5d9 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -1,7 +1,9 @@ mod components; mod ui; mod ui_state; +mod raw_terminal_backend; pub use components::*; pub use ui::*; pub use ui_state::*; +pub use raw_terminal_backend::*; diff --git a/src/display/raw_terminal_backend.rs b/src/display/raw_terminal_backend.rs new file mode 100644 index 0000000..3ae299a --- /dev/null +++ b/src/display/raw_terminal_backend.rs @@ -0,0 +1,52 @@ +// this is a bit of a hack: +// the TUI backend used by this app changes stdout to raw byte mode. +// this is not desired when we do not use it (in our --raw mode), +// since it makes writing to stdout overly complex +// +// so what we do here is provide a fake backend (RawTerminalBackend) +// that implements the Backend TUI trait, but does nothing +// this way, we don't need to create the TermionBackend +// and thus skew our stdout when we don't need it +use ::std::io; +use ::tui::backend::Backend; +use ::tui::buffer::Cell; +use ::tui::layout::Rect; + +pub struct RawTerminalBackend {} + +impl Backend for RawTerminalBackend { + fn clear(&mut self) -> io::Result<()> { + Ok(()) + } + + fn hide_cursor(&mut self) -> io::Result<()> { + Ok(()) + } + + fn show_cursor(&mut self) -> io::Result<()> { + Ok(()) + } + + fn get_cursor(&mut self) -> io::Result<(u16, u16)> { + Ok((0, 0)) + } + + fn set_cursor(&mut self, _x: u16, _y: u16) -> io::Result<()> { + Ok(()) + } + + fn draw<'a, I>(&mut self, _content: I) -> io::Result<()> + where + I: Iterator<Item = (u16, u16, &'a Cell)>, + { + Ok(()) + } + + fn size(&self) -> io::Result<Rect> { + Ok(Rect::new(0, 0, 0, 0)) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} diff --git a/src/display/ui.rs b/src/display/ui.rs index feacc5e..e23843e 100644 --- a/src/display/ui.rs +++ b/src/display/ui.rs @@ -5,10 +5,12 @@ use ::tui::Terminal; use crate::display::components::{Layout, Table, TotalBandwidth}; use crate::display::UIState; -use crate::network::{Connection, Utilization}; +use crate::network::{Connection, Utilization, display_connection_string, display_ip_or_host}; use ::std::net::Ipv4Addr; +use chrono::prelude::*; + pub struct Ui<B> where B: Backend, @@ -26,10 +28,52 @@ where let mut terminal = Terminal::new(terminal_backend).unwrap(); terminal.clear().unwrap(); terminal.hide_cursor().unwrap(); - Ui { - terminal, - state: Default::default(), - ip_to_host: Default::default(), + Ui { + terminal: terminal, + state: Default::default(), + ip_to_host: Default::default(), + } + } + pub fn output_text(&mut self, write_to_stdout: &mut Box<dyn FnMut(String) + Send>) { + let state = &self.state; + let ip_to_host = &self.ip_to_host; + let local_time: DateTime<Local> = Local::now(); + let timestamp = local_time.timestamp(); + for (process, process_network_data) in &state.processes { + write_to_stdout( + format!( + "process: <{}> \"{}\" up/down Bps: {}/{} connections: {}", + timestamp, + process, + process_network_data.total_bytes_uploaded, + process_network_data.total_bytes_downloaded, + process_network_data.connection_count + ) + ); + } + for (connection, connection_network_data) in &state.connections { + write_to_stdout( + format!( + "connection: <{}> {} up/down Bps: {}/{} process: \"{}\"", + timestamp, + display_connection_string(connection, ip_to_host), + connection_network_data.total_bytes_uploaded, + connection_network_data.total_bytes_downloaded, + connection_network_data.process_name + ) + ); + } + for (remote_address, remote_address_network_data) in &state.remote_addresses { + write_to_stdout( + format!( + "remote_address: <{}> {} up/down Bps: {}/{} connections: {}", + timestamp, + display_ip_or_host(*remote_address, ip_to_host), + remote_address_network_data.total_bytes_uploaded, + remote_address_network_data.total_bytes_downloaded, + remote_address_network_data.connection_count + ) + ); } } pub fn draw(&mut self) { @@ -40,11 +84,11 @@ where let |