From 2995f610871c3c9f5de9bd53e2815d0b2a62a92d Mon Sep 17 00:00:00 2001 From: hank Date: Thu, 11 Dec 2025 20:09:27 +0800 Subject: [PATCH] fix: service unexpected status after restart app in unix (#5768) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 修复macos重启应用后需要重设服务器模式问题 * chore: remove package-lock.json (using pnpm) * Delete test.sh * refactor(lifecycle): remove unnecessary conditional compilation for macOS and Windows * refactor(timing): remove conditional compilation for service wait durations on Windows and macOS --------- Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com> --- src-tauri/src/constants.rs | 6 +--- src-tauri/src/core/manager/lifecycle.rs | 42 ++++++++++++++++++++----- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src-tauri/src/constants.rs b/src-tauri/src/constants.rs index 93ef8e872..332491c18 100644 --- a/src-tauri/src/constants.rs +++ b/src-tauri/src/constants.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - pub mod network { pub const DEFAULT_EXTERNAL_CONTROLLER: &str = "127.0.0.1:9097"; @@ -20,16 +18,14 @@ pub mod network { } pub mod timing { - use super::Duration; + use std::time::Duration; pub const CONFIG_UPDATE_DEBOUNCE: Duration = Duration::from_millis(300); pub const EVENT_EMIT_DELAY: Duration = Duration::from_millis(20); pub const STARTUP_ERROR_DELAY: Duration = Duration::from_secs(2); pub const ERROR_BATCH_DELAY: Duration = Duration::from_millis(300); - #[cfg(target_os = "windows")] pub const SERVICE_WAIT_MAX: Duration = Duration::from_millis(3000); - #[cfg(target_os = "windows")] pub const SERVICE_WAIT_INTERVAL: Duration = Duration::from_millis(200); } diff --git a/src-tauri/src/core/manager/lifecycle.rs b/src-tauri/src/core/manager/lifecycle.rs index 0298773a8..97f2d0354 100644 --- a/src-tauri/src/core/manager/lifecycle.rs +++ b/src-tauri/src/core/manager/lifecycle.rs @@ -1,10 +1,12 @@ use super::{CoreManager, RunningMode}; use crate::cmd::StringifyErr as _; use crate::config::{Config, IVerge}; +use crate::constants::timing; use crate::core::handle::Handle; use crate::core::manager::CLASH_LOGGER; use crate::core::service::{SERVICE_MANAGER, ServiceStatus}; use anyhow::Result; +use backoff::{Error as BackoffError, ExponentialBackoff}; use clash_verge_logging::{Type, logging}; use scopeguard::defer; use smartstring::alias::String; @@ -63,7 +65,6 @@ impl CoreManager { } async fn prepare_startup(&self) -> Result<()> { - #[cfg(target_os = "windows")] self.wait_for_service_if_needed().await; let value = SERVICE_MANAGER.lock().await.current(); @@ -81,17 +82,40 @@ impl CoreManager { tauri_plugin_clash_verge_sysinfo::set_app_core_mode(app_handle, self.get_running_mode().to_string()); } - #[cfg(target_os = "windows")] async fn wait_for_service_if_needed(&self) { - use crate::{config::Config, constants::timing}; - use backoff::{Error as BackoffError, ExponentialBackoff}; + #[cfg(target_os = "windows")] + { + let needs_service = Config::verge().await.latest_arc().enable_tun_mode.unwrap_or(false); - let needs_service = Config::verge().await.latest_arc().enable_tun_mode.unwrap_or(false); + if !needs_service { + return; + } + } - if !needs_service { + // 在 unix 上,如果服务状态是 "Need Checks",尝试初始化服务管理器 + // 在 Windows 上,只有在需要 TUN 模式时才等待服务 + let mut manager = SERVICE_MANAGER.lock().await; + let current_status = manager.current(); + + // 如果服务状态是 "Need Checks",尝试初始化服务管理器 + if matches!(current_status, ServiceStatus::Unavailable(ref reason) if reason == "Need Checks") { + // 尝试初始化服务管理器,即使 IPC 路径可能暂时不存在 + if let Err(e) = manager.init().await { + logging!(debug, Type::Core, "服务管理器初始化失败(可能服务未启动): {}", e); + } else { + // 初始化成功,尝试刷新状态 + let _ = manager.refresh().await; + } + } + + // 如果服务已经就绪,直接返回 + if matches!(manager.current(), ServiceStatus::Ready) { return; } + drop(manager); + + // 使用退避重试策略等待服务就绪 let backoff = ExponentialBackoff { initial_interval: timing::SERVICE_WAIT_INTERVAL, max_interval: timing::SERVICE_WAIT_INTERVAL, @@ -108,7 +132,11 @@ impl CoreManager { return Ok(()); } - manager.init().await.map_err(BackoffError::transient)?; + // 如果服务管理器未初始化,尝试初始化 + if matches!(manager.current(), ServiceStatus::Unavailable(ref reason) if reason == "Need Checks") { + manager.init().await.map_err(BackoffError::transient)?; + } + let _ = manager.refresh().await; if matches!(manager.current(), ServiceStatus::Ready) {