mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 17:15:38 +08:00
feat(clippy): cognitive-complexity rule (#5215)
* feat(config): enhance configuration initialization and validation process * refactor(profile): streamline profile update logic and enhance error handling * refactor(config): simplify profile item checks and streamline update flag processing * refactor(disney_plus): add cognitive complexity allowance for check_disney_plus function * refactor(enhance): restructure configuration and profile item handling for improved clarity and maintainability * refactor(tray): add cognitive complexity allowance for create_tray_menu function * refactor(config): add cognitive complexity allowance for patch_config function * refactor(profiles): simplify item removal logic by introducing take_item_file_by_uid helper function * refactor(profile): add new validation logic for profile configuration syntax * refactor(profiles): improve formatting and readability of take_item_file_by_uid function * refactor(cargo): change cognitive complexity level from warn to deny * refactor(cargo): ensure cognitive complexity is denied in Cargo.toml * refactor(i18n): clean up imports and improve code readability refactor(proxy): simplify system proxy toggle logic refactor(service): remove unnecessary `as_str()` conversion in error handling refactor(tray): modularize tray menu creation for better maintainability * refactor(tray): update menu item text handling to use references for improved performance
This commit is contained in:
@@ -6,6 +6,7 @@ use crate::{logging, utils::logging::Type};
|
||||
use super::UnlockItem;
|
||||
use super::utils::{country_code_to_emoji, get_local_date_string};
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub(super) async fn check_disney_plus(client: &Client) -> UnlockItem {
|
||||
let device_api_url = "https://disney.api.edge.bamgrid.com/devices";
|
||||
let auth_header =
|
||||
|
||||
@@ -216,6 +216,257 @@ pub async fn delete_profile(index: String) -> CmdResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 验证新配置文件的语法
|
||||
async fn validate_new_profile(new_profile: &String) -> Result<(), ()> {
|
||||
logging!(info, Type::Cmd, "正在切换到新配置: {}", new_profile);
|
||||
|
||||
// 获取目标配置文件路径
|
||||
let config_file_result = {
|
||||
let profiles_config = Config::profiles().await;
|
||||
let profiles_data = profiles_config.latest_ref();
|
||||
match profiles_data.get_item(new_profile) {
|
||||
Ok(item) => {
|
||||
if let Some(file) = &item.file {
|
||||
let path = dirs::app_profiles_dir().map(|dir| dir.join(file.as_str()));
|
||||
path.ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Cmd, "获取目标配置信息失败: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 如果获取到文件路径,检查YAML语法
|
||||
if let Some(file_path) = config_file_result {
|
||||
if !file_path.exists() {
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
"目标配置文件不存在: {}",
|
||||
file_path.display()
|
||||
);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_not_found",
|
||||
format!("{}", file_path.display()),
|
||||
);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// 超时保护
|
||||
let file_read_result = tokio::time::timeout(
|
||||
Duration::from_secs(5),
|
||||
tokio::fs::read_to_string(&file_path),
|
||||
)
|
||||
.await;
|
||||
|
||||
match file_read_result {
|
||||
Ok(Ok(content)) => {
|
||||
let yaml_parse_result = AsyncHandler::spawn_blocking(move || {
|
||||
serde_yaml_ng::from_str::<serde_yaml_ng::Value>(&content)
|
||||
})
|
||||
.await;
|
||||
|
||||
match yaml_parse_result {
|
||||
Ok(Ok(_)) => {
|
||||
logging!(info, Type::Cmd, "目标配置文件语法正确");
|
||||
Ok(())
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
let error_msg = format!(" {err}");
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
"目标配置文件存在YAML语法错误:{}",
|
||||
error_msg
|
||||
);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::yaml_syntax_error",
|
||||
error_msg.clone(),
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
Err(join_err) => {
|
||||
let error_msg = format!("YAML解析任务失败: {join_err}");
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::yaml_parse_error",
|
||||
error_msg.clone(),
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
let error_msg = format!("无法读取目标配置文件: {err}");
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_read_error",
|
||||
error_msg.clone(),
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
Err(_) => {
|
||||
let error_msg = "读取配置文件超时(5秒)".to_string();
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_read_timeout",
|
||||
error_msg.clone(),
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 执行配置更新并处理结果
|
||||
async fn restore_previous_profile(prev_profile: String) -> CmdResult<()> {
|
||||
logging!(info, Type::Cmd, "尝试恢复到之前的配置: {}", prev_profile);
|
||||
let restore_profiles = IProfiles {
|
||||
current: Some(prev_profile),
|
||||
items: None,
|
||||
};
|
||||
Config::profiles()
|
||||
.await
|
||||
.draft_mut()
|
||||
.patch_config(restore_profiles)
|
||||
.stringify_err()?;
|
||||
Config::profiles().await.apply();
|
||||
crate::process::AsyncHandler::spawn(|| async move {
|
||||
if let Err(e) = profiles_save_file_safe().await {
|
||||
log::warn!(target: "app", "异步保存恢复配置文件失败: {e}");
|
||||
}
|
||||
});
|
||||
logging!(info, Type::Cmd, "成功恢复到之前的配置");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_success(current_sequence: u64, current_value: Option<String>) -> CmdResult<bool> {
|
||||
let latest_sequence = CURRENT_REQUEST_SEQUENCE.load(Ordering::SeqCst);
|
||||
if current_sequence < latest_sequence {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"内核操作后发现更新的请求 (序列号: {} < {}),忽略当前结果",
|
||||
current_sequence,
|
||||
latest_sequence
|
||||
);
|
||||
Config::profiles().await.discard();
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"配置更新成功,序列号: {}",
|
||||
current_sequence
|
||||
);
|
||||
Config::profiles().await.apply();
|
||||
handle::Handle::refresh_clash();
|
||||
|
||||
if let Err(e) = Tray::global().update_tooltip().await {
|
||||
log::warn!(target: "app", "异步更新托盘提示失败: {e}");
|
||||
}
|
||||
|
||||
if let Err(e) = Tray::global().update_menu().await {
|
||||
log::warn!(target: "app", "异步更新托盘菜单失败: {e}");
|
||||
}
|
||||
|
||||
if let Err(e) = profiles_save_file_safe().await {
|
||||
log::warn!(target: "app", "异步保存配置文件失败: {e}");
|
||||
}
|
||||
|
||||
if let Some(current) = ¤t_value {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"向前端发送配置变更事件: {}, 序列号: {}",
|
||||
current,
|
||||
current_sequence
|
||||
);
|
||||
handle::Handle::notify_profile_changed(current.clone());
|
||||
}
|
||||
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
async fn handle_validation_failure(
|
||||
error_msg: String,
|
||||
current_profile: Option<String>,
|
||||
) -> CmdResult<bool> {
|
||||
logging!(warn, Type::Cmd, "配置验证失败: {}", error_msg);
|
||||
Config::profiles().await.discard();
|
||||
if let Some(prev_profile) = current_profile {
|
||||
restore_previous_profile(prev_profile).await?;
|
||||
}
|
||||
handle::Handle::notice_message("config_validate::error", error_msg);
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn handle_update_error<E: std::fmt::Display>(e: E, current_sequence: u64) -> CmdResult<bool> {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Cmd,
|
||||
"更新过程发生错误: {}, 序列号: {}",
|
||||
e,
|
||||
current_sequence
|
||||
);
|
||||
Config::profiles().await.discard();
|
||||
handle::Handle::notice_message("config_validate::boot_error", e.to_string());
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn handle_timeout(current_profile: Option<String>, current_sequence: u64) -> CmdResult<bool> {
|
||||
let timeout_msg = "配置更新超时(30秒),可能是配置验证或核心通信阻塞";
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
"{}, 序列号: {}",
|
||||
timeout_msg,
|
||||
current_sequence
|
||||
);
|
||||
Config::profiles().await.discard();
|
||||
if let Some(prev_profile) = current_profile {
|
||||
restore_previous_profile(prev_profile).await?;
|
||||
}
|
||||
handle::Handle::notice_message("config_validate::timeout", timeout_msg);
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
async fn perform_config_update(
|
||||
current_sequence: u64,
|
||||
current_value: Option<String>,
|
||||
current_profile: Option<String>,
|
||||
) -> CmdResult<bool> {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"开始内核配置更新,序列号: {}",
|
||||
current_sequence
|
||||
);
|
||||
let update_result = tokio::time::timeout(
|
||||
Duration::from_secs(30),
|
||||
CoreManager::global().update_config(),
|
||||
)
|
||||
.await;
|
||||
|
||||
match update_result {
|
||||
Ok(Ok((true, _))) => handle_success(current_sequence, current_value).await,
|
||||
Ok(Ok((false, error_msg))) => handle_validation_failure(error_msg, current_profile).await,
|
||||
Ok(Err(e)) => handle_update_error(e, current_sequence).await,
|
||||
Err(_) => handle_timeout(current_profile, current_sequence).await,
|
||||
}
|
||||
}
|
||||
|
||||
/// 修改profiles的配置
|
||||
#[tauri::command]
|
||||
pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
@@ -256,108 +507,10 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
// 如果要切换配置,先检查目标配置文件是否有语法错误
|
||||
if let Some(new_profile) = profiles.current.as_ref()
|
||||
&& current_profile.as_ref() != Some(new_profile)
|
||||
&& validate_new_profile(new_profile).await.is_err()
|
||||
{
|
||||
logging!(info, Type::Cmd, "正在切换到新配置: {}", new_profile);
|
||||
|
||||
// 获取目标配置文件路径
|
||||
let config_file_result = {
|
||||
let profiles_config = Config::profiles().await;
|
||||
let profiles_data = profiles_config.latest_ref();
|
||||
match profiles_data.get_item(new_profile) {
|
||||
Ok(item) => {
|
||||
if let Some(file) = &item.file {
|
||||
let path = dirs::app_profiles_dir().map(|dir| dir.join(file.as_str()));
|
||||
path.ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
logging!(error, Type::Cmd, "获取目标配置信息失败: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 如果获取到文件路径,检查YAML语法
|
||||
if let Some(file_path) = config_file_result {
|
||||
if !file_path.exists() {
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
"目标配置文件不存在: {}",
|
||||
file_path.display()
|
||||
);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_not_found",
|
||||
format!("{}", file_path.display()),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// 超时保护
|
||||
let file_read_result = tokio::time::timeout(
|
||||
Duration::from_secs(5),
|
||||
tokio::fs::read_to_string(&file_path),
|
||||
)
|
||||
.await;
|
||||
|
||||
match file_read_result {
|
||||
Ok(Ok(content)) => {
|
||||
let yaml_parse_result = AsyncHandler::spawn_blocking(move || {
|
||||
serde_yaml_ng::from_str::<serde_yaml_ng::Value>(&content)
|
||||
})
|
||||
.await;
|
||||
|
||||
match yaml_parse_result {
|
||||
Ok(Ok(_)) => {
|
||||
logging!(info, Type::Cmd, "目标配置文件语法正确");
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
let error_msg = format!(" {err}");
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
"目标配置文件存在YAML语法错误:{}",
|
||||
error_msg
|
||||
);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::yaml_syntax_error",
|
||||
error_msg.clone(),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
Err(join_err) => {
|
||||
let error_msg = format!("YAML解析任务失败: {join_err}");
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::yaml_parse_error",
|
||||
error_msg.clone(),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
let error_msg = format!("无法读取目标配置文件: {err}");
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_read_error",
|
||||
error_msg.clone(),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
Err(_) => {
|
||||
let error_msg = "读取配置文件超时(5秒)".to_string();
|
||||
logging!(error, Type::Cmd, "{}", error_msg);
|
||||
handle::Handle::notice_message(
|
||||
"config_validate::file_read_timeout",
|
||||
error_msg.clone(),
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// 检查请求有效性
|
||||
@@ -399,163 +552,7 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult<bool> {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// 为配置更新添加超时保护
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"开始内核配置更新,序列号: {}",
|
||||
current_sequence
|
||||
);
|
||||
let update_result = tokio::time::timeout(
|
||||
Duration::from_secs(30), // 30秒超时
|
||||
CoreManager::global().update_config(),
|
||||
)
|
||||
.await;
|
||||
|
||||
// 更新配置并进行验证
|
||||
match update_result {
|
||||
Ok(Ok((true, _))) => {
|
||||
// 内核操作完成后再次检查请求有效性
|
||||
let latest_sequence = CURRENT_REQUEST_SEQUENCE.load(Ordering::SeqCst);
|
||||
if current_sequence < latest_sequence {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"内核操作后发现更新的请求 (序列号: {} < {}),忽略当前结果",
|
||||
current_sequence,
|
||||
latest_sequence
|
||||
);
|
||||
Config::profiles().await.discard();
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"配置更新成功,序列号: {}",
|
||||
current_sequence
|
||||
);
|
||||
Config::profiles().await.apply();
|
||||
handle::Handle::refresh_clash();
|
||||
|
||||
// 强制刷新代理缓存,确保profile切换后立即获取最新节点数据
|
||||
// crate::process::AsyncHandler::spawn(|| async move {
|
||||
// if let Err(e) = super::proxy::force_refresh_proxies().await {
|
||||
// log::warn!(target: "app", "强制刷新代理缓存失败: {e}");
|
||||
// }
|
||||
// });
|
||||
|
||||
if let Err(e) = Tray::global().update_tooltip().await {
|
||||
log::warn!(target: "app", "异步更新托盘提示失败: {e}");
|
||||
}
|
||||
|
||||
if let Err(e) = Tray::global().update_menu().await {
|
||||
log::warn!(target: "app", "异步更新托盘菜单失败: {e}");
|
||||
}
|
||||
|
||||
// 保存配置文件
|
||||
if let Err(e) = profiles_save_file_safe().await {
|
||||
log::warn!(target: "app", "异步保存配置文件失败: {e}");
|
||||
}
|
||||
|
||||
// 立即通知前端配置变更
|
||||
if let Some(current) = ¤t_value {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"向前端发送配置变更事件: {}, 序列号: {}",
|
||||
current,
|
||||
current_sequence
|
||||
);
|
||||
handle::Handle::notify_profile_changed(current.clone());
|
||||
}
|
||||
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(true)
|
||||
}
|
||||
Ok(Ok((false, error_msg))) => {
|
||||
logging!(warn, Type::Cmd, "配置验证失败: {}", error_msg);
|
||||
Config::profiles().await.discard();
|
||||
// 如果验证失败,恢复到之前的配置
|
||||
if let Some(prev_profile) = current_profile {
|
||||
logging!(info, Type::Cmd, "尝试恢复到之前的配置: {}", prev_profile);
|
||||
let restore_profiles = IProfiles {
|
||||
current: Some(prev_profile),
|
||||
items: None,
|
||||
};
|
||||
// 静默恢复,不触发验证
|
||||
Config::profiles()
|
||||
.await
|
||||
.draft_mut()
|
||||
.patch_config(restore_profiles)
|
||||
.stringify_err()?;
|
||||
Config::profiles().await.apply();
|
||||
|
||||
crate::process::AsyncHandler::spawn(|| async move {
|
||||
if let Err(e) = profiles_save_file_safe().await {
|
||||
log::warn!(target: "app", "异步保存恢复配置文件失败: {e}");
|
||||
}
|
||||
});
|
||||
|
||||
logging!(info, Type::Cmd, "成功恢复到之前的配置");
|
||||
}
|
||||
|
||||
// 发送验证错误通知
|
||||
handle::Handle::notice_message("config_validate::error", error_msg.to_string());
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
logging!(
|
||||
warn,
|
||||
Type::Cmd,
|
||||
"更新过程发生错误: {}, 序列号: {}",
|
||||
e,
|
||||
current_sequence
|
||||
);
|
||||
Config::profiles().await.discard();
|
||||
handle::Handle::notice_message("config_validate::boot_error", e.to_string());
|
||||
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
Err(_) => {
|
||||
// 超时处理
|
||||
let timeout_msg = "配置更新超时(30秒),可能是配置验证或核心通信阻塞";
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
"{}, 序列号: {}",
|
||||
timeout_msg,
|
||||
current_sequence
|
||||
);
|
||||
Config::profiles().await.discard();
|
||||
|
||||
if let Some(prev_profile) = current_profile {
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
"超时后尝试恢复到之前的配置: {}, 序列号: {}",
|
||||
prev_profile,
|
||||
current_sequence
|
||||
);
|
||||
let restore_profiles = IProfiles {
|
||||
current: Some(prev_profile),
|
||||
items: None,
|
||||
};
|
||||
Config::profiles()
|
||||
.await
|
||||
.draft_mut()
|
||||
.patch_config(restore_profiles)
|
||||
.stringify_err()?;
|
||||
Config::profiles().await.apply();
|
||||
}
|
||||
|
||||
handle::Handle::notice_message("config_validate::timeout", timeout_msg);
|
||||
CURRENT_SWITCHING_PROFILE.store(false, Ordering::SeqCst);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
perform_config_update(current_sequence, current_value, current_profile).await
|
||||
}
|
||||
|
||||
/// 根据profile name修改profiles
|
||||
|
||||
@@ -12,7 +12,7 @@ async fn execute_service_operation_sync(status: ServiceStatus, op_type: &str) ->
|
||||
.await
|
||||
{
|
||||
let emsg = format!("{} Service failed: {}", op_type, e);
|
||||
return Err(t(emsg.as_str()).await.into());
|
||||
return Err(t(emsg.as_str()).await);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user