summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/display/components/total_bandwidth.rs27
-rw-r--r--src/display/ui.rs7
-rw-r--r--src/main.rs16
-rw-r--r--src/network/dns/client.rs6
-rw-r--r--src/network/dns/resolver.rs13
-rw-r--r--src/os/shared.rs30
-rw-r--r--src/tests/cases/snapshots/ui__pause_by_space-2.snap55
-rw-r--r--src/tests/cases/snapshots/ui__pause_by_space-3.snap55
-rw-r--r--src/tests/cases/snapshots/ui__pause_by_space-4.snap55
-rw-r--r--src/tests/cases/snapshots/ui__pause_by_space-5.snap55
-rw-r--r--src/tests/cases/snapshots/ui__pause_by_space.snap55
-rw-r--r--src/tests/cases/test_utils.rs17
-rw-r--r--src/tests/cases/ui.rs55
-rw-r--r--src/tests/fakes/fake_input.rs17
14 files changed, 413 insertions, 50 deletions
diff --git a/src/display/components/total_bandwidth.rs b/src/display/components/total_bandwidth.rs
index cd6a6f2..ba78d2d 100644
--- a/src/display/components/total_bandwidth.rs
+++ b/src/display/components/total_bandwidth.rs
@@ -8,18 +8,29 @@ 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 title_text = [Text::styled(
- format!(
- " Total Rate Up / Down: {} / {}",
- DisplayBandwidth(self.state.total_bytes_uploaded as f64),
- DisplayBandwidth(self.state.total_bytes_downloaded as f64)
- ),
- Style::default().fg(Color::Green).modifier(Modifier::BOLD),
- )];
+ 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 Rate Up / Down: {} / {} {}",
+ DisplayBandwidth(self.state.total_bytes_uploaded as f64),
+ DisplayBandwidth(self.state.total_bytes_downloaded as f64),
+ paused_str
+ ),
+ Style::default().fg(color).modifier(Modifier::BOLD),
+ )]
+ };
Paragraph::new(title_text.iter())
.block(Block::default().borders(Borders::NONE))
.alignment(Alignment::Left)
diff --git a/src/display/ui.rs b/src/display/ui.rs
index dd8ecfb..49b6721 100644
--- a/src/display/ui.rs
+++ b/src/display/ui.rs
@@ -74,7 +74,7 @@ where
));
}
}
- pub fn draw(&mut self) {
+ pub fn draw(&mut self, paused: bool) {
let state = &self.state;
let ip_to_host = &self.ip_to_host;
self.terminal
@@ -83,7 +83,10 @@ where
let connections = Table::create_connections_table(&state, &ip_to_host);
let processes = Table::create_processes_table(&state);
let remote_addresses = Table::create_remote_addresses_table(&state, &ip_to_host);
- let total_bandwidth = TotalBandwidth { state: &state };
+ let total_bandwidth = TotalBandwidth {
+ state: &state,
+ paused,
+ };
let layout = Layout {
header: total_bandwidth,
children: vec![processes, connections, remote_addresses],
diff --git a/src/main.rs b/src/main.rs
index ea40de0..30a9b25 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -100,6 +100,7 @@ where
B: Backend + Send + 'static,
{
let running = Arc::new(AtomicBool::new(true));
+ let paused = Arc::new(AtomicBool::new(false));
let mut active_threads = vec![];
@@ -121,11 +122,12 @@ where
.name("resize_handler".to_string())
.spawn({
let ui = ui.clone();
+ let paused = paused.clone();
move || {
on_winch({
Box::new(move || {
let mut ui = ui.lock().unwrap();
- ui.draw();
+ ui.draw(paused.load(Ordering::SeqCst));
})
});
}
@@ -138,6 +140,7 @@ where
.name("display_handler".to_string())
.spawn({
let running = running.clone();
+ let paused = paused.clone();
let network_utilization = network_utilization.clone();
move || {
while running.load(Ordering::Acquire) {
@@ -160,11 +163,14 @@ where
}
{
let mut ui = ui.lock().unwrap();
- ui.update_state(sockets_to_procs, utilization, ip_to_host);
+ let paused = paused.load(Ordering::SeqCst);
+ if !paused {
+ ui.update_state(sockets_to_procs, utilization, ip_to_host);
+ }
if raw_mode {
ui.output_text(&mut write_to_stdout);
} else {
- ui.draw();
+ ui.draw(paused);
}
}
let render_duration = render_start_time.elapsed();
@@ -195,6 +201,10 @@ where
display_handler.unpark();
break;
}
+ Event::Key(Key::Char(' ')) => {
+ paused.fetch_xor(true, Ordering::SeqCst);
+ display_handler.unpark();
+ }
_ => (),
};
}
diff --git a/src/network/dns/client.rs b/src/network/dns/client.rs
index 1f3fe17..f9d12ed 100644
--- a/src/network/dns/client.rs
+++ b/src/network/dns/client.rs
@@ -1,7 +1,6 @@
use crate::network::dns::{resolver::Lookup, IpTable};
use std::{
collections::HashSet,
- future::Future,
net::Ipv4Addr,
sync::{Arc, Mutex},
thread::{Builder, JoinHandle},
@@ -23,14 +22,12 @@ pub struct Client {
}
impl Client {
- pub fn new<R, B>(resolver: R, background: B) -> Result<Self, failure::Error>
+ pub fn new<R>(resolver: R, mut runtime: Runtime) -> Result<Self, failure::Error>
where
R: Lookup + Send + Sync + 'static,
- B: Future<Output = ()> + Send + 'static,
{
let cache = Arc::new(Mutex::new(IpTable::new()));
let pending = Arc::new(Mutex::new(PendingAddrs::new()));
- let mut runtime = Runtime::new()?;
let (tx, mut rx) = mpsc::channel::<Vec<Ipv4Addr>>(CHANNEL_SIZE);
let handle = Builder::new().name("resolver".into()).spawn({
@@ -39,7 +36,6 @@ impl Client {
move || {
runtime.block_on(async {
let resolver = Arc::new(resolver);
- tokio::spawn(background);
while let Some(ips) = rx.recv().await {
for ip in ips {
diff --git a/src/network/dns/resolver.rs b/src/network/dns/resolver.rs
index 69f6308..007c485 100644
--- a/src/network/dns/resolver.rs
+++ b/src/network/dns/resolver.rs
@@ -1,18 +1,19 @@
use async_trait::async_trait;
-use std::{future::Future, net::Ipv4Addr};
-use trust_dns_resolver::{error::ResolveErrorKind, AsyncResolver};
+use std::net::Ipv4Addr;
+use tokio::runtime::Handle;
+use trust_dns_resolver::{error::ResolveErrorKind, TokioAsyncResolver};
#[async_trait]
pub trait Lookup {
async fn lookup(&self, ip: Ipv4Addr) -> Option<String>;
}
-pub struct Resolver(AsyncResolver);
+pub struct Resolver(TokioAsyncResolver);
impl Resolver {
- pub fn new() -> Result<(Self, impl Future<Output = ()>), failure::Error> {
- let (resolver, background) = AsyncResolver::from_system_conf()?;
- Ok((Self(resolver), background))
+ pub async fn new(runtime: Handle) -> Result<Self, failure::Error> {
+ let resolver = TokioAsyncResolver::from_system_conf(runtime).await?;
+ Ok(Self(resolver))
}
}
diff --git a/src/os/shared.rs b/src/os/shared.rs
index ec6a294..55a8553 100644
--- a/src/os/shared.rs
+++ b/src/os/shared.rs
@@ -4,6 +4,7 @@ use ::pnet_bandwhich_fork::datalink::{self, Config, NetworkInterface};
use ::std::io::{self, stdin, Write};
use ::termion::event::Event;
use ::termion::input::TermRead;
+use ::tokio::runtime::Runtime;
use ::std::io::ErrorKind;
use ::std::time;
@@ -110,9 +111,7 @@ pub fn get_input(
for iface in network_frames {
if let Some(iface_error) = iface.err() {
if let ErrorKind::PermissionDenied = iface_error.kind() {
- failure::bail!(
- "Insufficient permissions to listen on network interface(s). Try running with sudo.",
- )
+ failure::bail!(eperm_message())
}
}
}
@@ -123,8 +122,9 @@ pub fn get_input(
let write_to_stdout = create_write_to_stdout();
let (on_winch, cleanup) = sigwinch();
let dns_client = if resolve {
- let (resolver, background) = dns::Resolver::new()?;
- let dns_client = dns::Client::new(resolver, background)?;
+ let mut runtime = Runtime::new()?;
+ let resolver = runtime.block_on(dns::Resolver::new(runtime.handle().clone()))?;
+ let dns_client = dns::Client::new(resolver, runtime)?;
Some(dns_client)
} else {
None
@@ -141,3 +141,23 @@ pub fn get_input(
write_to_stdout,
})
}
+
+#[inline]
+#[cfg(target_os = "macos")]
+fn eperm_message() -> &'static str {
+ "Insufficient permissions to listen on network interface(s). Try running with sudo."
+}
+
+#[inline]
+#[cfg(target_os = "linux")]
+fn eperm_message() -> &'static str {
+ r#"
+ Insufficient permissions to listen on network interface(s). You can work around
+ this issue like this:
+
+ * Try running `bandwhich` with `sudo`
+
+ * Build a `setcap(8)` wrapper for `bandwhich` with the following rules:
+ `cap_net_raw,cap_net_admin+ep`
+ "#
+}
diff --git a/src/tests/cases/snapshots/ui__pause_by_space-2.snap b/src/tests/cases/snapshots/ui__pause_by_space-2.snap
new file mode 100644
index 0000000..204efd1
--- /dev/null
+++ b/src/tests/cases/snapshots/ui__pause_by_space-2.snap
@@ -0,0 +1,55 @@
+---
+source: src/tests/cases/ui.rs
+expression: "&terminal_draw_events_mirror[1]"
+---
+ Total Rate Up / Down: 0Bps / 0Bps [PAUSED]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/tests/cases/snapshots/ui__pause_by_space-3.snap b/src/tests/cases/snapshots/ui__pause_by_space-3.snap
new file mode 100644
index 0000000..d710afb
--- /dev/null
+++ b/src/tests/cases/snapshots/ui__pause_by_space-3.snap
@@ -0,0 +1,55 @@
+---
+source: src/tests/cases/ui.rs
+expression: "&terminal_draw_events_mirror[2]"
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/tests/cases/snapshots/ui__pause_by_space-4.snap b/src/tests/cases/snapshots/ui__pause_by_space-4.snap
new file mode 100644
index 0000000..5488196
--- /dev/null
+++ b/src/tests/cases/snapshots/ui__pause_by_space-4.snap
@@ -0,0 +1,55 @@
+---
+source: src/tests/cases/ui.rs
+expression: "&terminal_draw_events_mirror[3]"
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/tests/cases/snapshots/ui__pause_by_space-5.snap b/src/tests/cases/snapshots/ui__pause_by_space-5.snap
new file mode 100644
index 0000000..1524b66
--- /dev/null
+++ b/src/tests/cases/snapshots/ui__pause_by_space-5.snap
@@ -0,0 +1,55 @@
+---
+source: src/tests/cases/ui.rs
+expression: "&terminal_draw_events_mirror[4]"
+---
+ Total Rate Up / Down: 0Bps / 0Bps
+
+
+
+
+
+
+
+
+