diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index 7606a721a..94e6ba048 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -46,14 +46,10 @@ pub struct CoreManager { last_update: Arc>>, } -/// 内核运行模式 -#[derive(Debug, Clone, serde::Serialize, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, serde::Serialize, PartialEq, Eq)] pub enum RunningMode { - /// 服务模式运行 Service, - /// Sidecar 模式运行 Sidecar, - /// 未运行 NotRunning, } @@ -69,12 +65,16 @@ impl fmt::Display for RunningMode { use crate::config::IVerge; +const CONNECTION_ERROR_PATTERNS: &[&str] = &[ + "Failed to create connection", + "The system cannot find the file specified", + "operation timed out", + "connection refused", +]; + impl CoreManager { - /// 使用默认配置 pub async fn use_default_config(&self, msg_type: &str, msg_content: &str) -> Result<()> { let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG); - - // Extract clash config before async operations let clash_config = Config::clash().await.latest_ref().0.clone(); *Config::runtime().await.draft_mut() = Box::new(IRuntime { @@ -215,115 +215,85 @@ impl CoreManager { } fn should_restart_on_reload_error(err: &MihomoError) -> bool { - match err { - MihomoError::ConnectionFailed | MihomoError::ConnectionLost => true, - MihomoError::Io(io_err) => matches!( - io_err.kind(), + fn is_connection_io_error(kind: std::io::ErrorKind) -> bool { + matches!( + kind, std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::NotFound - ), + ) + } + + fn contains_error_pattern(text: &str) -> bool { + CONNECTION_ERROR_PATTERNS.iter().any(|p| text.contains(p)) + } + + match err { + MihomoError::ConnectionFailed | MihomoError::ConnectionLost => true, + MihomoError::Io(io_err) => is_connection_io_error(io_err.kind()), MihomoError::Reqwest(req_err) => { if req_err.is_connect() || req_err.is_timeout() { return true; } - let err_text = req_err.to_string(); if let Some(source) = req_err.source() { if let Some(io_err) = source.downcast_ref::() { - if matches!( - io_err.kind(), - std::io::ErrorKind::ConnectionAborted - | std::io::ErrorKind::ConnectionRefused - | std::io::ErrorKind::ConnectionReset - | std::io::ErrorKind::NotFound - ) { + if is_connection_io_error(io_err.kind()) { return true; } - } else if source.to_string().contains("Failed to create connection") { + } else if contains_error_pattern(&source.to_string()) { return true; } } - err_text.contains("Failed to create connection") - || err_text.contains("The system cannot find the file specified") - || err_text.contains("operation timed out") - || err_text.contains("connection refused") - } - MihomoError::FailedResponse(msg) => { - msg.contains("Failed to create connection") || msg.contains("connection refused") + contains_error_pattern(&req_err.to_string()) } + MihomoError::FailedResponse(msg) => contains_error_pattern(msg), _ => false, } } } impl CoreManager { - /// 清理多余的 mihomo 进程 async fn cleanup_orphaned_mihomo_processes(&self) -> Result<()> { logging!(info, Type::Core, "开始清理多余的 mihomo 进程"); - // 获取当前管理的进程 PID - let current_pid = { - let child_guard = self.child_sidecar.lock(); - child_guard.as_ref().map(|child| child.pid()) - }; - + let current_pid = self.child_sidecar.lock().as_ref().and_then(|child| child.pid()); let target_processes = ["verge-mihomo", "verge-mihomo-alpha"]; - // 并行查找所有目标进程 - let mut process_futures = Vec::new(); - for &target in &target_processes { + let process_futures = target_processes.iter().map(|&target| { let process_name = if cfg!(windows) { format!("{target}.exe") } else { - target.into() + target.to_string() }; - process_futures.push(self.find_processes_by_name(process_name, target)); - } + self.find_processes_by_name(process_name, target) + }); let process_results = futures::future::join_all(process_futures).await; - // 收集所有需要终止的进程PID - let mut pids_to_kill = Vec::new(); - for result in process_results { - match result { - Ok((pids, process_name)) => { - for pid in pids { - // 跳过当前管理的进程 - if let Some(current) = current_pid - && Some(pid) == current - { - logging!( - debug, - Type::Core, - "跳过当前管理的进程: {} (PID: {})", - process_name, - pid - ); - continue; - } - pids_to_kill.push((pid, process_name.clone())); - } - } - Err(e) => { - logging!(debug, Type::Core, "查找进程时发生错误: {}", e); - } - } - } + let pids_to_kill: Vec<_> = process_results + .into_iter() + .filter_map(|result| result.ok()) + .flat_map(|(pids, process_name)| { + pids.into_iter() + .filter(|&pid| Some(pid) != current_pid) + .map(move |pid| (pid, process_name.clone())) + }) + .collect(); if pids_to_kill.is_empty() { logging!(debug, Type::Core, "未发现多余的 mihomo 进程"); return Ok(()); } - let mut kill_futures = Vec::new(); - for (pid, process_name) in &pids_to_kill { - kill_futures.push(self.kill_process_with_verification(*pid, process_name.clone())); - } + let kill_futures = pids_to_kill.iter() + .map(|(pid, name)| self.kill_process_with_verification(*pid, name.clone())); - let kill_results = futures::future::join_all(kill_futures).await; - - let killed_count = kill_results.into_iter().filter(|&success| success).count(); + let killed_count = futures::future::join_all(kill_futures) + .await + .into_iter() + .filter(|&success| success) + .count(); if killed_count > 0 { logging!( @@ -355,10 +325,9 @@ impl CoreManager { let process_name_clone = process_name.clone(); let pids = AsyncHandler::spawn_blocking(move || -> Result> { - let mut pids = Vec::new(); + let mut pids = Vec::with_capacity(8); unsafe { - // 创建进程快照 let snapshot: HANDLE = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if snapshot == winapi::um::handleapi::INVALID_HANDLE_VALUE { return Err(anyhow::anyhow!("Failed to create process snapshot")); @@ -367,28 +336,24 @@ impl CoreManager { let mut pe32: PROCESSENTRY32W = mem::zeroed(); pe32.dwSize = mem::size_of::() as u32; - // 获取第一个进程 if Process32FirstW(snapshot, &mut pe32) != 0 { loop { - // 将宽字符转换为String - let end_pos = pe32 - .szExeFile - .iter() - .position(|&x| x == 0) + let end_pos = pe32.szExeFile.iter().position(|&x| x == 0) .unwrap_or(pe32.szExeFile.len()); - let exe_file = String::from_utf16_lossy(&pe32.szExeFile[..end_pos]); - - // 检查进程名是否匹配 - if exe_file.eq_ignore_ascii_case(&process_name_clone) { - pids.push(pe32.th32ProcessID); + + if end_pos > 0 { + let exe_file = String::from_utf16_lossy(&pe32.szExeFile[..end_pos]); + if exe_file.eq_ignore_ascii_case(&process_name_clone) { + pids.push(pe32.th32ProcessID); + } } + if Process32NextW(snapshot, &mut pe32) == 0 { break; } } } - // 关闭句柄 CloseHandle(snapshot); } @@ -407,7 +372,6 @@ impl CoreManager { .output() .await? } else { - // Linux tokio::process::Command::new("pidof") .arg(&process_name) .output() @@ -419,28 +383,17 @@ impl CoreManager { } let stdout = String::from_utf8_lossy(&output.stdout); - let mut pids = Vec::new(); - - // Unix系统直接解析PID列表 - for pid_str in stdout.split_whitespace() { - if let Ok(pid) = pid_str.parse::() { - pids.push(pid); - } - } + let pids: Vec = stdout + .split_whitespace() + .filter_map(|s| s.parse().ok()) + .collect(); Ok((pids, process_name)) } } - /// 终止进程并验证结果 - 使用Windows API直接终止,更优雅高效 async fn kill_process_with_verification(&self, pid: u32, process_name: String) -> bool { - logging!( - info, - Type::Core, - "尝试终止进程: {} (PID: {})", - process_name, - pid - ); + logging!(info, Type::Core, "尝试终止进程: {} (PID: {})", process_name, pid); #[cfg(windows)] let success = { @@ -448,93 +401,60 @@ impl CoreManager { use winapi::um::processthreadsapi::{OpenProcess, TerminateProcess}; use winapi::um::winnt::{HANDLE, PROCESS_TERMINATE}; - AsyncHandler::spawn_blocking(move || -> bool { - unsafe { - let process_handle: HANDLE = OpenProcess(PROCESS_TERMINATE, 0, pid); - if process_handle.is_null() { - return false; - } - let result = TerminateProcess(process_handle, 1); - CloseHandle(process_handle); - - result != 0 + AsyncHandler::spawn_blocking(move || unsafe { + let handle: HANDLE = OpenProcess(PROCESS_TERMINATE, 0, pid); + if handle.is_null() { + return false; } + let result = TerminateProcess(handle, 1) != 0; + CloseHandle(handle); + result }) .await .unwrap_or(false) }; #[cfg(not(windows))] - let success = { - tokio::process::Command::new("kill") - .args(["-9", &pid.to_string()]) - .output() - .await - .map(|output| output.status.success()) - .unwrap_or(false) - }; + let success = tokio::process::Command::new("kill") + .args(["-9", &pid.to_string()]) + .output() + .await + .map(|output| output.status.success()) + .unwrap_or(false); - if success { - // 短暂等待并验证进程是否真正终止 - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + if !success { + logging!(warn, Type::Core, "无法终止进程: {} (PID: {})", process_name, pid); + return false; + } - let still_running = self.is_process_running(pid).await.unwrap_or(false); - if still_running { - logging!( - warn, - Type::Core, - "进程 {} (PID: {}) 终止命令成功但进程仍在运行", - process_name, - pid - ); - false - } else { - logging!( - info, - Type::Core, - "成功终止进程: {} (PID: {})", - process_name, - pid - ); - true - } - } else { - logging!( - warn, - Type::Core, - "无法终止进程: {} (PID: {})", - process_name, - pid - ); + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + if self.is_process_running(pid).await.unwrap_or(false) { + logging!(warn, Type::Core, "进程 {} (PID: {}) 终止命令成功但进程仍在运行", process_name, pid); false + } else { + logging!(info, Type::Core, "成功终止进程: {} (PID: {})", process_name, pid); + true } } - /// Windows API检查进程 async fn is_process_running(&self, pid: u32) -> Result { #[cfg(windows)] { use winapi::shared::minwindef::DWORD; use winapi::um::handleapi::CloseHandle; - use winapi::um::processthreadsapi::GetExitCodeProcess; - use winapi::um::processthreadsapi::OpenProcess; + use winapi::um::processthreadsapi::{GetExitCodeProcess, OpenProcess}; use winapi::um::winnt::{HANDLE, PROCESS_QUERY_INFORMATION}; - AsyncHandler::spawn_blocking(move || -> Result { - unsafe { - let process_handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid); - if process_handle.is_null() { - return Ok(false); - } - let mut exit_code: DWORD = 0; - let result = GetExitCodeProcess(process_handle, &mut exit_code); - CloseHandle(process_handle); - - if result == 0 { - return Ok(false); - } - Ok(exit_code == 259) + AsyncHandler::spawn_blocking(move || unsafe { + let handle: HANDLE = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid); + if handle.is_null() { + return Ok(false); } + let mut exit_code: DWORD = 0; + let result = GetExitCodeProcess(handle, &mut exit_code); + CloseHandle(handle); + Ok(result != 0 && exit_code == 259) }) .await? } @@ -580,18 +500,10 @@ impl CoreManager { AsyncHandler::spawn(|| async move { while let Some(event) = rx.recv().await { match event { - tauri_plugin_shell::process::CommandEvent::Stdout(line) => { + tauri_plugin_shell::process::CommandEvent::Stdout(line) + | tauri_plugin_shell::process::CommandEvent::Stderr(line) => { let mut now = DeferredNow::default(); - let message = - CompactString::from(String::from_utf8_lossy(&line).into_owned()); - let w = shared_writer.lock().await; - write_sidecar_log(w, &mut now, Level::Error, &message); - ClashLogger::global().append_log(message); - } - tauri_plugin_shell::process::CommandEvent::Stderr(line) => { - let mut now = DeferredNow::default(); - let message = - CompactString::from(String::from_utf8_lossy(&line).into_owned()); + let message = CompactString::from(String::from_utf8_lossy(&line).as_ref()); let w = shared_writer.lock().await; write_sidecar_log(w, &mut now, Level::Error, &message); ClashLogger::global().append_log(message); @@ -660,22 +572,13 @@ impl Default for CoreManager { impl CoreManager { pub async fn init(&self) -> Result<()> { - logging!(info, Type::Core, "Initializing core"); + logging!(info, Type::Core, "开始核心初始化"); - // 应用启动时先清理任何遗留的 mihomo 进程 if let Err(e) = self.cleanup_orphaned_mihomo_processes().await { - logging!( - warn, - Type::Core, - "应用初始化时清理多余 mihomo 进程失败: {}", - e - ); + logging!(warn, Type::Core, "清理遗留 mihomo 进程失败: {}", e); } - // 使用简化的启动流程 - logging!(info, Type::Core, "开始核心初始化"); self.start_core().await?; - logging!(info, Type::Core, "核心初始化完成"); Ok(()) } @@ -686,8 +589,7 @@ impl CoreManager { } pub fn get_running_mode(&self) -> RunningMode { - let guard = self.running.lock(); - (*guard).clone() + *self.running.lock() } #[cfg(target_os = "windows")] diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e5891e1fc..3ddc75ef9 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -84,7 +84,7 @@ mod app_init { app.deep_link().on_open_url(|event| { let url = event.urls().first().map(|u| u.to_string()); if let Some(url) = url { - AsyncHandler::spawn(|| async { + let _ = AsyncHandler::spawn(|| async { if let Err(e) = resolve::resolve_scheme(url).await { logging!(error, Type::Setup, "Failed to resolve scheme: {}", e); } @@ -123,11 +123,9 @@ mod app_init { Ok(()) } - /// Generate all command handlers for the application pub fn generate_handlers() -> impl Fn(tauri::ipc::Invoke) -> bool + Send + Sync + 'static { tauri::generate_handler![ - // Common commands cmd::get_sys_proxy, cmd::get_auto_proxy, cmd::open_app_dir, @@ -138,27 +136,22 @@ mod app_init { cmd::get_network_interfaces, cmd::get_system_hostname, cmd::restart_app, - // Core management cmd::start_core, cmd::stop_core, cmd::restart_core, - // Application lifecycle cmd::notify_ui_ready, cmd::update_ui_stage, cmd::get_running_mode, cmd::get_app_uptime, cmd::get_auto_launch_status, cmd::is_admin, - // Lightweight mode cmd::entry_lightweight_mode, cmd::exit_lightweight_mode, - // Service management cmd::install_service, cmd::uninstall_service, cmd::reinstall_service, cmd::repair_service, cmd::is_service_available, - // Clash core commands cmd::get_clash_info, cmd::patch_clash_config, cmd::patch_clash_mode, @@ -178,7 +171,6 @@ mod app_init { cmd::get_dns_config_content, cmd::validate_dns_config, cmd::get_clash_logs, - // Verge configuration cmd::get_verge_config, cmd::patch_verge_config, cmd::test_delay, @@ -188,7 +180,6 @@ mod app_init { cmd::open_devtools, cmd::exit_app, cmd::get_network_interfaces_info, - // Profile management cmd::get_profiles, cmd::enhance_profiles, cmd::patch_profiles_config, @@ -202,10 +193,8 @@ mod app_init { cmd::read_profile_file, cmd::save_profile_file, cmd::get_next_update_time, - // Script validation cmd::script_validate_notice, cmd::validate_script_file, - // Backup and WebDAV cmd::create_local_backup, cmd::list_local_backup, cmd::delete_local_backup, @@ -216,10 +205,8 @@ mod app_init { cmd::list_webdav_backup, cmd::delete_webdav_backup, cmd::restore_webdav_backup, - // Diagnostics and system info cmd::export_diagnostic_info, cmd::get_system_info, - // Media unlock checker cmd::get_unlock_items, cmd::check_media_unlock, ] @@ -227,18 +214,15 @@ mod app_init { } pub fn run() { - // Setup singleton check if app_init::init_singleton_check().is_err() { return; } let _ = utils::dirs::init_portable_flag(); - // Set Linux environment variable #[cfg(target_os = "linux")] linux::configure_environment(); - // Create and configure the Tauri builder let builder = app_init::setup_plugins(tauri::Builder::default()) .setup(|app| { logging!(info, Type::Setup, "开始应用初始化..."); @@ -248,89 +232,56 @@ pub fn run() { .set(app.app_handle().clone()) .expect("failed to set global app handle"); - // Setup autostart plugin if let Err(e) = app_init::setup_autostart(app) { logging!(error, Type::Setup, "Failed to setup autostart: {}", e); } - // Setup deep links if let Err(e) = app_init::setup_deep_links(app) { logging!(error, Type::Setup, "Failed to setup deep links: {}", e); } - // Setup window state management if let Err(e) = app_init::setup_window_state(app) { logging!(error, Type::Setup, "Failed to setup window state: {}", e); } - logging!(info, Type::Setup, "执行主要设置操作..."); - resolve::resolve_setup_handle(); - // 异步任务启动,不等待完成 resolve::resolve_setup_async(); resolve::resolve_setup_sync(); - logging!(info, Type::Setup, "初始化已启动,继续执行"); + logging!(info, Type::Setup, "初始化已启动"); Ok(()) }) .invoke_handler(app_init::generate_handlers()); - /// Event handling helper functions mod event_handlers { use crate::core::handle; - use super::*; - /// Handle application ready/resumed events pub fn handle_ready_resumed(_app_handle: &AppHandle) { - // 双重检查:确保不在退出状态 if handle::Handle::global().is_exiting() { - logging!( - debug, - Type::System, - "handle_ready_resumed: 应用正在退出,跳过处理" - ); + logging!(debug, Type::System, "应用正在退出,跳过处理"); return; } - logging!(info, Type::System, "应用就绪或恢复"); + logging!(info, Type::System, "应用就绪"); handle::Handle::global().init(); #[cfg(target_os = "macos")] - { - if let Some(window) = _app_handle.get_webview_window("main") { - logging!(info, Type::Window, "设置macOS窗口标题"); - let _ = window.set_title("Clash Verge"); - } + if let Some(window) = _app_handle.get_webview_window("main") { + let _ = window.set_title("Clash Verge"); } } - /// Handle application reopen events (macOS) #[cfg(target_os = "macos")] pub async fn handle_reopen(has_visible_windows: bool) { - logging!( - info, - Type::System, - "处理 macOS 应用重新打开事件: has_visible_windows={}", - has_visible_windows - ); - handle::Handle::global().init(); if !has_visible_windows { - // 当没有可见窗口时,设置为 regular 模式并显示主窗口 handle::Handle::global().set_activation_policy_regular(); - - logging!(info, Type::System, "没有可见窗口,尝试显示主窗口"); - - let result = WindowManager::show_main_window().await; - logging!(info, Type::System, "窗口显示操作完成,结果: {:?}", result); - } else { - logging!(info, Type::System, "已有可见窗口,无需额外操作"); + let _ = WindowManager::show_main_window().await; } } - /// Handle window close requests pub fn handle_window_close(api: &tauri::WindowEvent) { #[cfg(target_os = "macos")] handle::Handle::global().set_activation_policy_accessory(); @@ -339,20 +290,16 @@ pub fn run() { return; } - log::info!(target: "app", "closing window..."); if let tauri::WindowEvent::CloseRequested { api, .. } = api { api.prevent_close(); if let Some(window) = core::handle::Handle::get_window() { let _ = window.hide(); - } else { - logging!(warn, Type::Window, "尝试隐藏窗口但窗口不存在"); } } } - /// Handle window focus events pub fn handle_window_focus(focused: bool) { - AsyncHandler::spawn(move || async move { + let _ = AsyncHandler::spawn(move || async move { let is_enable_global_hotkey = Config::verge() .await .latest_ref() @@ -363,197 +310,110 @@ pub fn run() { #[cfg(target_os = "macos")] { use crate::core::hotkey::SystemHotkey; - if let Err(e) = hotkey::Hotkey::global() - .register_system_hotkey(SystemHotkey::CmdQ) - .await - { - logging!(error, Type::Hotkey, "Failed to register CMD+Q: {}", e); - } - if let Err(e) = hotkey::Hotkey::global() - .register_system_hotkey(SystemHotkey::CmdW) - .await - { - logging!(error, Type::Hotkey, "Failed to register CMD+W: {}", e); - } + let _ = hotkey::Hotkey::global().register_system_hotkey(SystemHotkey::CmdQ).await; + let _ = hotkey::Hotkey::global().register_system_hotkey(SystemHotkey::CmdW).await; } - if !is_enable_global_hotkey - && let Err(e) = hotkey::Hotkey::global().init().await - { - logging!(error, Type::Hotkey, "Failed to init hotkeys: {}", e); + if !is_enable_global_hotkey { + let _ = hotkey::Hotkey::global().init().await; } return; } - // Handle unfocused state #[cfg(target_os = "macos")] { use crate::core::hotkey::SystemHotkey; - if let Err(e) = - hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdQ) - { - logging!(error, Type::Hotkey, "Failed to unregister CMD+Q: {}", e); - } - if let Err(e) = - hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdW) - { - logging!(error, Type::Hotkey, "Failed to unregister CMD+W: {}", e); - } + let _ = hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdQ); + let _ = hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdW); } - if !is_enable_global_hotkey && let Err(e) = hotkey::Hotkey::global().reset() { - logging!(error, Type::Hotkey, "Failed to reset hotkeys: {}", e); + if !is_enable_global_hotkey { + let _ = hotkey::Hotkey::global().reset(); } }); } - /// Handle window destroyed events pub fn handle_window_destroyed() { - AsyncHandler::spawn(|| async { - if let Err(e) = handle::Handle::mihomo() + let _ = AsyncHandler::spawn(|| async { + let _ = handle::Handle::mihomo() .await .clear_all_ws_connections() - .await - { - logging!(warn, Type::Window, "清理 WebSocket 连接失败: {}", e); - } else { - logging!(info, Type::Window, "WebSocket 连接已清理"); - } + .await; }); #[cfg(target_os = "macos")] { use crate::core::hotkey::SystemHotkey; - if let Err(e) = - hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdQ) - { - logging!( - error, - Type::Hotkey, - "Failed to unregister CMD+Q on destroy: {}", - e - ); - } - if let Err(e) = - hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdW) - { - logging!( - error, - Type::Hotkey, - "Failed to unregister CMD+W on destroy: {}", - e - ); - } + let _ = hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdQ); + let _ = hotkey::Hotkey::global().unregister_system_hotkey(SystemHotkey::CmdW); } } } - // Mock context for Clippy to avoid build errors #[cfg(feature = "clippy")] let context = tauri::test::mock_context(tauri::test::noop_assets()); #[cfg(feature = "clippy")] let app = builder.build(context).unwrap_or_else(|e| { - logging!( - error, - Type::Setup, - "Failed to build Tauri application: {}", - e - ); + logging!(error, Type::Setup, "Failed to build Tauri application: {}", e); std::process::exit(1); }); - // Build the application #[cfg(not(feature = "clippy"))] - let app = builder - .build(tauri::generate_context!()) - .unwrap_or_else(|e| { - logging!( - error, - Type::Setup, - "Failed to build Tauri application: {}", - e - ); - std::process::exit(1); - }); + let app = builder.build(tauri::generate_context!()).unwrap_or_else(|e| { + logging!(error, Type::Setup, "Failed to build Tauri application: {}", e); + std::process::exit(1); + }); app.run(|app_handle, e| { match e { tauri::RunEvent::Ready | tauri::RunEvent::Resumed => { - // 如果正在退出,忽略 Ready/Resumed 事件 if core::handle::Handle::global().is_exiting() { - logging!(debug, Type::System, "忽略 Ready/Resumed 事件,应用正在退出"); return; } event_handlers::handle_ready_resumed(app_handle); } #[cfg(target_os = "macos")] - tauri::RunEvent::Reopen { - has_visible_windows, - .. - } => { - // 如果正在退出,忽略 Reopen 事件 + tauri::RunEvent::Reopen { has_visible_windows, .. } => { if core::handle::Handle::global().is_exiting() { - logging!(debug, Type::System, "忽略 Reopen 事件,应用正在退出"); return; } - AsyncHandler::spawn(move || async move { + let _ = AsyncHandler::spawn(move || async move { event_handlers::handle_reopen(has_visible_windows).await; }); } tauri::RunEvent::ExitRequested { api, code, .. } => { tauri::async_runtime::block_on(async { - let _ = handle::Handle::mihomo() - .await - .clear_all_ws_connections() - .await; + let _ = handle::Handle::mihomo().await.clear_all_ws_connections().await; }); - // 如果已经在退出流程中,不要阻止退出 + if core::handle::Handle::global().is_exiting() { - logging!( - info, - Type::System, - "应用正在退出,允许 ExitRequested (code: {:?})", - code - ); return; } - // 只阻止外部的无退出码请求(如用户取消系统关机) if code.is_none() { - logging!(debug, Type::System, "阻止外部退出请求"); api.prevent_exit(); } } tauri::RunEvent::Exit => { let handle = core::handle::Handle::global(); - - if handle.is_exiting() { - logging!( - debug, - Type::System, - "Exit事件触发,但退出流程已执行,跳过重复清理" - ); - } else { - logging!(debug, Type::System, "Exit事件触发,执行清理流程"); + if !handle.is_exiting() { handle.set_is_exiting(); EventDrivenProxyManager::global().notify_app_stopping(); feat::clean(); } } - tauri::RunEvent::WindowEvent { label, event, .. } => { - if label == "main" { - match event { - tauri::WindowEvent::CloseRequested { .. } => { - event_handlers::handle_window_close(&event); - } - tauri::WindowEvent::Focused(focused) => { - event_handlers::handle_window_focus(focused); - } - tauri::WindowEvent::Destroyed => { - event_handlers::handle_window_destroyed(); - } - _ => {} + tauri::RunEvent::WindowEvent { label, event, .. } if label == "main" => { + match event { + tauri::WindowEvent::CloseRequested { .. } => { + event_handlers::handle_window_close(&event); } + tauri::WindowEvent::Focused(focused) => { + event_handlers::handle_window_focus(focused); + } + tauri::WindowEvent::Destroyed => { + event_handlers::handle_window_destroyed(); + } + _ => {} } } _ => {} diff --git a/src-tauri/src/utils/resolve/mod.rs b/src-tauri/src/utils/resolve/mod.rs index 3a062aab2..22ee681a2 100644 --- a/src-tauri/src/utils/resolve/mod.rs +++ b/src-tauri/src/utils/resolve/mod.rs @@ -26,91 +26,54 @@ pub fn resolve_setup_handle() { } pub fn resolve_setup_sync() { - AsyncHandler::spawn(|| async { - AsyncHandler::spawn_blocking(init_scheme); - AsyncHandler::spawn_blocking(init_embed_server); + let _ = AsyncHandler::spawn(|| async { + let _ = AsyncHandler::spawn_blocking(init_scheme); + let _ = AsyncHandler::spawn_blocking(init_embed_server); }); } pub fn resolve_setup_async() { - let start_time = std::time::Instant::now(); - logging!( - info, - Type::Setup, - "开始执行异步设置任务... 线程ID: {:?}", - std::thread::current().id() - ); - - AsyncHandler::spawn(|| async { + let _ = AsyncHandler::spawn(|| async { #[cfg(not(feature = "tauri-dev"))] resolve_setup_logger().await; - logging!( - info, - Type::ClashVergeRev, - "Version: {}", - env!("CARGO_PKG_VERSION") - ); + logging!(info, Type::ClashVergeRev, "Version: {}", env!("CARGO_PKG_VERSION")); - futures::join!(init_work_config(), init_resources(), init_startup_script(),); + futures::join!(init_work_config(), init_resources(), init_startup_script()); init_verge_config().await; - Config::verify_config_initialization().await; - - // 优先创建窗口,提升启动体验 init_window().await; - // 后台异步初始化核心,不阻塞窗口显示 let core_init = AsyncHandler::spawn(|| async { init_service_manager().await; init_core_manager().await; init_system_proxy().await; - AsyncHandler::spawn_blocking(|| { - init_system_proxy_guard(); - }); + let _ = AsyncHandler::spawn_blocking(init_system_proxy_guard); }); - let tray_and_refresh = async { + let tray_init = async { init_tray().await; refresh_tray_menu().await; }; - futures::join!( + let _ = futures::join!( core_init, - tray_and_refresh, + tray_init, init_timer(), init_hotkey(), init_auto_lightweight_mode(), init_once_auto_lightweight(), ); }); - - let elapsed = start_time.elapsed(); - logging!( - info, - Type::Setup, - "异步设置任务启动完成,耗时: {:?}", - elapsed - ); - - if elapsed.as_secs() > 10 { - logging!(warn, Type::Setup, "异步设置任务耗时较长({:?})", elapsed); - } } -// 其它辅助函数不变 pub async fn resolve_reset_async() -> Result<(), anyhow::Error> { - logging!(info, Type::Tray, "Resetting system proxy"); sysopt::Sysopt::global().reset_sysproxy().await?; - - logging!(info, Type::Core, "Stopping core service"); CoreManager::global().stop_core().await?; #[cfg(target_os = "macos")] { use dns::restore_public_dns; - - logging!(info, Type::System, "Restoring system DNS settings"); restore_public_dns().await; } @@ -118,95 +81,69 @@ pub async fn resolve_reset_async() -> Result<(), anyhow::Error> { } pub fn init_handle() { - logging!(info, Type::Setup, "Initializing app handle..."); handle::Handle::global().init(); } pub(super) fn init_scheme() { - logging!(info, Type::Setup, "Initializing custom URL scheme"); logging_error!(Type::Setup, init::init_scheme()); } #[cfg(not(feature = "tauri-dev"))] pub(super) async fn resolve_setup_logger() { - logging!(info, Type::Setup, "Initializing global logger..."); logging_error!(Type::Setup, init::init_logger().await); } pub async fn resolve_scheme(param: String) -> Result<()> { - logging!(info, Type::Setup, "Resolving scheme for param: {}", param); logging_error!(Type::Setup, scheme::resolve_scheme(param).await); Ok(()) } pub(super) fn init_embed_server() { - logging!(info, Type::Setup, "Initializing embedded server..."); server::embed_server(); } + pub(super) async fn init_resources() { - logging!(info, Type::Setup, "Initializing resources..."); logging_error!(Type::Setup, init::init_resources().await); } pub(super) async fn init_startup_script() { - logging!(info, Type::Setup, "Initializing startup script"); logging_error!(Type::Setup, init::startup_script().await); } pub(super) async fn init_timer() { - logging!(info, Type::Setup, "Initializing timer..."); logging_error!(Type::Setup, Timer::global().init().await); } pub(super) async fn init_hotkey() { - logging!(info, Type::Setup, "Initializing hotkey..."); logging_error!(Type::Setup, Hotkey::global().init().await); } pub(super) async fn init_once_auto_lightweight() { - logging!( - info, - Type::Lightweight, - "Running auto lightweight mode check..." - ); run_once_auto_lightweight().await; } pub(super) async fn init_auto_lightweight_mode() { - logging!(info, Type::Setup, "Initializing auto lightweight mode..."); logging_error!(Type::Setup, auto_lightweight_mode_init().await); } pub async fn init_work_config() { - logging!(info, Type::Setup, "Initializing work configuration..."); logging_error!(Type::Setup, init::init_config().await); } pub(super) async fn init_tray() { - // Check if tray should be disabled via environment variable if std::env::var("CLASH_VERGE_DISABLE_TRAY").unwrap_or_default() == "1" { - logging!(info, Type::Setup, "System tray disabled via --no-tray flag"); return; } - - logging!(info, Type::Setup, "Initializing system tray..."); logging_error!(Type::Setup, Tray::global().init().await); } pub(super) async fn init_verge_config() { - logging!(info, Type::Setup, "Initializing verge configuration..."); logging_error!(Type::Setup, Config::init_config().await); } pub(super) async fn init_service_manager() { - logging!(info, Type::Setup, "Initializing service manager..."); clash_verge_service_ipc::set_config(ServiceManager::config()).await; if !is_service_ipc_path_exists() { - logging!( - warn, - Type::Setup, - "Service IPC path does not exist, service may be unavailable" - ); return; } if SERVICE_MANAGER.lock().await.init().await.is_ok() { @@ -215,39 +152,27 @@ pub(super) async fn init_service_manager() { } pub(super) async fn init_core_manager() { - logging!(info, Type::Setup, "Initializing core manager..."); logging_error!(Type::Setup, CoreManager::global().init().await); } pub(super) async fn init_system_proxy() { - logging!(info, Type::Setup, "Initializing system proxy..."); - logging_error!( - Type::Setup, - sysopt::Sysopt::global().update_sysproxy().await - ); + logging_error!(Type::Setup, sysopt::Sysopt::global().update_sysproxy().await); } pub(super) fn init_system_proxy_guard() { - logging!(info, Type::Setup, "Initializing system proxy guard..."); logging_error!(Type::Setup, sysopt::Sysopt::global().init_guard_sysproxy()); } pub(super) async fn refresh_tray_menu() { - logging!(info, Type::Setup, "Refreshing tray menu..."); logging_error!(Type::Setup, Tray::global().update_part().await); } pub(super) async fn init_window() { - logging!(info, Type::Setup, "Initializing main window..."); - let is_silent_start = - { Config::verge().await.latest_ref().enable_silent_start }.unwrap_or(false); + let is_silent_start = Config::verge().await.latest_ref().enable_silent_start.unwrap_or(false); #[cfg(target_os = "macos")] - { - if is_silent_start { - use crate::core::handle::Handle; - - Handle::global().set_activation_policy_accessory(); - } + if is_silent_start { + use crate::core::handle::Handle; + Handle::global().set_activation_policy_accessory(); } WindowManager::create_window(!is_silent_start).await; } diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs index 3902688b3..e8576cdec 100644 --- a/src-tauri/src/utils/server.rs +++ b/src-tauri/src/utils/server.rs @@ -67,7 +67,7 @@ pub fn embed_server() { .expect("failed to set shutdown signal for embedded server"); let port = IVerge::get_singleton_port(); - AsyncHandler::spawn(move || async move { + let _ = AsyncHandler::spawn(move || async move { let visible = warp::path!("commands" / "visible").and_then(|| async { logging!(info, Type::Window, "检测到从单例模式恢复应用窗口"); if !lightweight::exit_lightweight_mode().await { @@ -84,20 +84,17 @@ pub fn embed_server() { let verge_config = Config::verge().await; let clash_config = Config::clash().await; - let content = verge_config + let pac_content = verge_config .latest_ref() .pac_file_content .clone() .unwrap_or(DEFAULT_PAC.into()); - let mixed_port = verge_config + let pac_port = verge_config .latest_ref() .verge_mixed_port .unwrap_or(clash_config.latest_ref().get_mixed_port()); - // Clone the content and port for the closure to avoid borrowing issues - let pac_content = content.clone(); - let pac_port = mixed_port; let pac = warp::path!("commands" / "pac").map(move || { let processed_content = pac_content.replace("%mixed-port%", &format!("{pac_port}")); warp::http::Response::builder() @@ -110,9 +107,8 @@ pub fn embed_server() { let scheme = warp::path!("commands" / "scheme") .and(warp::query::()) .map(|query: QueryParam| { - // Spawn async work in a fire-and-forget manner let param = query.param.clone(); - tokio::task::spawn_local(async move { + let _ = tokio::task::spawn_local(async move { logging_error!(Type::Setup, resolve::resolve_scheme(param).await); }); warp::reply::with_status::("ok".into(), warp::http::StatusCode::OK)