feat: add clash_core config validation & auto-fix to default; fixed "No such file or directory (os error 2)"

This commit is contained in:
wonfen
2025-06-16 20:27:02 +08:00
parent 2a0e1e206e
commit 26acce94a4
6 changed files with 107 additions and 26 deletions

View File

@@ -1,3 +1,8 @@
## v2.3.1
### 🐞 修复问题
- 增加配置文件校验,修复从古老版本升级上来的"No such file or directory (os error 2)"错误
## v2.3.0
**发行代号:御**
@@ -5,8 +10,6 @@
尽管 `external-controller` 密钥现已自动补全默认值且不允许为空,**仍建议手动修改密钥以提高安全性**。
---
### ⚠️ 已知问题
- 仅在 Ubuntu 22.04/24.04、Fedora 41 的 **GNOME 桌面环境** 做过简单测试,不保证其他 Linux 发行版兼容,后续将逐步适配和优化。
@@ -17,8 +20,6 @@
- 已确认窗口状态管理器存在上游缺陷,已暂时移除窗口大小与位置记忆功能。
---
### 🐞 修复问题
- 修复首页“代理模式”快速切换导致的卡死问题
@@ -42,8 +43,6 @@
- 修复 JS 脚本转义特殊字符报错
- 修复 macOS 静默启动时异常启动 Dock 栏图标
---
### ✨ 新增功能
- **Mihomo(Meta) 内核升级至 v1.19.10**
@@ -72,8 +71,6 @@
- 新增 Zashboard 一键跳转入口
- 使用系统默认窗口管理器
---
### 🚀 优化改进
- **系统相关:**
@@ -112,13 +109,9 @@
- 网络延迟测试替换为 HTTPS 协议:`https://cp.cloudflare.com/generate_204`
- 优化 IP 信息获取流程,添加去重机制与轮询检测算法
---
- 同步修复翻译错误与不一致项,优化整体语言体验
- 加强语言切换后的页面稳定性,避免加载异常
---
### 🗑️ 移除内容
- 窗口状态管理器(上游存在缺陷)

View File

@@ -1,6 +1,7 @@
use crate::{
config::{deserialize_encrypted, serialize_encrypted, DEFAULT_PAC},
utils::{dirs, help, i18n},
logging,
utils::{dirs, help, i18n, logging::Type},
};
use anyhow::Result;
use log::LevelFilter;
@@ -232,6 +233,94 @@ pub struct IVergeTheme {
}
impl IVerge {
/// 有效的clash核心名称
pub const VALID_CLASH_CORES: &'static [&'static str] = &["verge-mihomo", "verge-mihomo-alpha"];
/// 验证并修正配置文件中的clash_core值
pub fn validate_and_fix_config() -> Result<()> {
let config_path = dirs::verge_path()?;
let mut config = match help::read_yaml::<IVerge>(&config_path) {
Ok(config) => config,
Err(_) => Self::template(),
};
let mut needs_fix = false;
if let Some(ref core) = config.clash_core {
let core_str = core.trim();
if core_str.is_empty() || !Self::VALID_CLASH_CORES.contains(&core_str) {
logging!(
warn,
Type::Config,
true,
"启动时发现无效的clash_core配置: '{}', 将自动修正为 'verge-mihomo'",
core
);
config.clash_core = Some("verge-mihomo".to_string());
needs_fix = true;
}
} else {
logging!(
info,
Type::Config,
true,
"启动时发现未配置clash_core, 将设置为默认值 'verge-mihomo'"
);
config.clash_core = Some("verge-mihomo".to_string());
needs_fix = true;
}
// 修正后保存配置
if needs_fix {
logging!(info, Type::Config, true, "正在保存修正后的配置文件...");
help::save_yaml(&config_path, &config, Some("# Clash Verge Config"))?;
logging!(
info,
Type::Config,
true,
"配置文件修正完成,需要重新加载配置"
);
Self::reload_config_after_fix(config)?;
} else {
logging!(
info,
Type::Config,
true,
"clash_core配置验证通过: {:?}",
config.clash_core
);
}
Ok(())
}
/// 配置修正后重新加载配置
fn reload_config_after_fix(updated_config: IVerge) -> Result<()> {
use crate::config::Config;
let config_draft = Config::verge();
*config_draft.draft() = Box::new(updated_config.clone());
config_draft.apply();
logging!(
info,
Type::Config,
true,
"内存配置已强制更新新的clash_core: {:?}",
updated_config.clash_core
);
Ok(())
}
pub fn get_valid_clash_core(&self) -> String {
self.clash_core
.clone()
.unwrap_or_else(|| "verge-mihomo".to_string())
}
fn get_system_language() -> String {
let sys_lang = sys_locale::get_locale()
.unwrap_or_else(|| String::from("en"))
@@ -503,6 +592,8 @@ pub struct IVergeResponse {
impl From<IVerge> for IVergeResponse {
fn from(verge: IVerge) -> Self {
// 先获取验证后的clash_core值避免后续借用冲突
let valid_clash_core = verge.get_valid_clash_core();
Self {
app_log_level: verge.app_log_level,
language: verge.language,
@@ -534,7 +625,7 @@ impl From<IVerge> for IVergeResponse {
proxy_host: verge.proxy_host,
theme_setting: verge.theme_setting,
web_ui_list: verge.web_ui_list,
clash_core: verge.clash_core,
clash_core: Some(valid_clash_core),
hotkeys: verge.hotkeys,
auto_close_connection: verge.auto_close_connection,
auto_check_update: verge.auto_check_update,

View File

@@ -54,7 +54,7 @@ impl fmt::Display for RunningMode {
}
}
const CLASH_CORES: [&str; 2] = ["verge-mihomo", "verge-mihomo-alpha"];
use crate::config::IVerge;
impl CoreManager {
/// 检查文件是否为脚本文件
@@ -249,8 +249,7 @@ impl CoreManager {
config_path
);
let clash_core = { Config::verge().latest().clash_core.clone() };
let clash_core = clash_core.unwrap_or("verge-mihomo".into());
let clash_core = Config::verge().latest().get_valid_clash_core();
logging!(info, Type::Config, true, "使用内核: {}", clash_core);
let app_handle = handle::Handle::global().app_handle().unwrap();
@@ -442,11 +441,7 @@ impl CoreManager {
let app_handle = handle::Handle::global()
.app_handle()
.ok_or(anyhow::anyhow!("failed to get app handle"))?;
let clash_core = Config::verge()
.latest()
.clash_core
.clone()
.unwrap_or("verge-mihomo".to_string());
let clash_core = Config::verge().latest().get_valid_clash_core();
let config_dir = dirs::app_home_dir()?;
let service_log_dir = dirs::app_home_dir()?.join("logs").join("service");
@@ -804,7 +799,7 @@ impl CoreManager {
return Err(error_message.to_string());
}
let core: &str = &clash_core.clone().unwrap();
if !CLASH_CORES.contains(&core) {
if !IVerge::VALID_CLASH_CORES.contains(&core) {
let error_message = format!("Clash core invalid name: {}", core);
logging!(error, Type::Core, true, "{}", error_message);
return Err(error_message);

View File

@@ -742,8 +742,7 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
log::info!(target:"app", "尝试使用现有服务启动核心 (IPC)");
// logging!(info, Type::Service, true, "尝试使用现有服务启动核心");
let clash_core = { Config::verge().latest().clash_core.clone() };
let clash_core = clash_core.unwrap_or("verge-mihomo".into());
let clash_core = Config::verge().latest().get_valid_clash_core();
let bin_ext = if cfg!(windows) { ".exe" } else { "" };
let clash_bin = format!("{clash_core}{bin_ext}");

View File

@@ -22,7 +22,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
let verge = Config::verge();
let verge = verge.latest();
(
verge.clash_core.clone(),
Some(verge.get_valid_clash_core()),
verge.enable_tun_mode.unwrap_or(false),
verge.enable_builtin_enhanced.unwrap_or(true),
verge.verge_socks_enabled.unwrap_or(false),

View File

@@ -286,6 +286,9 @@ pub fn init_config() -> Result<()> {
<Result<()>>::Ok(())
}));
// 验证并修正verge.yaml中的clash_core配置
crate::log_err!(IVerge::validate_and_fix_config());
crate::log_err!(dirs::profiles_path().map(|path| {
if !path.exists() {
help::save_yaml(&path, &IProfiles::template(), Some("# Clash Verge"))?;