Skip to content

Commit 3f4c637

Browse files
committed
improve: enhanced network overflow handling and cleaner help display
1 parent 69973f7 commit 3f4c637

File tree

5 files changed

+55
-35
lines changed

5 files changed

+55
-35
lines changed

src/app.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl App {
130130
}
131131
Err(e) => {
132132
error!("Failed to read directory {:?}: {}", path, e);
133-
vec!["Permission Denied".to_string()]
133+
vec![format!("<Error: {}>", e)]
134134
},
135135
}
136136
}
@@ -228,7 +228,7 @@ impl App {
228228
self.selected_network - 1
229229
};
230230
// Reset network history when switching interfaces
231-
self.network_history = NetworkHistory::new();
231+
self.network_history.clear();
232232
}
233233
}
234234
_ => {}
@@ -254,7 +254,7 @@ impl App {
254254
if network_count > 0 {
255255
self.selected_network = (self.selected_network + 1) % network_count;
256256
// Reset network history when switching interfaces
257-
self.network_history = NetworkHistory::new();
257+
self.network_history.clear();
258258
}
259259
}
260260
_ => {}
@@ -371,8 +371,8 @@ impl App {
371371
self.file_list_state.select(Some(0));
372372
}
373373
} else if selected_item.starts_with("📁") {
374-
// Enter directory
375-
let dir_name = selected_item.trim_start_matches("📁 ");
374+
// Enter directory - handle truncated names properly
375+
let dir_name = selected_item.trim_start_matches("📁 ").trim_end_matches("...");
376376
let new_path = self.current_dir.join(dir_name);
377377
if new_path.is_dir() {
378378
self.current_dir = new_path;

src/network.rs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,28 @@ pub struct NetworkHistory {
1111
pub last_tx_bytes: u64,
1212
pub max_history: usize,
1313
pub current_interface: String,
14+
pub counter_wrapped: bool,
1415
}
1516

1617
impl NetworkHistory {
1718
pub fn new() -> Self {
1819
Self {
19-
rx_history: VecDeque::new(),
20-
tx_history: VecDeque::new(),
21-
rx_rates: VecDeque::new(),
22-
tx_rates: VecDeque::new(),
20+
rx_history: VecDeque::with_capacity(NETWORK_HISTORY_SIZE),
21+
tx_history: VecDeque::with_capacity(NETWORK_HISTORY_SIZE),
22+
rx_rates: VecDeque::with_capacity(NETWORK_HISTORY_SIZE),
23+
tx_rates: VecDeque::with_capacity(NETWORK_HISTORY_SIZE),
2324
last_rx_bytes: 0,
2425
last_tx_bytes: 0,
25-
max_history: NETWORK_HISTORY_SIZE, // Keep 60 data points (2 minutes at 2-second intervals)
26+
max_history: NETWORK_HISTORY_SIZE,
2627
current_interface: String::new(),
28+
counter_wrapped: false,
2729
}
2830
}
2931

3032
pub fn update(&mut self, networks: &Networks, selected_interface: &str) {
3133
// Find the selected network interface or use the first available one
32-
let network_list: Vec<_> = networks.list().iter().take(100).collect(); // Limit to 100 network interfaces
33-
let (interface_name, network_data) = if let Some(item) = network_list.get(0) {
34+
let network_list: Vec<_> = networks.list().iter().take(100).collect();
35+
let (interface_name, network_data) = if let Some(item) = network_list.first() {
3436
// If we have a specific interface selected, try to find it
3537
if !selected_interface.is_empty() {
3638
network_list.iter()
@@ -49,20 +51,17 @@ impl NetworkHistory {
4951
let total_rx = network_data.total_received();
5052
let total_tx = network_data.total_transmitted();
5153

52-
if self.last_rx_bytes > 0 && self.last_tx_bytes > 0 {
53-
// Calculate rate (bytes per 2 seconds) with overflow detection
54-
let rx_rate = if total_rx >= self.last_rx_bytes {
55-
total_rx.saturating_sub(self.last_rx_bytes)
56-
} else {
57-
// Network counter reset or overflow - skip this measurement
58-
0
59-
};
60-
let tx_rate = if total_tx >= self.last_tx_bytes {
61-
total_tx.saturating_sub(self.last_tx_bytes)
62-
} else {
63-
// Network counter reset or overflow - skip this measurement
64-
0
65-
};
54+
// Detect counter wraparound or interface reset
55+
if total_rx < self.last_rx_bytes || total_tx < self.last_tx_bytes {
56+
self.counter_wrapped = true;
57+
self.last_rx_bytes = total_rx;
58+
self.last_tx_bytes = total_tx;
59+
return; // Skip this measurement entirely
60+
}
61+
62+
if self.last_rx_bytes > 0 && self.last_tx_bytes > 0 && !self.counter_wrapped {
63+
let rx_rate = total_rx.saturating_sub(self.last_rx_bytes);
64+
let tx_rate = total_tx.saturating_sub(self.last_tx_bytes);
6665

6766
self.rx_rates.push_back(rx_rate);
6867
self.tx_rates.push_back(tx_rate);
@@ -87,5 +86,16 @@ impl NetworkHistory {
8786

8887
self.last_rx_bytes = total_rx;
8988
self.last_tx_bytes = total_tx;
89+
self.counter_wrapped = false;
90+
}
91+
92+
pub fn clear(&mut self) {
93+
self.rx_history.clear();
94+
self.tx_history.clear();
95+
self.rx_rates.clear();
96+
self.tx_rates.clear();
97+
self.last_rx_bytes = 0;
98+
self.last_tx_bytes = 0;
99+
self.counter_wrapped = false;
90100
}
91101
}

src/ui/help.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ NAVIGATION:
2323
PANELS:
2424
1. System Monitor - CPU, Memory, Uptime, Architecture
2525
2. System Status - Time, Disk usage, Network stats
26-
3. Process Manager- Top processes (j/k/PgUp/PgDn/Home/End)
27-
4. File Explorer - Navigate directories (j/k/PgUp/PgDn/Home/End + Enter)
28-
5. Network Graph - Real-time network traffic (↑↓ to cycle interfaces)
26+
3. Process Manager- Top processes by CPU usage
27+
4. File Explorer - Directory browser with navigation
28+
5. Network Graph - Real-time network traffic graphs
2929
3030
FEATURES:
3131
• Real-time system monitoring

src/ui/panels.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use chrono::{DateTime, Local};
1010
use crate::{
1111
app::App,
1212
utils::{
13-
format_memory_size, format_network_size, format_network_rate, truncate_string,
13+
format_memory_size, format_network_size, format_network_rate, truncate_string, format_path_display,
1414
PROCESS_NAME_MAX_LEN, INTERFACE_NAME_MAX_LEN,
1515
},
1616
};
@@ -178,11 +178,7 @@ pub fn render_file_browser(app: &App, frame: &mut Frame, area: Rect, is_selected
178178
Style::default().fg(Color::White)
179179
};
180180

181-
let path_display = if app.current_dir.to_string_lossy().len() > 30 {
182-
format!("...{}", app.current_dir.to_string_lossy().chars().rev().take(27).collect::<String>().chars().rev().collect::<String>())
183-
} else {
184-
app.current_dir.to_string_lossy().to_string()
185-
};
181+
let path_display = format_path_display(&app.current_dir);
186182
let title = format!("📂 Explorer: {}", path_display);
187183

188184
let block = Block::default()

src/utils.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub const MANUAL_REFRESH_COOLDOWN: Duration = Duration::from_millis(500);
1111
pub const PROCESS_NAME_MAX_LEN: usize = 35;
1212
pub const INTERFACE_NAME_MAX_LEN: usize = 20;
1313
pub const FILE_NAME_MAX_LEN: usize = 40;
14+
pub const MAX_PATH_DISPLAY_LEN: usize = 30;
1415

1516
/// Format memory size in bytes to human-readable string
1617
pub fn format_memory_size(bytes: u64) -> String {
@@ -56,3 +57,16 @@ pub fn truncate_string(s: &str, max_len: usize) -> String {
5657
format!("{}...", &s[..max_len.saturating_sub(3)])
5758
}
5859
}
60+
61+
/// Format path display with proper character boundary handling
62+
pub fn format_path_display(path: &std::path::Path) -> String {
63+
let path_str = path.to_string_lossy();
64+
if path_str.len() <= MAX_PATH_DISPLAY_LEN {
65+
path_str.to_string()
66+
} else {
67+
let chars: Vec<char> = path_str.chars().collect();
68+
let take_len = MAX_PATH_DISPLAY_LEN.saturating_sub(3);
69+
let start_pos = chars.len().saturating_sub(take_len);
70+
format!("...{}", chars[start_pos..].iter().collect::<String>())
71+
}
72+
}

0 commit comments

Comments
 (0)