summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrooks Rady <b.j.rady@gmail.com>2020-05-23 12:16:55 +0100
committerGitHub <noreply@github.com>2020-05-23 12:16:55 +0100
commite9b8a189b2323c337e11da317646cc601f963cf8 (patch)
tree4a43685c5de76dd679aef447e84ef62bcddf9369
parent55e8885302172ccf0a79bc9829d339acfdc3564d (diff)
parentb6f7f4295770e88a0967fcf55ddefbe10a57001d (diff)
Merge pull request #167 from Eosis/issue-163-elapsed-time
feat(interface): Added elapsed time (#167)
-rw-r--r--CHANGELOG.md1
-rw-r--r--src/display/components/header_details.rs117
-rw-r--r--src/display/components/layout.rs5
-rw-r--r--src/display/components/mod.rs4
-rw-r--r--src/display/components/total_bandwidth.rs45
-rw-r--r--src/display/ui.rs9
-rw-r--r--src/main.rs52
-rw-r--r--src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total-2.snap4
-rw-r--r--src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total.snap2
-rw-r--r--src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total-2.snap4
-rw-r--r--src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total.snap2
-rw-r--r--src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total-2.snap4
-rw-r--r--src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total.snap2
-rw-r--r--src/tests/cases/ui.rs6
14 files changed, 185 insertions, 72 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe0469a..b3a9513 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Added
* Ability to change the window layout with <TAB> (https://github.com/imsnif/bandwhich/pull/118) - [@Louis-Lesage](https://github.com/Louis-Lesage)
+* Show duration of current capture when running in "total utilization" mode. - [@Eosis](https://github.com/Eosis)
### Fixed
* Add terabytes as a display unit (for cumulative mode) (https://github.com/imsnif/bandwhich/pull/168) - [@TheLostLambda](https://github.com/TheLostLambda)
diff --git a/src/display/components/header_details.rs b/src/display/components/header_details.rs
new file mode 100644
index 0000000..042d667
--- /dev/null
+++ b/src/display/components/header_details.rs
@@ -0,0 +1,117 @@
+use crate::display::{DisplayBandwidth, UIState};
+use ::std::time::{Duration, Instant};
+use ::tui::backend::Backend;
+use ::tui::layout::{Alignment, Rect};
+use ::tui::style::{Color, Modifier, Style};
+use ::tui::terminal::Frame;
+use ::tui::widgets::{Paragraph, Text, Widget};
+
+const SECONDS_IN_DAY: u64 = 86400;
+
+pub struct HeaderDetails<'a> {
+ pub state: &'a UIState,
+ pub elapsed_time: std::time::Duration,
+ pub paused: bool,
+}
+
+pub fn elapsed_time(last_start_time: Instant, cumulative_time: Duration, paused: bool) -> Duration {
+ if paused {
+ cumulative_time
+ } else {
+ cumulative_time + last_start_time.elapsed()
+ }
+}
+
+impl<'a> HeaderDetails<'a> {
+ #[allow(clippy::int_plus_one)]
+ pub fn render(&self, frame: &mut Frame<impl Backend>, rect: Rect) {
+ let bandwidth = self.bandwidth_string();
+ let mut elapsed_time = None;
+ let print_elapsed_time = if self.state.cumulative_mode {
+ elapsed_time = Some(self.elapsed_time_string());
+ bandwidth.len() + elapsed_time.as_ref().unwrap().len() + 1 <= rect.width as usize
+ } else {
+ false
+ };
+
+ let color = if self.paused {
+ Color::Yellow
+ } else {
+ Color::Green
+ };
+
+ if print_elapsed_time {
+ self.render_elapsed_time(frame, rect, elapsed_time.as_ref().unwrap(), color);
+ }
+ self.render_bandwidth(frame, rect, &bandwidth, color);
+ }
+
+ fn render_bandwidth(
+ &self,
+ frame: &mut Frame<impl Backend>,
+ rect: Rect,
+ bandwidth: &str,
+ color: Color,
+ ) {
+ let bandwidth_text = {
+ [Text::styled(
+ bandwidth,
+ Style::default().fg(color).modifier(Modifier::BOLD),
+ )]
+ };
+
+ Paragraph::new(bandwidth_text.iter())
+ .alignment(Alignment::Left)
+ .render(frame, rect);
+ }
+
+ fn bandwidth_string(&self) -> String {
+ let c_mode = self.state.cumulative_mode;
+ format!(
+ " Total Up / Down: {} / {}{}",
+ DisplayBandwidth {
+ bandwidth: self.state.total_bytes_uploaded as f64,
+ as_rate: !c_mode,
+ },
+ DisplayBandwidth {
+ bandwidth: self.state.total_bytes_downloaded as f64,
+ as_rate: !c_mode,
+ },
+ if self.paused { " [PAUSED]" } else { "" }
+ )
+ }
+
+ fn render_elapsed_time(
+ &self,
+ frame: &mut Frame<impl Backend>,
+ rect: Rect,
+ elapsed_time: &str,
+ color: Color,
+ ) {
+ let elapsed_time_text = [Text::styled(
+ elapsed_time,
+ Style::default().fg(color).modifier(Modifier::BOLD),
+ )];
+ Paragraph::new(elapsed_time_text.iter())
+ .alignment(Alignment::Right)
+ .render(frame, rect);
+ }
+
+ fn days_string(&self) -> String {
+ match self.elapsed_time.as_secs() / SECONDS_IN_DAY {
+ 0 => "".to_string(),
+ 1 => "1 day, ".to_string(),
+ n => format!("{} days, ", n),
+ }
+ }
+
+ fn elapsed_time_string(&self) -> String {
+ format!(
+ "{}{:02}:{:02}:{:02} ",
+ self.days_string(),
+ (self.elapsed_time.as_secs() % SECONDS_IN_DAY) / 3600,
+ (self.elapsed_time.as_secs() % 3600) / 60,
+ self.elapsed_time.as_secs() % 60
+ )
+ }
+}
diff --git a/src/display/components/layout.rs b/src/display/components/layout.rs
index 79186cd..51c0175 100644
--- a/src/display/components/layout.rs
+++ b/src/display/components/layout.rs
@@ -2,9 +2,9 @@ use ::tui::backend::Backend;
use ::tui::layout::{Constraint, Direction, Rect};
use ::tui::terminal::Frame;
+use super::HeaderDetails;
use super::HelpText;
use super::Table;
-use super::TotalBandwidth;
const FIRST_HEIGHT_BREAKPOINT: u16 = 30;
const FIRST_WIDTH_BREAKPOINT: u16 = 120;
@@ -26,7 +26,7 @@ fn top_app_and_bottom_split(rect: Rect) -> (Rect, Rect, Rect) {
}
pub struct Layout<'a> {
- pub header: TotalBandwidth<'a>,
+ pub header: HeaderDetails<'a>,
pub children: Vec<Table<'a>>,
pub footer: HelpText,
}
@@ -99,6 +99,7 @@ impl<'a> Layout<'a> {
self.build_three_children_layout(rect)
}
}
+
pub fn render(&self, frame: &mut Frame<impl Backend>, rect: Rect, ui_offset: usize) {
let (top, app, bottom) = top_app_and_bottom_split(rect);
let layout_slots = self.build_layout(app);
diff --git a/src/display/components/mod.rs b/src/display/components/mod.rs
index c99596c..b5457f7 100644
--- a/src/display/components/mod.rs
+++ b/src/display/components/mod.rs
@@ -1,11 +1,11 @@
mod display_bandwidth;
+mod header_details;
mod help_text;
mod layout;
mod table;
-mod total_bandwidth;
pub use display_bandwidth::*;
+pub use header_details::*;
pub use help_text::*;
pub use layout::*;
pub use table::*;
-pub use total_bandwidth::*;
diff --git a/src/display/components/total_bandwidth.rs b/src/display/components/total_bandwidth.rs
deleted file mode 100644
index 80d892f..0000000
--- a/src/display/components/total_bandwidth.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use ::tui::backend::Backend;
-use ::tui::layout::{Alignment, Rect};
-use ::tui::style::{Color, Modifier, Style};
-use ::tui::terminal::Frame;
-use ::tui::widgets::{Paragraph, Text, Widget};
-
-use crate::display::{DisplayBandwidth, UIState};
-
-pub struct TotalBandwidth<'a> {
- pub state: &'a UIState,
- pub paused: bool,
-}
-
-impl<'a> TotalBandwidth<'a> {
- pub fn render(&self, frame: &mut Frame<impl Backend>, rect: Rect) {
- let c_mode = self.state.cumulative_mode;
- let title_text = {
- let paused_str = if self.paused { "[PAUSED]" } else { "" };
- let color = if self.paused {
- Color::Yellow
- } else {
- Color::Green
- };
-
- [Text::styled(
- format!(
- " Total Up / Down: {} / {} {}",
- DisplayBandwidth {
- bandwidth: self.state.total_bytes_uploaded as f64,
- as_rate: !c_mode,
- },
- DisplayBandwidth {
- bandwidth: self.state.total_bytes_downloaded as f64,
- as_rate: !c_mode,
- },
- paused_str
- ),
- Style::default().fg(color).modifier(Modifier::BOLD),
- )]
- };
- Paragraph::new(title_text.iter())
- .alignment(Alignment::Left)
- .render(frame, rect);
- }
-}
diff --git a/src/display/ui.rs b/src/display/ui.rs
index 600a6db..6361a7f 100644
--- a/src/display/ui.rs
+++ b/src/display/ui.rs
@@ -3,7 +3,7 @@ use ::std::collections::HashMap;
use ::tui::backend::Backend;
use ::tui::Terminal;
-use crate::display::components::{HelpText, Layout, Table, TotalBandwidth};
+use crate::display::components::{HeaderDetails, HelpText, Layout, Table};
use crate::display::UIState;
use crate::network::{display_connection_string, display_ip_or_host, LocalSocket, Utilization};
@@ -11,6 +11,7 @@ use ::std::net::IpAddr;
use crate::RenderOpts;
use chrono::prelude::*;
+use std::time::Duration;
pub struct Ui<B>
where
@@ -79,14 +80,16 @@ where
));
}
}
- pub fn draw(&mut self, paused: bool, show_dns: bool, ui_offset: usize) {
+
+ pub fn draw(&mut self, paused: bool, show_dns: bool, elapsed_time: Duration, ui_offset: usize) {
let state = &self.state;
let children = self.get_tables_to_display();
self.terminal
.draw(|mut frame| {
let size = frame.size();
- let total_bandwidth = TotalBandwidth {
+ let total_bandwidth = HeaderDetails {
state: &state,
+ elapsed_time,
paused,
};
let help_text = HelpText { paused, show_dns };
diff --git a/src/main.rs b/src/main.rs
index e327be5..586b9d0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,7 +6,7 @@ mod os;
#[cfg(test)]
mod tests;
-use display::{RawTerminalBackend, Ui};
+use display::{elapsed_time, RawTerminalBackend, Ui};
use network::{
dns::{self, IpTable},
Connection, LocalSocket, Sniffer, Utilization,
@@ -17,20 +17,21 @@ use ::pnet::datalink::{DataLinkReceiver, NetworkInterface};
use ::std::collections::HashMap;
use ::std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use ::std::sync::{Arc, Mutex};
+use ::std::thread;
use ::std::thread::park_timeout;
-use ::std::{thread, time};
use ::termion::event::{Event, Key};
use ::tui::backend::Backend;
use std::process;
use ::std::io;
-use ::std::time::Instant;
+use ::std::time::{Duration, Instant};
use ::termion::raw::IntoRawMode;
use ::tui::backend::TermionBackend;
+use std::sync::RwLock;
use structopt::StructOpt;
-const DISPLAY_DELTA: time::Duration = time::Duration::from_millis(1000);
+const DISPLAY_DELTA: Duration = Duration::from_millis(1000);
#[derive(StructOpt, Debug)]
#[structopt(name = "bandwhich")]
@@ -121,6 +122,8 @@ where
{
let running = Arc::new(AtomicBool::new(true));
let paused = Arc::new(AtomicBool::new(false));
+ let last_start_time = Arc::new(RwLock::new(Instant::now()));
+ let cumulative_time = Arc::new(RwLock::new(Duration::new(0, 0)));
let ui_offset = Arc::new(AtomicUsize::new(0));
let dns_shown = opts.show_dns;
@@ -145,15 +148,23 @@ where
.spawn({
let ui = ui.clone();
let paused = paused.clone();
+ let cumulative_time = cumulative_time.clone();
+ let last_start_time = last_start_time.clone();
let ui_offset = ui_offset.clone();
move || {
on_winch({
Box::new(move || {
let mut ui = ui.lock().unwrap();
+ let paused = paused.load(Ordering::SeqCst);
ui.draw(
- paused.load(Ordering::SeqCst),
+ paused,
dns_shown,
+ elapsed_time(
+ *last_start_time.read().unwrap(),
+ *cumulative_time.read().unwrap(),
+ paused,
+ ),
ui_offset.load(Ordering::SeqCst),
);
})
@@ -172,6 +183,8 @@ where
let ui_offset = ui_offset.clone();
let network_utilization = network_utilization.clone();
+ let last_start_time = last_start_time.clone();
+ let cumulative_time = cumulative_time.clone();
let ui = ui.clone();
move || {
@@ -200,10 +213,16 @@ where
if !paused {
ui.update_state(sockets_to_procs, utilization, ip_to_host);
}
+ let elapsed_time = elapsed_time(
+ *last_start_time.read().unwrap(),
+ *cumulative_time.read().unwrap(),
+ paused,
+ );
+
if raw_mode {
ui.output_text(&mut write_to_stdout);
} else {
- ui.draw(paused, dns_shown, ui_offset);
+ ui.draw(paused, dns_shown, elapsed_time, ui_offset);
}
}
let render_duration = render_start_time.elapsed();
@@ -238,14 +257,31 @@ where
break;
}
Event::Key(Key::Char(' ')) => {
- paused.fetch_xor(true, Ordering::SeqCst);
+ let restarting = paused.fetch_xor(true, Ordering::SeqCst);
+ if restarting {
+ *last_start_time.write().unwrap() = Instant::now();
+ } else {
+ let last_start_time_copy = *last_start_time.read().unwrap();
+ let current_cumulative_time_copy =
+ *cumulative_time.read().unwrap();
+ let new_cumulative_time = current_cumulative_time_copy
+ + last_start_time_copy.elapsed();
+ *cumulative_time.write().unwrap() = new_cumulative_time;
+ }
+
display_handler.unpark();
}
Event::Key(Key::Char('\t')) => {
+ let paused = paused.load(Ordering::SeqCst);
+ let elapsed_time = elapsed_time(
+ *last_start_time.read().unwrap(),
+ *cumulative_time.read().unwrap(),
+ paused,
+ );
let table_count = ui.get_table_count();
let new = ui_offset.load(Ordering::SeqCst) + 1 % table_count;
ui_offset.store(new, Ordering::SeqCst);
- ui.draw(paused.load(Ordering::SeqCst), dns_shown, new);
+ ui.draw(paused, dns_shown, elapsed_time, new);
}
_ => (),
};
diff --git a/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total-2.snap b/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total-2.snap
index 62a5202..27a8b30 100644
--- a/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total-2.snap
+++ b/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total-2.snap
@@ -1,8 +1,8 @@
---
source: src/tests/cases/ui.rs
-expression: "&terminal_draw_events_mirror[2]"
+expression: "&terminal_draw_events_mirror[2].replace(\"1 \\n\", \"2 \\n\")"
---
- 98 109B
+ 98 109B 2
diff --git a/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total.snap b/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total.snap
index abe1164..81929e3 100644
--- a/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total.snap
+++ b/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_bi_directional_total.snap
@@ -2,7 +2,7 @@
source: src/tests/cases/ui.rs
expression: "&terminal_draw_events_mirror[1]"
---
- 45B / 49B
+ 45B / 49B 1
diff --git a/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total-2.snap b/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total-2.snap
index 3fec816..cf6c136 100644
--- a/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total-2.snap
+++ b/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total-2.snap
@@ -1,8 +1,8 @@
---
source: src/tests/cases/ui.rs
-expression: "&terminal_draw_events_mirror[2]"
+expression: "&terminal_draw_events_mirror[2].replace(\"1 \\n\", \"2 \\n\")"
---
- 106B
+ 106B 2
diff --git a/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total.snap b/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total.snap
index 3012f6b..f09e329 100644
--- a/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total.snap
+++ b/src/tests/cases/snapshots/ui__sustained_traffic_from_multiple_processes_total.snap
@@ -2,7 +2,7 @@
source: src/tests/cases/ui.rs
expression: "&terminal_draw_events_mirror[1]"
---
- 41B
+ 41B 1
diff --git a/src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total-2.snap b/src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total-2.snap
index b6456b7..8dfceee 100644
--- a/src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total-2.snap
+++ b/src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total-2.snap
@@ -1,8 +1,8 @@
---
source: src/tests/cases/ui.rs
-expression: "&terminal_draw_events_mirror[2]"
+expression: "&terminal_draw_events_mirror[2].replace(\"1 \\n\", \"2 \\n\")"
---
- 53
+ 53 2
diff --git a/src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total.snap b/src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total.snap
index 8c590f5..3f5c319 100644
--- a/src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total.snap
+++ b/src/tests/cases/snapshots/ui__sustained_traffic_from_one_process_total.snap
@@ -2,7 +2,7 @@
source: src/tests/cases/ui.rs
expression: "&terminal_draw_events_mirror[1]"
---
- 22B
+ 22B 1
diff --git a/src/tests/cases/ui.rs b/src/tests/cases/ui.rs
index e755b5a..d3df052 100644
--- a/src/tests/cases/ui.rs
+++ b/src/tests/cases/ui.rs
@@ -707,7 +707,7 @@ fn sustained_traffic_from_one_process_total() {
assert_eq!(terminal_draw_events_mirror.len(), 3);
assert_snapshot!(&terminal_draw_events_mirror[1]);
- assert_snapshot!(&terminal_draw_events_mirror[2]);
+ assert_snapshot!(&terminal_draw_events_mirror[2].replace("1 \n", "2 \n"));
}
#[test]
@@ -816,7 +816,7 @@ fn sustained_traffic_from_multiple_processes_total() {
assert_eq!(terminal_draw_events_mirror.len(), 3);
assert_snapshot!(&terminal_draw_events_mirror[1]);
- assert_snapshot!(&terminal_draw_events_mirror[2]);
+ assert_snapshot!(&terminal_draw_events_mirror[2].replace("1 \n", "2 \n"));
}
#[test]
@@ -981,7 +981,7 @@ fn sustained_traffic_from_multiple_processes_bi_directional_total() {
assert_eq!(terminal_draw_events_mirror.len(), 3);
assert_snapshot!(&terminal_draw_events_mirror[1]);
- assert_snapshot!(&terminal_draw_events_mirror[2]);
+ assert_snapshot!(&terminal_draw_events_mirror[2].replace("1 \n", "2 \n"));
}
#[test]