Skip to content

Commit 2be6660

Browse files
committed
log auto scroll flag
1 parent ecb6f31 commit 2be6660

File tree

5 files changed

+73
-19
lines changed

5 files changed

+73
-19
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ description = "A graphical user interface for managing OverTLS clients."
1111

1212
[dependencies]
1313
arboard = { version = "3.6.1", default-features = false, features = ["image-data"] }
14-
chrono = "0.4.41"
14+
chrono = "0.4.42"
1515
dirs = "6.0.0"
1616
env_logger = "0.11.8"
1717
fltk = { version = "1.5.14", features = ["fltk-bundled"] }
@@ -27,7 +27,7 @@ serde = { version = "1.0.219", features = ["derive"] }
2727
serde_json = "1.0.143"
2828
tokio = { version = "1.47.1", features = ["full"] }
2929
tray-icon = { version = "0.21.1", default-features = false, features = ["libxdo"] }
30-
tun2proxy = { version = "0.7.14", default-features = false }
30+
tun2proxy = { version = "0.7.15", default-features = false }
3131

3232
[target.'cfg(target_os = "linux")'.dependencies]
3333
gtk = "0.18.2"

src/main.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ async fn main() -> Result<(), BoxError> {
160160
let running_token_run = running_token.clone();
161161
let running_handle_run = running_handle.clone();
162162
let state_clone = state.clone();
163-
menubar.add("&Main/Run", Shortcut::None, MenuFlag::Normal, move |_m| {
163+
menubar.add("&Main/Run\t", Shortcut::Alt | 'r', MenuFlag::Normal, move |_m| {
164164
let Some(idx) = *current_node_index_run.borrow() else {
165165
rfd::MessageDialog::new()
166166
.set_title("Error")
@@ -214,20 +214,33 @@ async fn main() -> Result<(), BoxError> {
214214
let title = config.remarks.clone().unwrap_or_default();
215215
let token = overtls::CancellationToken::new();
216216
*running_token_run.lock().unwrap() = Some(token.clone());
217-
let handle = std::thread::spawn(move || core::main_task_block(config, tun2proxy_args, token));
217+
let title_clone = title.clone();
218+
let running_token = running_token_run.clone();
219+
let running_handle = running_handle_run.clone();
220+
let handle = std::thread::spawn(move || {
221+
let res = core::main_task_block(config, tun2proxy_args, token);
222+
if let Err(e) = &res {
223+
log::error!("Node '{title_clone}' exited with error: {e}");
224+
}
225+
if let Ok(mut token) = running_token.try_lock()
226+
&& let Some(token) = token.take()
227+
{
228+
token.cancel();
229+
}
230+
if let Ok(mut handle) = running_handle.try_lock() {
231+
handle.take();
232+
}
233+
res
234+
});
218235
*running_handle_run.lock().unwrap() = Some(handle);
219236
log::debug!("Node '{title}' is starting...");
220237
});
221238

222239
let running_token_stop = running_token.clone();
223240
let running_handle_stop = running_handle.clone();
224-
menubar.add("&Main/Stop", Shortcut::None, MenuFlag::MenuDivider, move |_m| {
241+
menubar.add("&Main/Stop\t", Shortcut::Alt | 's', MenuFlag::MenuDivider, move |_m| {
225242
if let Err(e) = stop_running_node(&running_token_stop, &running_handle_stop) {
226-
rfd::MessageDialog::new()
227-
.set_title("Error")
228-
.set_description(format!("Failed to stop running node: {e}"))
229-
.set_level(rfd::MessageLevel::Error)
230-
.show();
243+
log::error!("Failed to stop running node: {e}");
231244
}
232245
});
233246

@@ -240,13 +253,13 @@ async fn main() -> Result<(), BoxError> {
240253
if let Some(token) = running_token.lock().map_err(f1)?.take() {
241254
token.cancel();
242255
} else {
243-
err_info = Some("No running node.");
256+
err_info = Some("No running node.".to_string());
244257
}
245258
let f2 = |e| std::io::Error::other(format!("running_handle lock error: {e}"));
246259
if let Some(handle) = running_handle.lock().map_err(f2)?.take()
247-
&& util::thread_handle_join_with_timeout(handle, 1000).is_none()
260+
&& let Err(e) = util::thread_handle_join_with_timeout(handle, 3000)
248261
{
249-
err_info = Some("Node thread did not finish in 1 second, force exit.");
262+
err_info = Some(format!("Failed to join running thread: {e:?}"));
250263
}
251264
err_info.map(|e| Err(std::io::Error::other(e))).unwrap_or(Ok(()))
252265
}
@@ -722,8 +735,10 @@ async fn main() -> Result<(), BoxError> {
722735
style_buffer.set_text(new_style);
723736
}
724737
log_display.set_highlight_data(style_buffer.clone(), style_table);
725-
let lines = log_buffer.count_lines(0, log_buffer.length());
726-
log_display.scroll(lines, 0);
738+
if state.borrow().system_settings.as_ref().unwrap().log_auto_scroll.unwrap_or(true) {
739+
let lines = log_buffer.count_lines(0, log_buffer.length());
740+
log_display.scroll(lines, 0);
741+
}
727742
}
728743
}
729744
}

src/settings_dialog.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ macro_rules! add_row_spin {
8989
/// Pop up the settings dialog, and send the result via channel to avoid idle closure accumulation.
9090
pub fn show_settings_dialog(win: &Window, system_settings: &SystemSettings, tx: std::sync::mpsc::Sender<SystemSettings>) {
9191
let dialog_w = 600;
92-
let dialog_h = 320;
92+
let dialog_h = 360;
9393
let x = win.x() + (win.width() - dialog_w) / 2;
9494
let y = win.y() + (win.height() - dialog_h) / 2;
9595
let mut dlg = Window::new(x, y, dialog_w, dialog_h, "Settings");
@@ -157,6 +157,7 @@ pub fn show_settings_dialog(win: &Window, system_settings: &SystemSettings, tx:
157157
let mut ipstack_log_level = add_row_choice!("Ipstack Log Level", ipstack_log_level, flex_logging, &log_level_options());
158158
let mut overtls_log_level = add_row_choice!("OverTls Log Level", overtls_log_level, flex_logging, &log_level_options());
159159
let mut tun2proxy_log_level = add_row_choice!("Tun2proxy Log Level", tun2proxy_log_level, flex_logging, &log_level_options());
160+
let mut log_auto_scroll = add_row_check!("Log Auto Scroll", log_auto_scroll, flex_logging);
160161

161162
tab_logging.end();
162163

@@ -191,6 +192,7 @@ pub fn show_settings_dialog(win: &Window, system_settings: &SystemSettings, tx:
191192
ipstack_log_level.set_value(log_level_index(system_settings.ipstack_log_level.as_deref().unwrap_or("Info")));
192193
overtls_log_level.set_value(log_level_index(system_settings.overtls_log_level.as_deref().unwrap_or("Info")));
193194
tun2proxy_log_level.set_value(log_level_index(system_settings.tun2proxy_log_level.as_deref().unwrap_or("Info")));
195+
log_auto_scroll.set_value(system_settings.log_auto_scroll.unwrap_or(true));
194196

195197
let mut submit_btn = Button::new(dialog_w / 2 - 60, dialog_h - 45, 120, 35, "Submit");
196198
dlg.end();
@@ -228,6 +230,7 @@ pub fn show_settings_dialog(win: &Window, system_settings: &SystemSettings, tx:
228230
let ipstack_log_level_val = Some(log_level_by_index(ipstack_log_level.value()));
229231
let overtls_log_level_val = Some(log_level_by_index(overtls_log_level.value()));
230232
let tun2proxy_log_level_val = Some(log_level_by_index(tun2proxy_log_level.value()));
233+
let log_auto_scroll_val = log_auto_scroll.value();
231234

232235
let tun2proxy_cfg = Some(tun2proxy::Args {
233236
exit_on_fatal_error: exit_on_fatal_error_val,
@@ -255,6 +258,7 @@ pub fn show_settings_dialog(win: &Window, system_settings: &SystemSettings, tx:
255258
ipstack_log_level: ipstack_log_level_val,
256259
overtls_log_level: overtls_log_level_val,
257260
tun2proxy_log_level: tun2proxy_log_level_val,
261+
log_auto_scroll: Some(log_auto_scroll_val),
258262
};
259263
let _ = tx.send(new_settings);
260264
dlg_cb.hide();

src/states_manager.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ pub struct SystemSettings {
6868

6969
#[serde(skip_serializing_if = "Option::is_none", default)]
7070
pub tun2proxy_log_level: Option<String>, // tun2proxy log level
71+
72+
#[serde(skip_serializing_if = "Option::is_none")]
73+
pub log_auto_scroll: Option<bool>, // log auto scroll
7174
}
7275

7376
impl Default for SystemSettings {
@@ -88,6 +91,7 @@ impl Default for SystemSettings {
8891
ipstack_log_level: Some("Debug".to_string()),
8992
overtls_log_level: Some("Debug".to_string()),
9093
tun2proxy_log_level: Some("Debug".to_string()),
94+
log_auto_scroll: Some(true),
9195
}
9296
}
9397
}

src/util.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,50 @@ pub const fn host_os_name() -> &'static str {
1212
}
1313
}
1414

15-
pub fn thread_handle_join_with_timeout<T>(handle: std::thread::JoinHandle<T>, timeout_ms: u64) -> Option<T> {
15+
// ===============================================================================================
16+
17+
#[derive(Debug)]
18+
pub enum ThreadJoinError {
19+
Timeout,
20+
Panic(Box<dyn std::any::Any + Send + 'static>),
21+
}
22+
23+
impl std::fmt::Display for ThreadJoinError {
24+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25+
match self {
26+
ThreadJoinError::Timeout => write!(f, "Thread join timed out"),
27+
ThreadJoinError::Panic(p) => {
28+
if let Some(s) = p.downcast_ref::<String>() {
29+
write!(f, "Thread panicked: {s}")
30+
} else if let Some(s) = p.downcast_ref::<&str>() {
31+
write!(f, "Thread panicked: {s}")
32+
} else if let Some(s) = p.downcast_ref::<std::io::Error>() {
33+
write!(f, "Thread panicked: {s}")
34+
} else {
35+
write!(f, "Thread panicked with unknown type")
36+
}
37+
}
38+
}
39+
}
40+
}
41+
42+
impl std::error::Error for ThreadJoinError {}
43+
44+
pub fn thread_handle_join_with_timeout<T>(handle: std::thread::JoinHandle<T>, timeout_ms: u64) -> Result<T, ThreadJoinError> {
1645
let start = std::time::Instant::now();
1746
loop {
1847
if handle.is_finished() {
19-
return handle.join().ok();
48+
return handle.join().map_err(ThreadJoinError::Panic);
2049
}
2150
if start.elapsed() > std::time::Duration::from_millis(timeout_ms) {
22-
return None;
51+
return Err(ThreadJoinError::Timeout);
2352
}
2453
std::thread::sleep(std::time::Duration::from_millis(50));
2554
}
2655
}
2756

57+
// ===============================================================================================
58+
2859
pub fn file_chooser_open_file(title: &str, default_path: Option<&str>, filter: &str, filter_exts: &[&str]) -> Option<PathBuf> {
2960
rfd::FileDialog::new()
3061
.set_title(title)

0 commit comments

Comments
 (0)