diff --git a/UPDATELOG.md b/UPDATELOG.md index 136aa2e1d..de1ae001d 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -1,7 +1,8 @@ ## v2.3.1 ### 🐞 修复问题 - - 增加配置文件校验,修复从古老版本升级上来的"No such file or directory (os error 2)"错误 + +- 增加配置文件校验,修复从古老版本升级上来的"No such file or directory (os error 2)"错误 ## v2.3.0 @@ -14,6 +15,7 @@ - 仅在 Ubuntu 22.04/24.04、Fedora 41 的 **GNOME 桌面环境** 做过简单测试,不保证其他 Linux 发行版兼容,后续将逐步适配和优化。 - macOS: + - MacOS 下自动升级成功后请关闭程序等待 30 秒重启,因为 MacOS 的端口释放特性,卸载服务后需重启应用等 30 秒才能恢复内核通信。立即启动可能无法正常启动内核。 - 墙贴主要为浅色,深色 Tray 图标存在闪烁问题; - 彩色 Tray 图标颜色偏淡; diff --git a/src-tauri/src/cmd/save_profile.rs b/src-tauri/src/cmd/save_profile.rs index 5c4b73ef1..5e2b7bc1b 100644 --- a/src-tauri/src/cmd/save_profile.rs +++ b/src-tauri/src/cmd/save_profile.rs @@ -1,5 +1,11 @@ use super::CmdResult; -use crate::{config::*, core::*, utils::dirs, wrap_err}; +use crate::{ + config::*, + core::*, + logging, + utils::{dirs, logging::Type}, + wrap_err, +}; use std::fs; /// 保存profiles的配置 @@ -26,29 +32,54 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR wrap_err!(fs::write(&file_path, file_data.clone().unwrap()))?; let file_path_str = file_path.to_string_lossy().to_string(); - println!( + logging!( + info, + Type::Config, + true, "[cmd配置save] 开始验证配置文件: {}, 是否为merge文件: {}", - file_path_str, is_merge_file + file_path_str, + is_merge_file ); // 对于 merge 文件,只进行语法验证,不进行后续内核验证 if is_merge_file { - println!("[cmd配置save] 检测到merge文件,只进行语法验证"); + logging!( + info, + Type::Config, + true, + "[cmd配置save] 检测到merge文件,只进行语法验证" + ); match CoreManager::global() .validate_config_file(&file_path_str, Some(true)) .await { Ok((true, _)) => { - println!("[cmd配置save] merge文件语法验证通过"); + logging!( + info, + Type::Config, + true, + "[cmd配置save] merge文件语法验证通过" + ); // 成功后尝试更新整体配置 if let Err(e) = CoreManager::global().update_config().await { - println!("[cmd配置save] 更新整体配置时发生错误: {}", e); - log::warn!(target: "app", "更新整体配置时发生错误: {}", e); + logging!( + warn, + Type::Config, + true, + "[cmd配置save] 更新整体配置时发生错误: {}", + e + ); } return Ok(()); } Ok((false, error_msg)) => { - println!("[cmd配置save] merge文件语法验证失败: {}", error_msg); + logging!( + warn, + Type::Config, + true, + "[cmd配置save] merge文件语法验证失败: {}", + error_msg + ); // 恢复原始配置文件 wrap_err!(fs::write(&file_path, original_content))?; // 发送合并文件专用错误通知 @@ -57,7 +88,13 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR return Ok(()); } Err(e) => { - println!("[cmd配置save] 验证过程发生错误: {}", e); + logging!( + error, + Type::Config, + true, + "[cmd配置save] 验证过程发生错误: {}", + e + ); // 恢复原始配置文件 wrap_err!(fs::write(&file_path, original_content))?; return Err(e.to_string()); @@ -71,11 +108,17 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR .await { Ok((true, _)) => { - println!("[cmd配置save] 验证成功"); + logging!(info, Type::Config, true, "[cmd配置save] 验证成功"); Ok(()) } Ok((false, error_msg)) => { - println!("[cmd配置save] 验证失败: {}", error_msg); + logging!( + warn, + Type::Config, + true, + "[cmd配置save] 验证失败: {}", + error_msg + ); // 恢复原始配置文件 wrap_err!(fs::write(&file_path, original_content))?; @@ -90,24 +133,30 @@ pub async fn save_profile_file(index: String, file_data: Option) -> CmdR || (!file_path_str.ends_with(".js") && !is_script_error) { // 普通YAML错误使用YAML通知处理 - println!("[cmd配置save] YAML配置文件验证失败,发送通知"); + log::info!(target: "app", "[cmd配置save] YAML配置文件验证失败,发送通知"); let result = (false, error_msg.clone()); crate::cmd::validate::handle_yaml_validation_notice(&result, "YAML配置文件"); } else if is_script_error { // 脚本错误使用专门的通知处理 - println!("[cmd配置save] 脚本文件验证失败,发送通知"); + log::info!(target: "app", "[cmd配置save] 脚本文件验证失败,发送通知"); let result = (false, error_msg.clone()); crate::cmd::validate::handle_script_validation_notice(&result, "脚本文件"); } else { // 普通配置错误使用一般通知 - println!("[cmd配置save] 其他类型验证失败,发送一般通知"); + log::info!(target: "app", "[cmd配置save] 其他类型验证失败,发送一般通知"); handle::Handle::notice_message("config_validate::error", &error_msg); } Ok(()) } Err(e) => { - println!("[cmd配置save] 验证过程发生错误: {}", e); + logging!( + error, + Type::Config, + true, + "[cmd配置save] 验证过程发生错误: {}", + e + ); // 恢复原始配置文件 wrap_err!(fs::write(&file_path, original_content))?; Err(e.to_string()) diff --git a/src-tauri/src/cmd/validate.rs b/src-tauri/src/cmd/validate.rs index 94cab28b7..7275ac074 100644 --- a/src-tauri/src/cmd/validate.rs +++ b/src-tauri/src/cmd/validate.rs @@ -1,5 +1,5 @@ use super::CmdResult; -use crate::core::*; +use crate::{core::*, logging, utils::logging::Type}; /// 发送脚本验证通知消息 #[tauri::command] @@ -28,7 +28,14 @@ pub fn handle_script_validation_notice(result: &(bool, String), file_type: &str) "config_validate::script_error" }; - log::warn!(target: "app", "{} 验证失败: {}", file_type, error_msg); + logging!( + warn, + Type::Config, + true, + "{} 验证失败: {}", + file_type, + error_msg + ); handle::Handle::notice_message(status, error_msg); } } @@ -36,7 +43,7 @@ pub fn handle_script_validation_notice(result: &(bool, String), file_type: &str) /// 验证指定脚本文件 #[tauri::command] pub async fn validate_script_file(file_path: String) -> CmdResult { - log::info!(target: "app", "验证脚本文件: {}", file_path); + logging!(info, Type::Config, true, "验证脚本文件: {}", file_path); match CoreManager::global() .validate_config_file(&file_path, None) @@ -48,7 +55,13 @@ pub async fn validate_script_file(file_path: String) -> CmdResult { } Err(e) => { let error_msg = e.to_string(); - log::error!(target: "app", "验证脚本文件过程发生错误: {}", error_msg); + logging!( + error, + Type::Config, + true, + "验证脚本文件过程发生错误: {}", + error_msg + ); handle::Handle::notice_message("config_validate::process_terminated", &error_msg); Ok(false) } @@ -60,7 +73,14 @@ pub async fn validate_script_file(file_path: String) -> CmdResult { pub fn handle_yaml_validation_notice(result: &(bool, String), file_type: &str) { if !result.0 { let error_msg = &result.1; - println!("[通知] 处理{}验证错误: {}", file_type, error_msg); + logging!( + info, + Type::Config, + true, + "[通知] 处理{}验证错误: {}", + file_type, + error_msg + ); // 检查是否为merge文件 let is_merge_file = file_type.contains("合并"); @@ -97,8 +117,22 @@ pub fn handle_yaml_validation_notice(result: &(bool, String), file_type: &str) { } }; - log::warn!(target: "app", "{} 验证失败: {}", file_type, error_msg); - println!("[通知] 发送通知: status={}, msg={}", status, error_msg); + logging!( + warn, + Type::Config, + true, + "{} 验证失败: {}", + file_type, + error_msg + ); + logging!( + info, + Type::Config, + true, + "[通知] 发送通知: status={}, msg={}", + status, + error_msg + ); handle::Handle::notice_message(status, error_msg); } } diff --git a/src-tauri/src/feat/clash.rs b/src-tauri/src/feat/clash.rs index 68b0134f8..c57e69537 100644 --- a/src-tauri/src/feat/clash.rs +++ b/src-tauri/src/feat/clash.rs @@ -84,7 +84,7 @@ pub fn change_clash_mode(mode: String) { after_change_clash_mode(); } } - Err(err) => println!("{err}"), + Err(err) => log::error!(target: "app", "{err}"), } }); } diff --git a/src-tauri/src/feat/profile.rs b/src-tauri/src/feat/profile.rs index f2f341973..1b76c228b 100644 --- a/src-tauri/src/feat/profile.rs +++ b/src-tauri/src/feat/profile.rs @@ -2,7 +2,9 @@ use crate::{ cmd, config::{Config, PrfItem, PrfOption}, core::{handle, CoreManager, *}, + logging, process::AsyncHandler, + utils::logging::Type, }; use anyhow::{bail, Result}; @@ -29,7 +31,7 @@ pub async fn update_profile( option: Option, auto_refresh: Option, ) -> Result<()> { - println!("[订阅更新] 开始更新订阅 {}", uid); + logging!(info, Type::Config, true, "[订阅更新] 开始更新订阅 {}", uid); let auto_refresh = auto_refresh.unwrap_or(true); // 默认为true,保持兼容性 let url_opt = { @@ -39,13 +41,13 @@ pub async fn update_profile( let is_remote = item.itype.as_ref().is_some_and(|s| s == "remote"); if !is_remote { - println!("[订阅更新] {} 不是远程订阅,跳过更新", uid); + log::info!(target: "app", "[订阅更新] {} 不是远程订阅,跳过更新", uid); None // 非远程订阅直接更新 } else if item.url.is_none() { - println!("[订阅更新] {} 缺少URL,无法更新", uid); + log::warn!(target: "app", "[订阅更新] {} 缺少URL,无法更新", uid); bail!("failed to get the profile item url"); } else { - println!( + log::info!(target: "app", "[订阅更新] {} 是远程订阅,URL: {}", uid, item.url.clone().unwrap() @@ -56,24 +58,24 @@ pub async fn update_profile( let should_update = match url_opt { Some((url, opt)) => { - println!("[订阅更新] 开始下载新的订阅内容"); + log::info!(target: "app", "[订阅更新] 开始下载新的订阅内容"); let merged_opt = PrfOption::merge(opt.clone(), option.clone()); // 尝试使用正常设置更新 match PrfItem::from_url(&url, None, None, merged_opt.clone()).await { Ok(item) => { - println!("[订阅更新] 更新订阅配置成功"); + log::info!(target: "app", "[订阅更新] 更新订阅配置成功"); let profiles = Config::profiles(); let mut profiles = profiles.latest(); profiles.update_item(uid.clone(), item)?; let is_current = Some(uid.clone()) == profiles.get_current(); - println!("[订阅更新] 是否为当前使用的订阅: {}", is_current); + log::info!(target: "app", "[订阅更新] 是否为当前使用的订阅: {}", is_current); is_current && auto_refresh } Err(err) => { // 首次更新失败,尝试使用Clash代理 - println!("[订阅更新] 正常更新失败: {},尝试使用Clash代理更新", err); + log::warn!(target: "app", "[订阅更新] 正常更新失败: {},尝试使用Clash代理更新", err); // 发送通知 handle::Handle::notice_message("update_retry_with_clash", uid.clone()); @@ -90,7 +92,7 @@ pub async fn update_profile( // 使用Clash代理重试 match PrfItem::from_url(&url, None, None, Some(fallback_opt)).await { Ok(mut item) => { - println!("[订阅更新] 使用Clash代理更新成功"); + log::info!(target: "app", "[订阅更新] 使用Clash代理更新成功"); // 恢复原始代理设置到item if let Some(option) = item.option.as_mut() { @@ -110,11 +112,11 @@ pub async fn update_profile( handle::Handle::notice_message("update_with_clash_proxy", profile_name); let is_current = Some(uid.clone()) == profiles.get_current(); - println!("[订阅更新] 是否为当前使用的订阅: {}", is_current); + log::info!(target: "app", "[订阅更新] 是否为当前使用的订阅: {}", is_current); is_current && auto_refresh } Err(retry_err) => { - println!("[订阅更新] 使用Clash代理更新仍然失败: {}", retry_err); + log::error!(target: "app", "[订阅更新] 使用Clash代理更新仍然失败: {}", retry_err); handle::Handle::notice_message( "update_failed_even_with_clash", format!("{}", retry_err), @@ -129,14 +131,14 @@ pub async fn update_profile( }; if should_update { - println!("[订阅更新] 更新内核配置"); + logging!(info, Type::Config, true, "[订阅更新] 更新内核配置"); match CoreManager::global().update_config().await { Ok(_) => { - println!("[订阅更新] 更新成功"); + logging!(info, Type::Config, true, "[订阅更新] 更新成功"); handle::Handle::refresh_clash(); } Err(err) => { - println!("[订阅更新] 更新失败: {}", err); + logging!(error, Type::Config, true, "[订阅更新] 更新失败: {}", err); handle::Handle::notice_message("update_failed", format!("{err}")); log::error!(target: "app", "{err}"); } diff --git a/src-tauri/src/feat/window.rs b/src-tauri/src/feat/window.rs index 40f3c4ca9..d537d8061 100644 --- a/src-tauri/src/feat/window.rs +++ b/src-tauri/src/feat/window.rs @@ -3,45 +3,39 @@ use crate::AppHandleManager; use crate::{ config::Config, core::{handle, sysopt, CoreManager}, + logging, module::mihomo::MihomoManager, - utils::resolve, + utils::{logging::Type, resolve}, }; /// Open or close the dashboard window #[allow(dead_code)] pub fn open_or_close_dashboard() { - println!("Attempting to open/close dashboard"); log::info!(target: "app", "Attempting to open/close dashboard"); // 检查是否在轻量模式下 if crate::module::lightweight::is_in_lightweight_mode() { - println!("Currently in lightweight mode, exiting lightweight mode"); log::info!(target: "app", "Currently in lightweight mode, exiting lightweight mode"); crate::module::lightweight::exit_lightweight_mode(); - println!("Creating new window after exiting lightweight mode"); log::info!(target: "app", "Creating new window after exiting lightweight mode"); resolve::create_window(true); return; } if let Some(window) = handle::Handle::global().get_window() { - println!("Found existing window"); log::info!(target: "app", "Found existing window"); // 如果窗口存在,则切换其显示状态 match window.is_visible() { Ok(visible) => { - println!("Window visibility status: {}", visible); log::info!(target: "app", "Window visibility status: {}", visible); if visible { - println!("Attempting to hide window"); log::info!(target: "app", "Attempting to hide window"); let _ = window.hide(); } else { - println!("Attempting to show and focus window"); log::info!(target: "app", "Attempting to show and focus window"); if window.is_minimized().unwrap_or(false) { let _ = window.unminimize(); @@ -51,12 +45,10 @@ pub fn open_or_close_dashboard() { } } Err(e) => { - println!("Failed to get window visibility: {:?}", e); log::error!(target: "app", "Failed to get window visibility: {:?}", e); } } } else { - println!("No existing window found, creating new window"); log::info!(target: "app", "No existing window found, creating new window"); resolve::create_window(true); } @@ -65,7 +57,7 @@ pub fn open_or_close_dashboard() { /// 异步优化的应用退出函数 pub fn quit() { use crate::process::AsyncHandler; - log::debug!(target: "app", "启动退出流程"); + logging!(debug, Type::System, true, "启动退出流程"); // 获取应用句柄并设置退出标志 let app_handle = handle::Handle::global().app_handle().unwrap(); @@ -79,10 +71,16 @@ pub fn quit() { // 使用异步任务处理资源清理,避免阻塞 AsyncHandler::spawn(move || async move { - log::info!(target: "app", "开始异步清理资源"); + logging!(info, Type::System, true, "开始异步清理资源"); let cleanup_result = clean_async().await; - log::info!(target: "app", "资源清理完成,退出代码: {}", if cleanup_result { 0 } else { 1 }); + logging!( + info, + Type::System, + true, + "资源清理完成,退出代码: {}", + if cleanup_result { 0 } else { 1 } + ); app_handle.exit(if cleanup_result { 0 } else { 1 }); }); } @@ -90,7 +88,7 @@ pub fn quit() { async fn clean_async() -> bool { use tokio::time::{timeout, Duration}; - log::info!(target: "app", "开始执行异步清理操作..."); + logging!(info, Type::System, true, "开始执行异步清理操作..."); // 1. 处理TUN模式 let tun_task = async { @@ -178,10 +176,16 @@ async fn clean_async() -> bool { let all_success = tun_success && proxy_success && core_success && dns_success; - log::info!( - target: "app", + logging!( + info, + Type::System, + true, "异步清理操作完成 - TUN: {}, 代理: {}, 核心: {}, DNS: {}, 总体: {}", - tun_success, proxy_success, core_success, dns_success, all_success + tun_success, + proxy_success, + core_success, + dns_success, + all_success ); all_success @@ -193,7 +197,7 @@ pub fn clean() -> bool { let (tx, rx) = std::sync::mpsc::channel(); AsyncHandler::spawn(move || async move { - log::info!(target: "app", "开始执行清理操作..."); + logging!(info, Type::System, true, "开始执行清理操作..."); // 使用已有的异步清理函数 let cleanup_result = clean_async().await; @@ -204,11 +208,16 @@ pub fn clean() -> bool { match rx.recv_timeout(std::time::Duration::from_secs(8)) { Ok(result) => { - log::info!(target: "app", "清理操作完成,结果: {}", result); + logging!(info, Type::System, true, "清理操作完成,结果: {}", result); result } Err(_) => { - log::warn!(target: "app", "清理操作超时,返回成功状态避免阻塞"); + logging!( + warn, + Type::System, + true, + "清理操作超时,返回成功状态避免阻塞" + ); true } } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 137f32b2e..245ad23c7 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -368,7 +368,7 @@ pub fn run() { if core::handle::Handle::global().is_exiting() { return; } - println!("closing window..."); + log::info!(target: "app", "closing window..."); api.prevent_close(); if let Some(window) = core::handle::Handle::global().get_window() { let _ = window.hide(); diff --git a/src/components/setting/mods/controller-viewer.tsx b/src/components/setting/mods/controller-viewer.tsx index 84a77f103..5734d2b78 100644 --- a/src/components/setting/mods/controller-viewer.tsx +++ b/src/components/setting/mods/controller-viewer.tsx @@ -1,6 +1,5 @@ import { BaseDialog, DialogRef } from "@/components/base"; import { useClashInfo } from "@/hooks/use-clash"; -import { patchClashConfig } from "@/services/cmds"; import { showNotice } from "@/services/noticeService"; import { ContentCopy } from "@mui/icons-material"; import { @@ -42,19 +41,19 @@ export const ControllerViewer = forwardRef((props, ref) => { // 保存配置 const onSave = useLockFn(async () => { if (!controller.trim()) { - showNotice("error", t("Controller address cannot be empty"), 3000); + showNotice("error", t("Controller address cannot be empty")); return; } if (!secret.trim()) { - showNotice("error", t("Secret cannot be empty"), 3000); + showNotice("error", t("Secret cannot be empty")); return; } try { setIsSaving(true); await patchInfo({ "external-controller": controller, secret }); - showNotice("success", t("Configuration saved successfully"), 2000); + showNotice("success", t("Configuration saved successfully")); setOpen(false); } catch (err: any) { showNotice( @@ -73,9 +72,9 @@ export const ControllerViewer = forwardRef((props, ref) => { try { await navigator.clipboard.writeText(text); setCopySuccess(type); - setTimeout(() => setCopySuccess(null), 2000); + setTimeout(() => setCopySuccess(null)); } catch (err) { - showNotice("error", t("Failed to copy"), 2000); + showNotice("error", t("Failed to copy")); } }, );