mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-09 20:02:20 +08:00
fix: handle proxy cleanup failures during app exit
This commit is contained in:
Generated
+25
-25
@@ -1257,8 +1257,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clash_verge_service_ipc"
|
||||
version = "2.6.2"
|
||||
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc.git?tag=v2.6.2#edf7cb57811d4e572f1e2d607472cb87bd421ef4"
|
||||
version = "2.6.3"
|
||||
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc.git?tag=v2.6.3#322bc6fad12538195aeaeb3711231d7523c88e6f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"compact_str",
|
||||
@@ -1363,7 +1363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2044,7 +2044,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.2",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2324,7 +2324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3397,7 +3397,7 @@ dependencies = [
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.5",
|
||||
"socket2 0.5.10",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
@@ -3417,7 +3417,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.62.2",
|
||||
"windows-core 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4241,7 +4241,7 @@ dependencies = [
|
||||
"png 0.18.1",
|
||||
"serde",
|
||||
"thiserror 2.0.19",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4410,7 +4410,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4830,7 +4830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5504,7 +5504,7 @@ dependencies = [
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2 0.6.5",
|
||||
"socket2 0.5.10",
|
||||
"thiserror 2.0.19",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -5543,9 +5543,9 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2 0.6.5",
|
||||
"socket2 0.5.10",
|
||||
"tracing",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6093,7 +6093,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6106,7 +6106,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6165,7 +6165,7 @@ dependencies = [
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6796,7 +6796,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7009,8 +7009,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysproxy"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/clash-verge-rev/sysproxy-rs?branch=main#16500c3e91a4fa8d541108fb603c5ee4258004a6"
|
||||
version = "0.6.1"
|
||||
source = "git+https://github.com/clash-verge-rev/sysproxy-rs?branch=main#c63788cf88e3deac1087d759c16543235d66b921"
|
||||
dependencies = [
|
||||
"iptools",
|
||||
"log",
|
||||
@@ -7683,10 +7683,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.4.3",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8405,7 +8405,7 @@ dependencies = [
|
||||
"png 0.18.1",
|
||||
"serde",
|
||||
"thiserror 2.0.19",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8508,7 +8508,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"tempfile",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9093,7 +9093,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9697,7 +9697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -96,7 +96,7 @@ tauri-plugin-devtools = { version = "2.1.0" }
|
||||
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo", branch = "refactor-use-reqwest-ipc" }
|
||||
clash_verge_logger = { git = "https://github.com/clash-verge-rev/clash-verge-logger" }
|
||||
async-trait = "0.1.92"
|
||||
clash_verge_service_ipc = { git = "https://github.com/clash-verge-rev/clash-verge-service-ipc.git", tag = "v2.6.2", version = "2.6.2", features = [
|
||||
clash_verge_service_ipc = { git = "https://github.com/clash-verge-rev/clash-verge-service-ipc.git", tag = "v2.6.3", version = "2.6.3", features = [
|
||||
"client",
|
||||
] }
|
||||
arc-swap = "1.9.2"
|
||||
|
||||
@@ -170,12 +170,25 @@ where
|
||||
first_failure([("global proxy", global), ("PAC", pac)])
|
||||
}
|
||||
|
||||
/// Treats a missing network service as a completed disable: with nothing to write to, the
|
||||
/// requested "no proxy" state already holds. Turning a proxy on must still fail.
|
||||
fn tolerate_missing_network_service(enabling: bool, outcome: sysproxy::Result<()>) -> Result<()> {
|
||||
match outcome {
|
||||
#[cfg(target_os = "macos")]
|
||||
Err(sysproxy::Error::NoActiveNetworkService) if !enabling => {
|
||||
logging!(warn, Type::Core, "no active network service, nothing to turn off");
|
||||
Ok(())
|
||||
}
|
||||
other => other.map_err(anyhow::Error::from),
|
||||
}
|
||||
}
|
||||
|
||||
/// Force both proxy kinds off, in one blocking hop.
|
||||
async fn disable_all_proxies(sys: Sysproxy, auto: Autoproxy) -> Result<()> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
disable_both(
|
||||
|| sys.set_system_proxy().map_err(anyhow::Error::from),
|
||||
|| auto.set_auto_proxy().map_err(anyhow::Error::from),
|
||||
|| tolerate_missing_network_service(sys.enable, sys.set_system_proxy()),
|
||||
|| tolerate_missing_network_service(auto.enable, auto.set_auto_proxy()),
|
||||
)
|
||||
})
|
||||
.await?
|
||||
@@ -472,11 +485,11 @@ impl Sysopt {
|
||||
let applied = tokio::task::spawn_blocking(move || {
|
||||
for (index, step) in apply_steps.into_iter().enumerate() {
|
||||
let written = match step {
|
||||
ProxyApplyStep::Autoproxy => auto.set_auto_proxy(),
|
||||
ProxyApplyStep::Sysproxy => sys.set_system_proxy(),
|
||||
ProxyApplyStep::Autoproxy => tolerate_missing_network_service(auto.enable, auto.set_auto_proxy()),
|
||||
ProxyApplyStep::Sysproxy => tolerate_missing_network_service(sys.enable, sys.set_system_proxy()),
|
||||
};
|
||||
if let Err(error) = written {
|
||||
return Err((index > 0, anyhow::Error::from(error)));
|
||||
return Err((index > 0, error));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -54,7 +54,10 @@ pub async fn restart_app() {
|
||||
|
||||
if !cleanup_result.core_stopped {
|
||||
handle::Handle::global().clear_is_exiting();
|
||||
handle::Handle::notice_message("app_restart::core_stop_failed", "");
|
||||
handle::Handle::notice_message(
|
||||
"app_restart::core_stop_failed",
|
||||
cleanup_result.stop_error.unwrap_or_default(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,17 @@ use crate::module::lightweight;
|
||||
use crate::utils;
|
||||
use crate::utils::window_manager::WindowManager;
|
||||
use clash_verge_logging::{Type, logging};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::time::Duration;
|
||||
#[cfg(target_os = "macos")]
|
||||
use tokio::time::timeout;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct CleanupResult {
|
||||
pub all_success: bool,
|
||||
pub core_stopped: bool,
|
||||
/// Why the stop failed, for the cancelled-exit notice.
|
||||
pub stop_error: Option<String>,
|
||||
}
|
||||
|
||||
const fn should_abort_exit_after_cleanup(core_stopped: bool) -> bool {
|
||||
@@ -29,14 +32,12 @@ where
|
||||
AncillaryFuture: std::future::Future<Output = bool>,
|
||||
{
|
||||
if !stop_core().await {
|
||||
return CleanupResult {
|
||||
all_success: false,
|
||||
core_stopped: false,
|
||||
};
|
||||
return CleanupResult::default();
|
||||
}
|
||||
CleanupResult {
|
||||
all_success: ancillary_cleanup().await,
|
||||
core_stopped: true,
|
||||
stop_error: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +129,10 @@ pub async fn quit() -> clash_verge_signal::ShutdownOutcome {
|
||||
|
||||
if should_abort_exit_after_cleanup(cleanup_result.core_stopped) {
|
||||
handle::Handle::global().clear_is_exiting();
|
||||
handle::Handle::notice_message("app_quit::core_stop_failed", "");
|
||||
handle::Handle::notice_message(
|
||||
"app_quit::core_stop_failed",
|
||||
cleanup_result.stop_error.unwrap_or_default(),
|
||||
);
|
||||
return clash_verge_signal::ShutdownOutcome::Canceled;
|
||||
}
|
||||
|
||||
@@ -145,7 +149,8 @@ pub async fn clean_async() -> CleanupResult {
|
||||
"Starting interactive cleanup; controlled core stop will be awaited to completion"
|
||||
);
|
||||
|
||||
let result = run_interactive_cleanup_transition(
|
||||
let stop_error = Mutex::new(None);
|
||||
let mut result = run_interactive_cleanup_transition(
|
||||
|| async {
|
||||
logging!(info, Type::System, "Stopping core for interactive quit or restart");
|
||||
match CoreManager::global().stop_core().await {
|
||||
@@ -159,6 +164,7 @@ pub async fn clean_async() -> CleanupResult {
|
||||
Type::Window,
|
||||
"Controlled core stop failed; interactive quit or restart must remain cancelled: {error:#}"
|
||||
);
|
||||
*stop_error.lock() = Some(format!("{error:#}"));
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -166,6 +172,7 @@ pub async fn clean_async() -> CleanupResult {
|
||||
restore_dns_after_core_stop,
|
||||
)
|
||||
.await;
|
||||
result.stop_error = stop_error.into_inner();
|
||||
|
||||
logging!(
|
||||
info,
|
||||
|
||||
@@ -33,9 +33,15 @@ export const handleNoticeMessage = (
|
||||
'settings.sections.system.notifications.tunMode.autoDisableFailed',
|
||||
),
|
||||
'app_restart::core_stop_failed': () =>
|
||||
showNotice.error('layout.feedback.errors.restartCoreStopFailed'),
|
||||
showNotice.error(
|
||||
'layout.feedback.errors.restartCoreStopFailed',
|
||||
msg || undefined,
|
||||
),
|
||||
'app_quit::core_stop_failed': () =>
|
||||
showNotice.error('layout.feedback.errors.quitCoreStopFailed'),
|
||||
showNotice.error(
|
||||
'layout.feedback.errors.quitCoreStopFailed',
|
||||
msg || undefined,
|
||||
),
|
||||
update_with_clash_proxy: () =>
|
||||
showNotice.success(
|
||||
'settings.feedback.notifications.updater.withClashProxySuccess',
|
||||
|
||||
Reference in New Issue
Block a user