mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-30 18:52:12 +08:00
✨ **New Features**: * Added API and frontend support for forcibly refreshing Clash configuration cache * Implemented a configuration cache TTL mechanism (60 seconds) to reduce redundant requests * Introduced `ProxyRequestCache` system to manage backend data caching * Automatically refresh frontend state after core operations to enhance user experience 🚀 **Performance Optimizations**: * Increased Clash configuration refresh interval from 5 seconds to 60 seconds * Force refresh cache after configuration updates to resolve data inconsistency * Automatically trigger state refresh after core switch, start, stop, and restart actions 🔧 **Technical Improvements**: * Removed unused dependencies: `ab_glyph`, `owned_ttf_parser`, `ttf-parser` * Simplified WebSocket dependency management, unified `tungstenite` version * Refactored configuration save validation process, improved merge file handling * Improved error handling and overall user experience
172 lines
6.1 KiB
Rust
172 lines
6.1 KiB
Rust
use super::CmdResult;
|
|
use crate::{
|
|
config::*,
|
|
core::*,
|
|
logging,
|
|
utils::{dirs, logging::Type},
|
|
wrap_err,
|
|
};
|
|
use std::fs;
|
|
|
|
/// 保存profiles的配置
|
|
#[tauri::command]
|
|
pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdResult {
|
|
if file_data.is_none() {
|
|
return Ok(());
|
|
}
|
|
|
|
// 在异步操作前完成所有文件操作
|
|
let (file_path, original_content, is_merge_file) = {
|
|
let profiles = Config::profiles();
|
|
let profiles_guard = profiles.latest_ref();
|
|
let item = wrap_err!(profiles_guard.get_item(&index))?;
|
|
// 确定是否为merge类型文件
|
|
let is_merge = item.itype.as_ref().is_some_and(|t| t == "merge");
|
|
let content = wrap_err!(item.read_file())?;
|
|
let path = item.file.clone().ok_or("file field is null")?;
|
|
let profiles_dir = wrap_err!(dirs::app_profiles_dir())?;
|
|
(profiles_dir.join(path), content, is_merge)
|
|
};
|
|
|
|
// 保存新的配置文件
|
|
wrap_err!(fs::write(&file_path, file_data.clone().unwrap()))?;
|
|
|
|
let file_path_str = file_path.to_string_lossy().to_string();
|
|
logging!(
|
|
info,
|
|
Type::Config,
|
|
true,
|
|
"[cmd配置save] 开始验证配置文件: {}, 是否为merge文件: {}",
|
|
file_path_str,
|
|
is_merge_file
|
|
);
|
|
|
|
// 对于 merge 文件,只进行语法验证,不进行后续内核验证
|
|
if is_merge_file {
|
|
logging!(
|
|
info,
|
|
Type::Config,
|
|
true,
|
|
"[cmd配置save] 检测到merge文件,只进行语法验证"
|
|
);
|
|
match CoreManager::global()
|
|
.validate_config_file(&file_path_str, Some(true))
|
|
.await
|
|
{
|
|
Ok((true, _)) => {
|
|
logging!(
|
|
info,
|
|
Type::Config,
|
|
true,
|
|
"[cmd配置save] merge文件语法验证通过"
|
|
);
|
|
// 成功后尝试更新整体配置
|
|
match CoreManager::global().update_config().await {
|
|
Ok(_) => {
|
|
// 配置更新成功,刷新前端
|
|
handle::Handle::refresh_clash();
|
|
}
|
|
Err(e) => {
|
|
logging!(
|
|
warn,
|
|
Type::Config,
|
|
true,
|
|
"[cmd配置save] 更新整体配置时发生错误: {}",
|
|
e
|
|
);
|
|
}
|
|
}
|
|
return Ok(());
|
|
}
|
|
Ok((false, error_msg)) => {
|
|
logging!(
|
|
warn,
|
|
Type::Config,
|
|
true,
|
|
"[cmd配置save] merge文件语法验证失败: {}",
|
|
error_msg
|
|
);
|
|
// 恢复原始配置文件
|
|
wrap_err!(fs::write(&file_path, original_content))?;
|
|
// 发送合并文件专用错误通知
|
|
let result = (false, error_msg.clone());
|
|
crate::cmd::validate::handle_yaml_validation_notice(&result, "合并配置文件");
|
|
return Ok(());
|
|
}
|
|
Err(e) => {
|
|
logging!(
|
|
error,
|
|
Type::Config,
|
|
true,
|
|
"[cmd配置save] 验证过程发生错误: {}",
|
|
e
|
|
);
|
|
// 恢复原始配置文件
|
|
wrap_err!(fs::write(&file_path, original_content))?;
|
|
return Err(e.to_string());
|
|
}
|
|
}
|
|
}
|
|
|
|
// 非merge文件使用完整验证流程
|
|
match CoreManager::global()
|
|
.validate_config_file(&file_path_str, None)
|
|
.await
|
|
{
|
|
Ok((true, _)) => {
|
|
logging!(info, Type::Config, true, "[cmd配置save] 验证成功");
|
|
Ok(())
|
|
}
|
|
Ok((false, error_msg)) => {
|
|
logging!(
|
|
warn,
|
|
Type::Config,
|
|
true,
|
|
"[cmd配置save] 验证失败: {}",
|
|
error_msg
|
|
);
|
|
// 恢复原始配置文件
|
|
wrap_err!(fs::write(&file_path, original_content))?;
|
|
|
|
// 智能判断错误类型
|
|
let is_script_error = file_path_str.ends_with(".js")
|
|
|| error_msg.contains("Script syntax error")
|
|
|| error_msg.contains("Script must contain a main function")
|
|
|| error_msg.contains("Failed to read script file");
|
|
|
|
if error_msg.contains("YAML syntax error")
|
|
|| error_msg.contains("Failed to read file:")
|
|
|| (!file_path_str.ends_with(".js") && !is_script_error)
|
|
{
|
|
// 普通YAML错误使用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 {
|
|
// 脚本错误使用专门的通知处理
|
|
log::info!(target: "app", "[cmd配置save] 脚本文件验证失败,发送通知");
|
|
let result = (false, error_msg.clone());
|
|
crate::cmd::validate::handle_script_validation_notice(&result, "脚本文件");
|
|
} else {
|
|
// 普通配置错误使用一般通知
|
|
log::info!(target: "app", "[cmd配置save] 其他类型验证失败,发送一般通知");
|
|
handle::Handle::notice_message("config_validate::error", &error_msg);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
Err(e) => {
|
|
logging!(
|
|
error,
|
|
Type::Config,
|
|
true,
|
|
"[cmd配置save] 验证过程发生错误: {}",
|
|
e
|
|
);
|
|
// 恢复原始配置文件
|
|
wrap_err!(fs::write(&file_path, original_content))?;
|
|
Err(e.to_string())
|
|
}
|
|
}
|
|
}
|