fix: improve error handling and logging in various modules

This commit is contained in:
Tunglies
2025-11-05 02:11:43 +08:00
parent 28483ff9db
commit 3e2f605e77
6 changed files with 63 additions and 35 deletions

View File

@@ -292,8 +292,7 @@ async fn restore_previous_profile(prev_profile: &String) -> CmdResult<()> {
}; };
Config::profiles() Config::profiles()
.await .await
.edit_draft(|d| d.patch_config(&restore_profiles)) .edit_draft(|d| d.patch_config(&restore_profiles));
.stringify_err()?;
Config::profiles().await.apply(); Config::profiles().await.apply();
crate::process::AsyncHandler::spawn(|| async move { crate::process::AsyncHandler::spawn(|| async move {
if let Err(e) = profiles_save_file_safe().await { if let Err(e) = profiles_save_file_safe().await {
@@ -412,7 +411,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
CURRENT_SWITCHING_PROFILE.store(false, Ordering::Release); CURRENT_SWITCHING_PROFILE.store(false, Ordering::Release);
return Ok(false); return Ok(false);
} }
let _ = Config::profiles() Config::profiles()
.await .await
.edit_draft(|d| d.patch_config(&profiles)); .edit_draft(|d| d.patch_config(&profiles));

View File

@@ -155,15 +155,13 @@ impl Config {
}; };
let runtime = Config::runtime().await; let runtime = Config::runtime().await;
let config = runtime let runtime_arc = runtime.latest_arc();
.latest_arc() let config = runtime_arc
.config .config
.as_ref() .as_ref()
.ok_or_else(|| anyhow!("failed to get runtime config"))? .ok_or_else(|| anyhow!("failed to get runtime config"))?;
.clone();
drop(runtime); // 显式释放锁
help::save_yaml(&path, &config, Some("# Generated by Clash Verge")).await?; help::save_yaml(&path, config, Some("# Generated by Clash Verge")).await?;
Ok(path) Ok(path)
} }

View File

@@ -87,7 +87,7 @@ impl IProfiles {
} }
/// 只修改currentvalid和chain /// 只修改currentvalid和chain
pub fn patch_config(&mut self, patch: &IProfiles) -> Result<()> { pub fn patch_config(&mut self, patch: &IProfiles) {
if self.items.is_none() { if self.items.is_none() {
self.items = Some(vec![]); self.items = Some(vec![]);
} }
@@ -100,8 +100,6 @@ impl IProfiles {
self.current = some_uid.cloned(); self.current = some_uid.cloned();
} }
} }
Ok(())
} }
pub fn get_current(&self) -> Option<&String> { pub fn get_current(&self) -> Option<&String> {

View File

@@ -24,6 +24,8 @@ use futures::future::join_all;
use parking_lot::Mutex; use parking_lot::Mutex;
use smartstring::alias::String; use smartstring::alias::String;
use std::collections::HashMap; use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use std::{ use std::{
sync::atomic::{AtomicBool, Ordering}, sync::atomic::{AtomicBool, Ordering},
@@ -575,9 +577,6 @@ impl Tray {
return; return;
} }
use std::future::Future;
use std::pin::Pin;
let fut: Pin<Box<dyn Future<Output = ()> + Send>> = match tray_event.as_str() { let fut: Pin<Box<dyn Future<Output = ()> + Send>> = match tray_event.as_str() {
"system_proxy" => Box::pin(async move { "system_proxy" => Box::pin(async move {
feat::toggle_system_proxy().await; feat::toggle_system_proxy().await;
@@ -1226,7 +1225,14 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
}; };
feat::switch_proxy_node(group_name, proxy_name).await; feat::switch_proxy_node(group_name, proxy_name).await;
} }
_ => {} _ => {
logging!(
debug,
Type::Tray,
"Unhandled tray menu event: {:?}",
event.id
);
}
} }
// We dont expected to refresh tray state here // We dont expected to refresh tray state here

View File

@@ -275,41 +275,43 @@ impl CoreConfigValidator {
logging!(info, Type::Validate, "验证目录: {}", app_dir_str); logging!(info, Type::Validate, "验证目录: {}", app_dir_str);
// 使用子进程运行clash验证配置 // 使用子进程运行clash验证配置
let output = app_handle let command = app_handle.shell().sidecar(clash_core.as_str())?.args([
.shell() "-t",
.sidecar(clash_core.as_str())? "-d",
.args(["-t", "-d", app_dir_str, "-f", config_path]) app_dir_str,
.output() "-f",
.await?; config_path,
]);
let output = command.output().await?;
let stderr = std::string::String::from_utf8_lossy(&output.stderr); let status = &output.status;
let stdout = std::string::String::from_utf8_lossy(&output.stdout); let stderr = &output.stderr;
let stdout = &output.stdout;
// 检查进程退出状态和错误输出 // 检查进程退出状态和错误输出
let error_keywords = ["FATA", "fatal", "Parse config error", "level=fatal"]; let error_keywords = ["FATA", "fatal", "Parse config error", "level=fatal"];
let has_error = let has_error = !status.success() || contains_any_keyword(stderr, &error_keywords);
!output.status.success() || error_keywords.iter().any(|&kw| stderr.contains(kw));
logging!(info, Type::Validate, "-------- 验证结果 --------"); logging!(info, Type::Validate, "-------- 验证结果 --------");
if !stderr.is_empty() { if !stderr.is_empty() {
logging!(info, Type::Validate, "stderr输出:\n{}", stderr); logging!(info, Type::Validate, "stderr输出:\n{:?}", stderr);
} }
if has_error { if has_error {
logging!(info, Type::Validate, "发现错误,开始处理错误信息"); logging!(info, Type::Validate, "发现错误,开始处理错误信息");
let error_msg = if !stdout.is_empty() { let error_msg: String = if !stdout.is_empty() {
stdout.into() str::from_utf8(stdout).unwrap_or_default().into()
} else if !stderr.is_empty() { } else if !stderr.is_empty() {
stderr.into() str::from_utf8(stderr).unwrap_or_default().into()
} else if let Some(code) = output.status.code() { } else if let Some(code) = status.code() {
format!("验证进程异常退出,退出码: {code}") format!("验证进程异常退出,退出码: {code}").into()
} else { } else {
"验证进程被终止".into() "验证进程被终止".into()
}; };
logging!(info, Type::Validate, "-------- 验证结束 --------"); logging!(info, Type::Validate, "-------- 验证结束 --------");
Ok((false, error_msg.into())) // 返回错误消息给调用者处理 Ok((false, error_msg)) // 返回错误消息给调用者处理
} else { } else {
logging!(info, Type::Validate, "验证成功"); logging!(info, Type::Validate, "验证成功");
logging!(info, Type::Validate, "-------- 验证结束 --------"); logging!(info, Type::Validate, "-------- 验证结束 --------");
@@ -342,6 +344,23 @@ fn has_ext<P: AsRef<std::path::Path>>(path: P, ext: &str) -> bool {
.unwrap_or(false) .unwrap_or(false)
} }
fn contains_any_keyword<'a>(buf: &'a [u8], keywords: &'a [&str]) -> bool {
for &kw in keywords {
let needle = kw.as_bytes();
if needle.is_empty() {
continue;
}
let mut i = 0;
while i + needle.len() <= buf.len() {
if &buf[i..i + needle.len()] == needle {
return true;
}
i += 1;
}
}
false
}
singleton_lazy!( singleton_lazy!(
CoreConfigValidator, CoreConfigValidator,
CORECONFIGVALIDATOR, CORECONFIGVALIDATOR,

View File

@@ -1,4 +1,4 @@
#[cfg(not(feature = "tracing"))] // #[cfg(not(feature = "tracing"))]
#[cfg(not(feature = "tauri-dev"))] #[cfg(not(feature = "tauri-dev"))]
use crate::utils::logging::NoModuleFilter; use crate::utils::logging::NoModuleFilter;
use crate::{ use crate::{
@@ -49,7 +49,9 @@ pub async fn init_logger() -> Result<()> {
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
spec.module("tauri", log::LevelFilter::Debug); spec.module("tauri", log::LevelFilter::Debug);
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
spec.module("wry", log::LevelFilter::Debug); spec.module("wry", log::LevelFilter::Off);
#[cfg(feature = "tracing")]
spec.module("tauri_plugin_mihomo", log::LevelFilter::Off);
let spec = spec.build(); let spec = spec.build();
let logger = Logger::with(spec) let logger = Logger::with(spec)
@@ -67,6 +69,12 @@ pub async fn init_logger() -> Result<()> {
); );
#[cfg(not(feature = "tracing"))] #[cfg(not(feature = "tracing"))]
let logger = logger.filter(Box::new(NoModuleFilter(&["wry", "tauri"]))); let logger = logger.filter(Box::new(NoModuleFilter(&["wry", "tauri"])));
#[cfg(feature = "tracing")]
let logger = logger.filter(Box::new(NoModuleFilter(&[
"wry",
"tauri_plugin_mihomo",
"kode_bridge",
])));
let _handle = logger.start()?; let _handle = logger.start()?;