mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 04:53:44 +08:00
feat: enhance merge config validation and error handling
This commit is contained in:
parent
1a9b0a476b
commit
a4dd4bcc8a
@ -187,24 +187,57 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 在异步操作前完成所有文件操作
|
// 在异步操作前完成所有文件操作
|
||||||
let (file_path, original_content) = {
|
let (file_path, original_content, is_merge_file) = {
|
||||||
let profiles = Config::profiles();
|
let profiles = Config::profiles();
|
||||||
let profiles_guard = profiles.latest();
|
let profiles_guard = profiles.latest();
|
||||||
let item = wrap_err!(profiles_guard.get_item(&index))?;
|
let item = wrap_err!(profiles_guard.get_item(&index))?;
|
||||||
|
// 确定是否为merge类型文件
|
||||||
|
let is_merge = item.itype.as_ref().map_or(false, |t| t == "merge");
|
||||||
let content = wrap_err!(item.read_file())?;
|
let content = wrap_err!(item.read_file())?;
|
||||||
let path = item.file.clone().ok_or("file field is null")?;
|
let path = item.file.clone().ok_or("file field is null")?;
|
||||||
let profiles_dir = wrap_err!(dirs::app_profiles_dir())?;
|
let profiles_dir = wrap_err!(dirs::app_profiles_dir())?;
|
||||||
(profiles_dir.join(path), content)
|
(profiles_dir.join(path), content, is_merge)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 保存新的配置文件
|
// 保存新的配置文件
|
||||||
wrap_err!(fs::write(&file_path, file_data.clone().unwrap()))?;
|
wrap_err!(fs::write(&file_path, file_data.clone().unwrap()))?;
|
||||||
|
|
||||||
let file_path_str = file_path.to_string_lossy();
|
let file_path_str = file_path.to_string_lossy().to_string();
|
||||||
println!("[cmd配置save] 开始验证配置文件: {}", file_path_str);
|
println!("[cmd配置save] 开始验证配置文件: {}, 是否为merge文件: {}", file_path_str, is_merge_file);
|
||||||
|
|
||||||
// 验证配置文件
|
// 对于 merge 文件,只进行语法验证,不进行后续内核验证
|
||||||
match CoreManager::global().validate_config_file(&file_path_str).await {
|
if is_merge_file {
|
||||||
|
println!("[cmd配置save] 检测到merge文件,只进行语法验证");
|
||||||
|
match CoreManager::global().validate_config_file(&file_path_str, Some(true)).await {
|
||||||
|
Ok((true, _)) => {
|
||||||
|
println!("[cmd配置save] merge文件语法验证通过");
|
||||||
|
// 成功后尝试更新整体配置
|
||||||
|
if let Err(e) = CoreManager::global().update_config().await {
|
||||||
|
println!("[cmd配置save] 更新整体配置时发生错误: {}", e);
|
||||||
|
log::warn!(target: "app", "更新整体配置时发生错误: {}", e);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Ok((false, error_msg)) => {
|
||||||
|
println!("[cmd配置save] merge文件语法验证失败: {}", error_msg);
|
||||||
|
// 恢复原始配置文件
|
||||||
|
wrap_err!(fs::write(&file_path, original_content))?;
|
||||||
|
// 发送合并文件专用错误通知
|
||||||
|
let result = (false, error_msg.clone());
|
||||||
|
handle_yaml_validation_notice(&result, "合并配置文件");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("[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, _)) => {
|
Ok((true, _)) => {
|
||||||
println!("[cmd配置save] 验证成功");
|
println!("[cmd配置save] 验证成功");
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -214,18 +247,27 @@ pub async fn save_profile_file(index: String, file_data: Option<String>) -> CmdR
|
|||||||
// 恢复原始配置文件
|
// 恢复原始配置文件
|
||||||
wrap_err!(fs::write(&file_path, original_content))?;
|
wrap_err!(fs::write(&file_path, original_content))?;
|
||||||
|
|
||||||
// 智能判断是否为脚本错误
|
// 智能判断错误类型
|
||||||
let is_script_error = file_path_str.ends_with(".js") ||
|
let is_script_error = file_path_str.ends_with(".js") ||
|
||||||
error_msg.contains("Script syntax error") ||
|
error_msg.contains("Script syntax error") ||
|
||||||
error_msg.contains("Script must contain a main function") ||
|
error_msg.contains("Script must contain a main function") ||
|
||||||
error_msg.contains("Failed to read script file");
|
error_msg.contains("Failed to read script file");
|
||||||
|
|
||||||
if is_script_error {
|
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通知处理
|
||||||
|
println!("[cmd配置save] YAML配置文件验证失败,发送通知");
|
||||||
|
let result = (false, error_msg.clone());
|
||||||
|
handle_yaml_validation_notice(&result, "YAML配置文件");
|
||||||
|
} else if is_script_error {
|
||||||
// 脚本错误使用专门的通知处理
|
// 脚本错误使用专门的通知处理
|
||||||
|
println!("[cmd配置save] 脚本文件验证失败,发送通知");
|
||||||
let result = (false, error_msg.clone());
|
let result = (false, error_msg.clone());
|
||||||
handle_script_validation_notice(&result, "脚本文件");
|
handle_script_validation_notice(&result, "脚本文件");
|
||||||
} else {
|
} else {
|
||||||
// 普通配置错误使用一般通知
|
// 普通配置错误使用一般通知
|
||||||
|
println!("[cmd配置save] 其他类型验证失败,发送一般通知");
|
||||||
handle::Handle::notice_message("config_validate::error", &error_msg);
|
handle::Handle::notice_message("config_validate::error", &error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,7 +635,7 @@ pub fn handle_script_validation_notice(result: &(bool, String), file_type: &str)
|
|||||||
pub async fn validate_script_file(file_path: String) -> CmdResult<bool> {
|
pub async fn validate_script_file(file_path: String) -> CmdResult<bool> {
|
||||||
log::info!(target: "app", "验证脚本文件: {}", file_path);
|
log::info!(target: "app", "验证脚本文件: {}", file_path);
|
||||||
|
|
||||||
match CoreManager::global().validate_config_file(&file_path).await {
|
match CoreManager::global().validate_config_file(&file_path, None).await {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
handle_script_validation_notice(&result, "脚本文件");
|
handle_script_validation_notice(&result, "脚本文件");
|
||||||
Ok(result.0) // 返回验证结果布尔值
|
Ok(result.0) // 返回验证结果布尔值
|
||||||
@ -606,3 +648,51 @@ pub async fn validate_script_file(file_path: String) -> CmdResult<bool> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 处理YAML验证相关的所有消息通知
|
||||||
|
/// 统一通知接口,保持消息类型一致性
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 检查是否为merge文件
|
||||||
|
let is_merge_file = file_type.contains("合并");
|
||||||
|
|
||||||
|
// 根据错误消息内容判断错误类型
|
||||||
|
let status = if error_msg.starts_with("File not found:") {
|
||||||
|
"config_validate::file_not_found"
|
||||||
|
} else if error_msg.starts_with("Failed to read file:") {
|
||||||
|
"config_validate::yaml_read_error"
|
||||||
|
} else if error_msg.starts_with("YAML syntax error:") {
|
||||||
|
if is_merge_file {
|
||||||
|
"config_validate::merge_syntax_error"
|
||||||
|
} else {
|
||||||
|
"config_validate::yaml_syntax_error"
|
||||||
|
}
|
||||||
|
} else if error_msg.contains("mapping values are not allowed") {
|
||||||
|
if is_merge_file {
|
||||||
|
"config_validate::merge_mapping_error"
|
||||||
|
} else {
|
||||||
|
"config_validate::yaml_mapping_error"
|
||||||
|
}
|
||||||
|
} else if error_msg.contains("did not find expected key") {
|
||||||
|
if is_merge_file {
|
||||||
|
"config_validate::merge_key_error"
|
||||||
|
} else {
|
||||||
|
"config_validate::yaml_key_error"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果是其他类型错误,根据文件类型作为一般错误处理
|
||||||
|
if is_merge_file {
|
||||||
|
"config_validate::merge_error"
|
||||||
|
} else {
|
||||||
|
"config_validate::yaml_error"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
log::warn!(target: "app", "{} 验证失败: {}", file_type, error_msg);
|
||||||
|
println!("[通知] 发送通知: status={}, msg={}", status, error_msg);
|
||||||
|
handle::Handle::notice_message(status, error_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -240,7 +240,7 @@ impl CoreManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 验证指定的配置文件
|
/// 验证指定的配置文件
|
||||||
pub async fn validate_config_file(&self, config_path: &str) -> Result<(bool, String)> {
|
pub async fn validate_config_file(&self, config_path: &str, is_merge_file: Option<bool>) -> Result<(bool, String)> {
|
||||||
// 检查文件是否存在
|
// 检查文件是否存在
|
||||||
if !std::path::Path::new(config_path).exists() {
|
if !std::path::Path::new(config_path).exists() {
|
||||||
let error_msg = format!("File not found: {}", config_path);
|
let error_msg = format!("File not found: {}", config_path);
|
||||||
@ -248,6 +248,12 @@ impl CoreManager {
|
|||||||
return Ok((false, error_msg));
|
return Ok((false, error_msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果是合并文件且不是强制验证,执行语法检查但不进行完整验证
|
||||||
|
if is_merge_file.unwrap_or(false) {
|
||||||
|
println!("[core配置验证] 检测到Merge文件,仅进行语法检查: {}", config_path);
|
||||||
|
return self.validate_file_syntax(config_path).await;
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否为脚本文件
|
// 检查是否为脚本文件
|
||||||
let is_script = if config_path.ends_with(".js") {
|
let is_script = if config_path.ends_with(".js") {
|
||||||
true
|
true
|
||||||
@ -345,7 +351,8 @@ impl CoreManager {
|
|||||||
Ok(content) => content,
|
Ok(content) => content,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let error_msg = format!("Failed to read script file: {}", err);
|
let error_msg = format!("Failed to read script file: {}", err);
|
||||||
//handle::Handle::notice_message("config_validate::script_error", &error_msg);
|
log::warn!(target: "app", "脚本语法错误: {}", err);
|
||||||
|
//handle::Handle::notice_message("config_validate::script_syntax_error", &error_msg);
|
||||||
return Ok((false, error_msg));
|
return Ok((false, error_msg));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -440,4 +447,34 @@ impl CoreManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 只进行文件语法检查,不进行完整验证
|
||||||
|
async fn validate_file_syntax(&self, config_path: &str) -> Result<(bool, String)> {
|
||||||
|
println!("[core配置语法检查] 开始检查文件: {}", config_path);
|
||||||
|
|
||||||
|
// 读取文件内容
|
||||||
|
let content = match std::fs::read_to_string(config_path) {
|
||||||
|
Ok(content) => content,
|
||||||
|
Err(err) => {
|
||||||
|
let error_msg = format!("Failed to read file: {}", err);
|
||||||
|
println!("[core配置语法检查] 无法读取文件: {}", error_msg);
|
||||||
|
return Ok((false, error_msg));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 对YAML文件尝试解析,只检查语法正确性
|
||||||
|
println!("[core配置语法检查] 进行YAML语法检查");
|
||||||
|
match serde_yaml::from_str::<serde_yaml::Value>(&content) {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("[core配置语法检查] YAML语法检查通过");
|
||||||
|
Ok((true, String::new()))
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
// 使用标准化的前缀,以便错误处理函数能正确识别
|
||||||
|
let error_msg = format!("YAML syntax error: {}", err);
|
||||||
|
println!("[core配置语法检查] YAML语法错误: {}", error_msg);
|
||||||
|
Ok((false, error_msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -451,5 +451,18 @@
|
|||||||
"File Not Found": "File missing, changes reverted",
|
"File Not Found": "File missing, changes reverted",
|
||||||
"Script File Error": "Script file error, changes reverted",
|
"Script File Error": "Script file error, changes reverted",
|
||||||
"Core Changed Successfully": "Core changed successfully",
|
"Core Changed Successfully": "Core changed successfully",
|
||||||
"Failed to Change Core": "Failed to change core"
|
"Failed to Change Core": "Failed to change core",
|
||||||
|
"YAML Syntax Error": "YAML syntax error, changes reverted",
|
||||||
|
"YAML Read Error": "YAML read error, changes reverted",
|
||||||
|
"YAML Mapping Error": "YAML mapping error, changes reverted",
|
||||||
|
"YAML Key Error": "YAML key error, changes reverted",
|
||||||
|
"YAML Error": "YAML error, changes reverted",
|
||||||
|
"Merge File Syntax Error": "Merge file syntax error, changes reverted",
|
||||||
|
"Merge File Mapping Error": "Merge file mapping error, changes reverted",
|
||||||
|
"Merge File Key Error": "Merge file key error, changes reverted",
|
||||||
|
"Merge File Error": "Merge file error, changes reverted",
|
||||||
|
"Validate YAML File": "Validate YAML File",
|
||||||
|
"Validate Merge File": "Validate Merge File",
|
||||||
|
"Validation Success": "Validation Success",
|
||||||
|
"Validation Failed": "Validation Failed"
|
||||||
}
|
}
|
||||||
|
@ -135,9 +135,9 @@
|
|||||||
"Hidden": "隐藏代理组",
|
"Hidden": "隐藏代理组",
|
||||||
"Group Name Required": "代理组名称不能为空",
|
"Group Name Required": "代理组名称不能为空",
|
||||||
"Group Name Already Exists": "代理组名称已存在",
|
"Group Name Already Exists": "代理组名称已存在",
|
||||||
"Extend Config": "扩展配置",
|
"Extend Config": "扩展覆写配置",
|
||||||
"Extend Script": "扩展脚本",
|
"Extend Script": "扩展脚本",
|
||||||
"Global Merge": "全局扩展配置",
|
"Global Merge": "全局扩展覆写配置",
|
||||||
"Global Script": "全局扩展脚本",
|
"Global Script": "全局扩展脚本",
|
||||||
"Type": "类型",
|
"Type": "类型",
|
||||||
"Name": "名称",
|
"Name": "名称",
|
||||||
@ -444,5 +444,18 @@
|
|||||||
"File Not Found": "文件丢失,变更已撤销",
|
"File Not Found": "文件丢失,变更已撤销",
|
||||||
"Script File Error": "脚本文件错误,变更已撤销",
|
"Script File Error": "脚本文件错误,变更已撤销",
|
||||||
"Core Changed Successfully": "内核切换成功",
|
"Core Changed Successfully": "内核切换成功",
|
||||||
"Failed to Change Core": "无法切换内核"
|
"Failed to Change Core": "无法切换内核",
|
||||||
|
"YAML Syntax Error": "YAML语法错误,变更已撤销",
|
||||||
|
"YAML Read Error": "YAML读取错误,变更已撤销",
|
||||||
|
"YAML Mapping Error": "YAML映射错误,变更已撤销",
|
||||||
|
"YAML Key Error": "YAML键错误,变更已撤销",
|
||||||
|
"YAML Error": "YAML错误,变更已撤销",
|
||||||
|
"Merge File Syntax Error": "覆写文件语法错误,变更已撤销",
|
||||||
|
"Merge File Mapping Error": "覆写文件映射错误,变更已撤销",
|
||||||
|
"Merge File Key Error": "覆写文件键错误,变更已撤销",
|
||||||
|
"Merge File Error": "覆写文件错误,变更已撤销",
|
||||||
|
"Validate YAML File": "验证YAML文件",
|
||||||
|
"Validate Merge File": "验证覆写文件",
|
||||||
|
"Validation Success": "验证成功",
|
||||||
|
"Validation Failed": "验证失败"
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,33 @@ const handleNoticeMessage = (
|
|||||||
case "config_validate::file_not_found":
|
case "config_validate::file_not_found":
|
||||||
Notice.error(`${t("File Not Found")} ${msg}`);
|
Notice.error(`${t("File Not Found")} ${msg}`);
|
||||||
break;
|
break;
|
||||||
|
case "config_validate::yaml_syntax_error":
|
||||||
|
Notice.error(`${t("YAML Syntax Error")} ${msg}`);
|
||||||
|
break;
|
||||||
|
case "config_validate::yaml_read_error":
|
||||||
|
Notice.error(`${t("YAML Read Error")} ${msg}`);
|
||||||
|
break;
|
||||||
|
case "config_validate::yaml_mapping_error":
|
||||||
|
Notice.error(`${t("YAML Mapping Error")} ${msg}`);
|
||||||
|
break;
|
||||||
|
case "config_validate::yaml_key_error":
|
||||||
|
Notice.error(`${t("YAML Key Error")} ${msg}`);
|
||||||
|
break;
|
||||||
|
case "config_validate::yaml_error":
|
||||||
|
Notice.error(`${t("YAML Error")} ${msg}`);
|
||||||
|
break;
|
||||||
|
case "config_validate::merge_syntax_error":
|
||||||
|
Notice.error(`${t("Merge File Syntax Error")} ${msg}`);
|
||||||
|
break;
|
||||||
|
case "config_validate::merge_mapping_error":
|
||||||
|
Notice.error(`${t("Merge File Mapping Error")} ${msg}`);
|
||||||
|
break;
|
||||||
|
case "config_validate::merge_key_error":
|
||||||
|
Notice.error(`${t("Merge File Key Error")} ${msg}`);
|
||||||
|
break;
|
||||||
|
case "config_validate::merge_error":
|
||||||
|
Notice.error(`${t("Merge File Error")} ${msg}`);
|
||||||
|
break;
|
||||||
case "config_core::change_success":
|
case "config_core::change_success":
|
||||||
Notice.success(`${t("Core Changed Successfully")}: ${msg}`);
|
Notice.success(`${t("Core Changed Successfully")}: ${msg}`);
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user