mirror of
https://github.com/domcyrus/rustnet.git
synced 2026-01-08 06:49:51 -06:00
feat: Display current bandwidth based on recent activity
This commit is contained in:
62
src/app.rs
62
src/app.rs
@@ -333,7 +333,7 @@ impl App {
|
||||
/// Update application state on tick
|
||||
pub fn on_tick(&mut self) -> Result<()> {
|
||||
// Store currently selected connection (if any)
|
||||
let selected = self.selected_connection.clone();
|
||||
let selected_conn_key = self.selected_connection.as_ref().map(|sc| self.get_connection_key(sc));
|
||||
|
||||
// Update connections from shared data updated by the background thread
|
||||
if let Some(shared_data_arc) = &self.connections_data_shared {
|
||||
@@ -370,11 +370,35 @@ impl App {
|
||||
});
|
||||
|
||||
// Update connections with the sorted list
|
||||
self.connections = new_connections;
|
||||
self.connections = new_connections; // self.connections is now updated
|
||||
|
||||
// Calculate current rates for each connection
|
||||
let now = Instant::now();
|
||||
for conn in &mut self.connections {
|
||||
let time_delta = now.duration_since(conn.last_rate_update_time);
|
||||
let time_delta_secs = time_delta.as_secs_f64();
|
||||
|
||||
if time_delta_secs > 0.0 {
|
||||
let bytes_sent_delta = conn.bytes_sent.saturating_sub(conn.prev_bytes_sent);
|
||||
let bytes_received_delta = conn.bytes_received.saturating_sub(conn.prev_bytes_received);
|
||||
|
||||
conn.current_outgoing_rate_bps = bytes_sent_delta as f64 / time_delta_secs;
|
||||
conn.current_incoming_rate_bps = bytes_received_delta as f64 / time_delta_secs;
|
||||
} else {
|
||||
// Avoid division by zero if time_delta is too small or zero
|
||||
conn.current_outgoing_rate_bps = 0.0;
|
||||
conn.current_incoming_rate_bps = 0.0;
|
||||
}
|
||||
|
||||
conn.prev_bytes_sent = conn.bytes_sent;
|
||||
conn.prev_bytes_received = conn.bytes_received;
|
||||
conn.last_rate_update_time = now;
|
||||
}
|
||||
|
||||
|
||||
// Restore selected connection position if possible
|
||||
if let Some(ref conn) = selected {
|
||||
if let Some(idx) = self.find_connection_index(conn) {
|
||||
if let Some(key) = selected_conn_key {
|
||||
if let Some(idx) = self.find_connection_index_by_key(&key) {
|
||||
self.selected_connection_idx = idx;
|
||||
self.selected_connection = Some(self.connections[idx].clone());
|
||||
} else if !self.connections.is_empty() {
|
||||
@@ -394,6 +418,26 @@ impl App {
|
||||
} else {
|
||||
// connections_data_shared is None, likely before start_capture fully initializes it.
|
||||
// self.connections will not be updated this tick.
|
||||
// Still, update rates for existing connections if any (e.g. from initial load)
|
||||
let now = Instant::now();
|
||||
for conn in &mut self.connections {
|
||||
let time_delta = now.duration_since(conn.last_rate_update_time);
|
||||
let time_delta_secs = time_delta.as_secs_f64();
|
||||
|
||||
if time_delta_secs > 0.0 {
|
||||
let bytes_sent_delta = conn.bytes_sent.saturating_sub(conn.prev_bytes_sent);
|
||||
let bytes_received_delta = conn.bytes_received.saturating_sub(conn.prev_bytes_received);
|
||||
|
||||
conn.current_outgoing_rate_bps = bytes_sent_delta as f64 / time_delta_secs;
|
||||
conn.current_incoming_rate_bps = bytes_received_delta as f64 / time_delta_secs;
|
||||
} else {
|
||||
conn.current_outgoing_rate_bps = 0.0;
|
||||
conn.current_incoming_rate_bps = 0.0;
|
||||
}
|
||||
conn.prev_bytes_sent = conn.bytes_sent;
|
||||
conn.prev_bytes_received = conn.bytes_received;
|
||||
conn.last_rate_update_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -510,17 +554,13 @@ impl App {
|
||||
)
|
||||
}
|
||||
|
||||
/// Find the index of a connection that matches the selected connection
|
||||
fn find_connection_index(&self, selected: &Connection) -> Option<usize> {
|
||||
let selected_key = self.get_connection_key(selected);
|
||||
|
||||
/// Find the index of a connection by its key
|
||||
fn find_connection_index_by_key(&self, target_key: &str) -> Option<usize> {
|
||||
for (i, conn) in self.connections.iter().enumerate() {
|
||||
let key = self.get_connection_key(conn);
|
||||
if key == selected_key {
|
||||
if self.get_connection_key(conn) == target_key {
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
@@ -92,8 +92,13 @@ pub struct Connection {
|
||||
pub packets_received: u64,
|
||||
pub created_at: SystemTime,
|
||||
pub last_activity: SystemTime,
|
||||
// pub service_port: Option<u16>, // Field removed as it's unused
|
||||
pub service_name: Option<String>,
|
||||
// Fields for current rate calculation
|
||||
pub prev_bytes_sent: u64,
|
||||
pub prev_bytes_received: u64,
|
||||
pub last_rate_update_time: Instant,
|
||||
pub current_incoming_rate_bps: f64,
|
||||
pub current_outgoing_rate_bps: f64,
|
||||
}
|
||||
|
||||
// get_service_name_raw function is removed.
|
||||
@@ -121,6 +126,12 @@ impl Connection {
|
||||
created_at: now,
|
||||
last_activity: now,
|
||||
service_name: None, // Service name will be set by NetworkMonitor
|
||||
// Initialize new fields for rate calculation
|
||||
prev_bytes_sent: 0,
|
||||
prev_bytes_received: 0,
|
||||
last_rate_update_time: Instant::now(),
|
||||
current_incoming_rate_bps: 0.0,
|
||||
current_outgoing_rate_bps: 0.0,
|
||||
};
|
||||
new_conn
|
||||
}
|
||||
|
||||
25
src/ui.rs
25
src/ui.rs
@@ -170,8 +170,8 @@ fn draw_connections_list(f: &mut Frame, app: &mut App, area: Rect) {
|
||||
let (local_display, remote_display) = formatted_addresses[idx].clone();
|
||||
let service_display = conn.service_name.clone().unwrap_or_else(|| "-".to_string());
|
||||
|
||||
let incoming_rate_str = format_rate(conn.bytes_received, conn.age());
|
||||
let outgoing_rate_str = format_rate(conn.bytes_sent, conn.age());
|
||||
let incoming_rate_str = format_rate_from_bps(conn.current_incoming_rate_bps);
|
||||
let outgoing_rate_str = format_rate_from_bps(conn.current_outgoing_rate_bps);
|
||||
let bandwidth_display = format!("{} / {}", incoming_rate_str, outgoing_rate_str);
|
||||
|
||||
|
||||
@@ -267,12 +267,12 @@ fn draw_side_panel(f: &mut Frame, app: &App, area: Rect) -> Result<()> {
|
||||
Line::from(format!(
|
||||
"{}: {}",
|
||||
app.i18n.get("total_incoming"),
|
||||
format_rate(app.connections.iter().map(|c| c.bytes_received).sum(), app.start_time.elapsed())
|
||||
format_rate_from_bps(app.connections.iter().map(|c| c.current_incoming_rate_bps).sum())
|
||||
)),
|
||||
Line::from(format!(
|
||||
"{}: {}",
|
||||
app.i18n.get("total_outgoing"),
|
||||
format_rate(app.connections.iter().map(|c| c.bytes_sent).sum(), app.start_time.elapsed())
|
||||
format_rate_from_bps(app.connections.iter().map(|c| c.current_outgoing_rate_bps).sum())
|
||||
)),
|
||||
];
|
||||
|
||||
@@ -754,26 +754,35 @@ fn draw_status_bar(f: &mut Frame, app: &App, area: Rect) {
|
||||
f.render_widget(status_bar, area);
|
||||
}
|
||||
|
||||
/// Format rate to human readable form (KB/s, MB/s, etc.)
|
||||
/// Format rate (given as bytes and duration) to human readable form (KB/s, MB/s, etc.)
|
||||
fn format_rate(bytes: u64, duration: std::time::Duration) -> String {
|
||||
if duration.as_secs() == 0 {
|
||||
if duration.as_secs_f64() < 0.001 { // Avoid division by zero or extremely small durations
|
||||
return "-".to_string();
|
||||
}
|
||||
|
||||
let bytes_per_second = bytes as f64 / duration.as_secs_f64();
|
||||
format_rate_from_bps(bytes_per_second)
|
||||
}
|
||||
|
||||
/// Format rate (given as f64 bytes_per_second) to human readable form (KB/s, MB/s, etc.)
|
||||
fn format_rate_from_bps(bytes_per_second: f64) -> String {
|
||||
const KB_PER_SEC: f64 = 1024.0;
|
||||
const MB_PER_SEC: f64 = KB_PER_SEC * 1024.0;
|
||||
const GB_PER_SEC: f64 = MB_PER_SEC * 1024.0;
|
||||
|
||||
if bytes_per_second.is_nan() || bytes_per_second.is_infinite() {
|
||||
return "-".to_string();
|
||||
}
|
||||
|
||||
if bytes_per_second >= GB_PER_SEC {
|
||||
format!("{:.2} GB/s", bytes_per_second / GB_PER_SEC)
|
||||
} else if bytes_per_second >= MB_PER_SEC {
|
||||
format!("{:.2} MB/s", bytes_per_second / MB_PER_SEC)
|
||||
} else if bytes_per_second >= KB_PER_SEC {
|
||||
format!("{:.2} KB/s", bytes_per_second / KB_PER_SEC)
|
||||
} else {
|
||||
} else if bytes_per_second > 0.1 || bytes_per_second == 0.0 { // Show B/s for very small rates or zero
|
||||
format!("{:.0} B/s", bytes_per_second)
|
||||
} else { // For very small, non-zero rates, indicate less than 1 B/s
|
||||
"<1 B/s".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user