refactor: streamline config handling and logging mechanisms

This commit is contained in:
Tunglies
2025-11-15 02:46:34 +08:00
parent f6f288f02b
commit 2b0ba4dc95
6 changed files with 17 additions and 108 deletions

View File

@@ -1,9 +1,6 @@
use super::CmdResult; use super::CmdResult;
use crate::{ use crate::{
cmd::StringifyErr as _, cmd::StringifyErr as _, config::Config, core::CoreManager, logging_error, utils::logging::Type,
config::{Config, ConfigType},
core::CoreManager,
log_err,
}; };
use anyhow::{Context as _, anyhow}; use anyhow::{Context as _, anyhow};
use serde_yaml_ng::Mapping; use serde_yaml_ng::Mapping;
@@ -104,14 +101,9 @@ pub async fn update_proxy_chain_config_in_runtime(
{ {
let runtime = Config::runtime().await; let runtime = Config::runtime().await;
runtime.edit_draft(|d| d.update_proxy_chain_config(proxy_chain_config)); runtime.edit_draft(|d| d.update_proxy_chain_config(proxy_chain_config));
runtime.apply(); // 我们需要在 CoreManager 中验证并应用配置,这里不应该直接调用 runtime.apply()
} }
logging_error!(Type::Core, CoreManager::global().update_config().await);
// 生成新的运行配置文件并通知 Clash 核心重新加载
let run_path = Config::generate_file(ConfigType::Run)
.await
.stringify_err()?;
log_err!(CoreManager::global().put_configs_force(run_path).await);
Ok(()) Ok(())
} }

View File

@@ -35,8 +35,7 @@ pub mod bypass {
pub mod timing { pub mod timing {
use super::Duration; use super::Duration;
pub const CONFIG_UPDATE_DEBOUNCE: Duration = Duration::from_millis(500); pub const CONFIG_UPDATE_DEBOUNCE: Duration = Duration::from_millis(300);
pub const CONFIG_RELOAD_DELAY: Duration = Duration::from_millis(300);
pub const EVENT_EMIT_DELAY: Duration = Duration::from_millis(20); pub const EVENT_EMIT_DELAY: Duration = Duration::from_millis(20);
pub const STARTUP_ERROR_DELAY: Duration = Duration::from_secs(2); pub const STARTUP_ERROR_DELAY: Duration = Duration::from_secs(2);
pub const ERROR_BATCH_DELAY: Duration = Duration::from_millis(300); pub const ERROR_BATCH_DELAY: Duration = Duration::from_millis(300);
@@ -58,15 +57,6 @@ pub mod files {
pub const WINDOW_STATE: &str = "window_state.json"; pub const WINDOW_STATE: &str = "window_state.json";
} }
pub mod error_patterns {
pub const CONNECTION_ERRORS: &[&str] = &[
"Failed to create connection",
"The system cannot find the file specified",
"operation timed out",
"connection refused",
];
}
pub mod tun { pub mod tun {
pub const DEFAULT_STACK: &str = "gvisor"; pub const DEFAULT_STACK: &str = "gvisor";

View File

@@ -10,7 +10,6 @@ use anyhow::{Result, anyhow};
use smartstring::alias::String; use smartstring::alias::String;
use std::{path::PathBuf, time::Instant}; use std::{path::PathBuf, time::Instant};
use tauri_plugin_mihomo::Error as MihomoError; use tauri_plugin_mihomo::Error as MihomoError;
use tokio::time::sleep;
impl CoreManager { impl CoreManager {
pub async fn use_default_config(&self, error_key: &str, error_msg: &str) -> Result<()> { pub async fn use_default_config(&self, error_key: &str, error_msg: &str) -> Result<()> {
@@ -37,25 +36,25 @@ impl CoreManager {
return Ok((true, String::new())); return Ok((true, String::new()));
} }
if !self.should_update_config()? { if !self.should_update_config() {
return Ok((true, String::new())); return Ok((true, String::new()));
} }
self.perform_config_update().await self.perform_config_update().await
} }
fn should_update_config(&self) -> Result<bool> { fn should_update_config(&self) -> bool {
let now = Instant::now(); let now = Instant::now();
let last = self.get_last_update(); let last = self.get_last_update();
if let Some(last_time) = last if let Some(last_time) = last
&& now.duration_since(*last_time) < timing::CONFIG_UPDATE_DEBOUNCE && now.duration_since(*last_time) < timing::CONFIG_UPDATE_DEBOUNCE
{ {
return Ok(false); return false;
} }
self.set_last_update(now); self.set_last_update(now);
Ok(true) true
} }
async fn perform_config_update(&self) -> Result<(bool, String)> { async fn perform_config_update(&self) -> Result<(bool, String)> {
@@ -78,22 +77,14 @@ impl CoreManager {
} }
} }
pub async fn put_configs_force(&self, path: PathBuf) -> Result<()> { async fn apply_config(&self, path: PathBuf) -> Result<()> {
self.apply_config(path).await let path = dirs::path_to_str(&path)?;
} match self.reload_config(path).await {
pub(super) async fn apply_config(&self, path: PathBuf) -> Result<()> {
let path_str = dirs::path_to_str(&path)?;
match self.reload_config(path_str).await {
Ok(_) => { Ok(_) => {
Config::runtime().await.apply(); Config::runtime().await.apply();
logging!(info, Type::Core, "Configuration applied"); logging!(info, Type::Core, "Configuration applied");
Ok(()) Ok(())
} }
Err(err) if Self::should_restart_on_error(&err) => {
self.retry_with_restart(path_str).await
}
Err(err) => { Err(err) => {
Config::runtime().await.discard(); Config::runtime().await.discard();
Err(anyhow!("Failed to apply config: {}", err)) Err(anyhow!("Failed to apply config: {}", err))
@@ -101,54 +92,10 @@ impl CoreManager {
} }
} }
async fn retry_with_restart(&self, config_path: &str) -> Result<()> {
if handle::Handle::global().is_exiting() {
return Err(anyhow!("Application exiting"));
}
logging!(warn, Type::Core, "Restarting core for config reload");
self.restart_core().await?;
sleep(timing::CONFIG_RELOAD_DELAY).await;
self.reload_config(config_path).await?;
Config::runtime().await.apply();
logging!(info, Type::Core, "Configuration applied after restart");
Ok(())
}
async fn reload_config(&self, path: &str) -> Result<(), MihomoError> { async fn reload_config(&self, path: &str) -> Result<(), MihomoError> {
handle::Handle::mihomo() handle::Handle::mihomo()
.await .await
.reload_config(true, path) .reload_config(true, path)
.await .await
} }
fn should_restart_on_error(err: &MihomoError) -> bool {
match err {
MihomoError::ConnectionFailed | MihomoError::ConnectionLost => true,
MihomoError::Io(io_err) => Self::is_connection_io_error(io_err.kind()),
MihomoError::Reqwest(req_err) => {
req_err.is_connect()
|| req_err.is_timeout()
|| Self::contains_error_pattern(&req_err.to_string())
}
MihomoError::FailedResponse(msg) => Self::contains_error_pattern(msg),
_ => false,
}
}
const 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 {
use crate::constants::error_patterns::CONNECTION_ERRORS;
CONNECTION_ERRORS.iter().any(|p| text.contains(p))
}
} }

View File

@@ -1,5 +1,6 @@
use super::{CoreManager, RunningMode}; use super::{CoreManager, RunningMode};
use crate::config::{Config, ConfigType, IVerge}; use crate::cmd::StringifyErr as _;
use crate::config::{Config, IVerge};
use crate::{ use crate::{
core::{ core::{
logger::CLASH_LOGGER, logger::CLASH_LOGGER,
@@ -55,13 +56,8 @@ impl CoreManager {
let verge_data = Config::verge().await.latest_arc(); let verge_data = Config::verge().await.latest_arc();
verge_data.save_file().await.map_err(|e| e.to_string())?; verge_data.save_file().await.map_err(|e| e.to_string())?;
let run_path = Config::generate_file(ConfigType::Run) self.update_config().await.stringify_err()?;
.await Ok(())
.map_err(|e| e.to_string())?;
self.apply_config(run_path)
.await
.map_err(|e| e.to_string().into())
} }
async fn prepare_startup(&self) -> Result<()> { async fn prepare_startup(&self) -> Result<()> {

View File

@@ -1,12 +1,11 @@
use crate::{ use crate::{
config::Config, config::Config,
core::{handle, timer::Timer, tray::Tray}, core::{handle, timer::Timer, tray::Tray},
log_err, logging, logging,
process::AsyncHandler, process::AsyncHandler,
utils::logging::Type, utils::logging::Type,
}; };
#[cfg(target_os = "macos")]
use crate::logging_error; use crate::logging_error;
use crate::utils::window_manager::WindowManager; use crate::utils::window_manager::WindowManager;
@@ -184,7 +183,7 @@ fn cancel_window_close_listener() {
fn setup_webview_focus_listener() { fn setup_webview_focus_listener() {
if let Some(window) = handle::Handle::get_window() { if let Some(window) = handle::Handle::get_window() {
let handler_id = window.listen("tauri://focus", move |_event| { let handler_id = window.listen("tauri://focus", move |_event| {
log_err!(cancel_light_weight_timer()); logging_error!(Type::Lightweight, cancel_light_weight_timer());
logging!( logging!(
debug, debug,
Type::Lightweight, Type::Lightweight,

View File

@@ -65,21 +65,6 @@ macro_rules! error {
}; };
} }
#[macro_export]
macro_rules! log_err {
($result: expr) => {
if let Err(err) = $result {
log::error!(target: "app", "{err}");
}
};
($result: expr, $err_str: expr) => {
if let Err(_) = $result {
log::error!(target: "app", "{}", $err_str);
}
};
}
/// wrap the anyhow error /// wrap the anyhow error
/// transform the error to String /// transform the error to String
#[macro_export] #[macro_export]