diff --git a/Cargo.lock b/Cargo.lock index 3206364e2..2c5c14fa2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1117,6 +1117,7 @@ dependencies = [ "chrono", "clash-verge-draft", "clash-verge-logging", + "clash-verge-signal", "clash_verge_logger", "clash_verge_service_ipc", "compact_str", @@ -1147,7 +1148,6 @@ dependencies = [ "serde", "serde_json", "serde_yaml_ng", - "signal-hook 0.3.18", "smartstring", "sys-locale", "sysinfo", @@ -1172,7 +1172,6 @@ dependencies = [ "tokio-stream", "warp", "winapi", - "windows-sys 0.61.2", "winreg 0.55.0", "zip 6.0.0", ] @@ -1197,6 +1196,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "clash-verge-signal" +version = "0.1.0" +dependencies = [ + "clash-verge-logging", + "log", + "signal-hook 0.3.18", + "tauri", + "windows-sys 0.61.2", +] + [[package]] name = "clash_verge_logger" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 413bdf1d4..80beae005 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "src-tauri", "crates/clash-verge-draft", "crates/clash-verge-logging", + "crates/clash-verge-signal", ] resolver = "2" @@ -42,6 +43,8 @@ strip = false [workspace.dependencies] clash-verge-draft = { path = "crates/clash-verge-draft" } clash-verge-logging = { path = "crates/clash-verge-logging" } +clash-verge-signal = { path = "crates/clash-verge-signal" } +tauri = { version = "2.9.3" } parking_lot = { version = "0.12.5", features = [ "hardware-lock-elision", "send_guard", diff --git a/crates/clash-verge-signal/Cargo.toml b/crates/clash-verge-signal/Cargo.toml new file mode 100644 index 000000000..998d9bd24 --- /dev/null +++ b/crates/clash-verge-signal/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "clash-verge-signal" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true + +[dependencies] +tauri = { workspace = true } +clash-verge-logging = { workspace = true } +log = { workspace = true } + +[target.'cfg(unix)'.dependencies] +signal-hook = "0.3.18" + +[target.'cfg(windows)'.dependencies] +windows-sys = { version = "0.61.2", features = [ + "Win32_Foundation", + "Win32_Graphics_Gdi", + "Win32_System_SystemServices", + "Win32_UI_WindowsAndMessaging", +] } + + +[lints] +workspace = true diff --git a/crates/clash-verge-signal/src/lib.rs b/crates/clash-verge-signal/src/lib.rs new file mode 100644 index 000000000..c30ad02a5 --- /dev/null +++ b/crates/clash-verge-signal/src/lib.rs @@ -0,0 +1,16 @@ +#[cfg(unix)] +mod unix; +#[cfg(windows)] +mod windows; + +pub fn register(#[cfg(windows)] app_handle: &tauri::AppHandle, f: F) +where + F: Fn() -> Fut + Send + Sync + 'static, + Fut: Future + Send + 'static, +{ + #[cfg(unix)] + unix::register(f); + + #[cfg(windows)] + windows::register(app_handle, f); +} diff --git a/crates/clash-verge-signal/src/unix.rs b/crates/clash-verge-signal/src/unix.rs new file mode 100644 index 000000000..3ec421eeb --- /dev/null +++ b/crates/clash-verge-signal/src/unix.rs @@ -0,0 +1,44 @@ +use signal_hook::{ + consts::{SIGHUP, SIGINT, SIGTERM}, + iterator::Signals, + low_level, +}; + +use clash_verge_logging::{Type, logging, logging_error}; + +pub fn register(f: F) +where + F: Fn() -> Fut + Send + Sync + 'static, + Fut: Future + Send + 'static, +{ + tauri::async_runtime::spawn(async move { + let signals = [SIGTERM, SIGINT, SIGHUP]; + + let mut sigs = match Signals::new(signals) { + Ok(s) => s, + Err(e) => { + logging!(error, Type::System, "注册信号处理器失败: {}", e); + return; + } + }; + + for signal in &mut sigs { + let signal_to_str = |signal: i32| match signal { + SIGTERM => "SIGTERM", + SIGINT => "SIGINT", + SIGHUP => "SIGHUP", + _ => "UNKNOWN", + }; + + logging!(info, Type::System, "捕获到信号 {}", signal_to_str(signal)); + + f().await; + + logging_error!( + Type::System, + "信号 {:?} 默认处理失败", + low_level::emulate_default_handler(signal) + ); + } + }); +} diff --git a/src-tauri/src/module/signal/windows.rs b/crates/clash-verge-signal/src/windows.rs similarity index 77% rename from src-tauri/src/module/signal/windows.rs rename to crates/clash-verge-signal/src/windows.rs index 582ab19ef..f60d4215a 100644 --- a/src-tauri/src/module/signal/windows.rs +++ b/crates/clash-verge-signal/src/windows.rs @@ -1,4 +1,6 @@ -use tauri::Manager as _; +use std::{future::Future, pin::Pin, sync::OnceLock}; + +use tauri::{AppHandle, Manager as _}; use windows_sys::Win32::{ Foundation::{HWND, LPARAM, LRESULT, WPARAM}, UI::WindowsAndMessaging::{ @@ -8,13 +10,17 @@ use windows_sys::Win32::{ }, }; -use crate::{core::handle, feat}; use clash_verge_logging::{Type, logging}; // code refer to: // global-hotkey (https://github.com/tauri-apps/global-hotkey) // Global Shortcut (https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/global-shortcut) +type ShutdownHandler = + Box Pin + Send>> + Send + Sync>; + +static SHUTDOWN_HANDLER: OnceLock = OnceLock::new(); + struct ShutdownState { hwnd: HWND, } @@ -49,11 +55,19 @@ unsafe extern "system" fn shutdown_proc( ); } WM_ENDSESSION => { - tauri::async_runtime::block_on(async move { - logging!(info, Type::System, "Session ended, system shutting down."); - feat::clean_async().await; - logging!(info, Type::System, "resolved reset finished"); - }); + if let Some(handler) = SHUTDOWN_HANDLER.get() { + tauri::async_runtime::block_on(async { + logging!(info, Type::System, "Session ended, system shutting down."); + handler().await; + logging!(info, Type::System, "resolved reset finished"); + }); + } else { + logging!( + error, + Type::System, + "WM_ENDSESSION received but no shutdown handler is registered" + ); + } } _ => {} }; @@ -81,8 +95,18 @@ fn get_instance_handle() -> windows_sys::Win32::Foundation::HMODULE { unsafe { &__ImageBase as *const _ as _ } } -pub fn register() { - let app_handle = handle::Handle::app_handle(); +pub fn register(app_handle: &AppHandle, f: F) +where + F: Fn() -> Fut + Send + Sync + 'static, + Fut: Future + Send + 'static, +{ + let _ = SHUTDOWN_HANDLER.set(Box::new(move || { + let fut = (f)(); + Box::pin(async move { + fut.await; + }) as Pin + Send>> + })); + let class_name = encode_wide("global_shutdown_app"); unsafe { let hinstance = get_instance_handle(); diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index d5ecc7d26..8ae853de9 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -32,6 +32,14 @@ tauri-build = { version = "2.5.2", features = [] } [dependencies] clash-verge-draft = { workspace = true } clash-verge-logging = { workspace = true } +clash-verge-signal = { workspace = true } +tauri = { workspace = true, features = [ + "protocol-asset", + "devtools", + "tray-icon", + "image-ico", + "image-png", +] } parking_lot = { workspace = true } anyhow = { workspace = true } tokio = { workspace = true } @@ -57,13 +65,6 @@ regex = "1.12.2" sysproxy = { git = "https://github.com/clash-verge-rev/sysproxy-rs", features = [ "guard", ] } -tauri = { version = "2.9.3", features = [ - "protocol-asset", - "devtools", - "tray-icon", - "image-ico", - "image-png", -] } network-interface = { version = "2.0.3", features = ["serde"] } tauri-plugin-shell = "2.3.3" tauri-plugin-dialog = "2.4.2" @@ -115,15 +116,6 @@ winapi = { version = "0.3.9", features = [ "winhttp", "winreg", ] } -windows-sys = { version = "0.61.2", features = [ - "Win32_Foundation", - "Win32_Graphics_Gdi", - "Win32_System_SystemServices", - "Win32_UI_WindowsAndMessaging", -] } - -[target.'cfg(unix)'.dependencies] -signal-hook = "0.3.18" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-autostart = "2.5.1" diff --git a/src-tauri/src/module/mod.rs b/src-tauri/src/module/mod.rs index 87055c6ca..80d2fa30d 100644 --- a/src-tauri/src/module/mod.rs +++ b/src-tauri/src/module/mod.rs @@ -1,4 +1,3 @@ pub mod auto_backup; pub mod lightweight; -pub mod signal; pub mod sysinfo; diff --git a/src-tauri/src/module/signal/mod.rs b/src-tauri/src/module/signal/mod.rs deleted file mode 100644 index 10f3d69cf..000000000 --- a/src-tauri/src/module/signal/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -#[cfg(unix)] -mod unix; -#[cfg(windows)] -mod windows; - -pub fn register() { - #[cfg(windows)] - windows::register(); - - #[cfg(unix)] - unix::register(); -} diff --git a/src-tauri/src/module/signal/unix.rs b/src-tauri/src/module/signal/unix.rs deleted file mode 100644 index fa131991b..000000000 --- a/src-tauri/src/module/signal/unix.rs +++ /dev/null @@ -1,37 +0,0 @@ -use signal_hook::{ - consts::{SIGHUP, SIGINT, SIGTERM}, - iterator::Signals, - low_level, -}; - -use crate::feat; -use clash_verge_logging::{Type, logging, logging_error}; - -pub fn register() { - tauri::async_runtime::spawn(async { - let signals = [SIGTERM, SIGINT, SIGHUP]; - match Signals::new(signals) { - Ok(mut sigs) => { - for signal in &mut sigs { - let signal_to_str = |signal: i32| match signal { - SIGTERM => "SIGTERM", - SIGINT => "SIGINT", - SIGHUP => "SIGHUP", - _ => "UNKNOWN", - }; - logging!(info, Type::System, "捕获到信号 {}", signal_to_str(signal)); - feat::clean_async().await; - // After printing it, do whatever the signal was supposed to do in the first place - logging_error!( - Type::System, - "信号 {:?} 默认处理失败", - low_level::emulate_default_handler(signal) - ); - } - } - Err(e) => { - logging!(error, Type::System, "注册信号处理器失败: {}", e); - } - } - }); -} diff --git a/src-tauri/src/utils/resolve/mod.rs b/src-tauri/src/utils/resolve/mod.rs index df9d26e52..1f03e279b 100644 --- a/src-tauri/src/utils/resolve/mod.rs +++ b/src-tauri/src/utils/resolve/mod.rs @@ -9,11 +9,13 @@ use crate::{ sysopt, tray::Tray, }, - module::{auto_backup::AutoBackupManager, lightweight::auto_lightweight_boot, signal}, + feat, + module::{auto_backup::AutoBackupManager, lightweight::auto_lightweight_boot}, process::AsyncHandler, utils::{init, server, window_manager::WindowManager}, }; use clash_verge_logging::{Type, logging, logging_error}; +use clash_verge_signal; pub mod dns; pub mod scheme; @@ -134,7 +136,11 @@ pub(super) async fn init_auto_backup() { pub(super) fn init_signal() { logging!(info, Type::Setup, "Initializing signal handlers..."); - signal::register(); + clash_verge_signal::register( + #[cfg(windows)] + handle::Handle::app_handle(), + feat::clean_async, + ); } pub async fn init_work_config() {