* feat: replace all tokio::spawn with unified AsyncHandler::spawn - 🚀 Core Improvements: * Replace all tokio::spawn calls with AsyncHandler::spawn for unified Tauri async task management * Prioritize converting sync functions to async functions to reduce spawn usage * Use .await directly in async contexts instead of spawn - 🔧 Major Changes: * core/hotkey.rs: Use AsyncHandler::spawn for hotkey callback functions * module/lightweight.rs: Async lightweight mode switching * feat/window.rs: Convert window operation functions to async, use .await internally * feat/proxy.rs, feat/clash.rs: Async proxy and mode switching functions * lib.rs: Window focus handling with AsyncHandler::spawn * core/tray/mod.rs: Complete async tray event handling - ✨ Technical Advantages: * Unified task tracking and debugging capabilities (via tokio-trace feature) * Better error handling and task management * Consistency with Tauri runtime * Reduced async boundaries for better performance - 🧪 Verification: * Compilation successful with 0 errors, 0 warnings * Maintains complete original functionality * Optimized async execution flow * feat: complete tokio fs migration and replace tokio::spawn with AsyncHandler 🚀 Major achievements: - Migrate 8 core modules from std::fs to tokio::fs - Create 6 Send-safe wrapper functions using spawn_blocking pattern - Replace all tokio::spawn calls with AsyncHandler::spawn for unified async task management - Solve all 19 Send trait compilation errors through innovative spawn_blocking architecture 🔧 Core changes: - config/profiles.rs: Add profiles_*_safe functions to handle Send trait constraints - cmd/profile.rs: Update all Tauri commands to use Send-safe operations - config/prfitem.rs: Replace append_item calls with profiles_append_item_safe - utils/help.rs: Convert YAML operations to async (read_yaml, save_yaml) - Multiple modules: Replace tokio::task::spawn_blocking with AsyncHandler::spawn_blocking ✅ Technical innovations: - spawn_blocking wrapper pattern resolves parking_lot RwLock Send trait conflicts - Maintain parking_lot performance while achieving Tauri async command compatibility - Preserve backwards compatibility with gradual migration strategy 🎯 Results: - Zero compilation errors - Zero warnings - All async file operations working correctly - Complete Send trait compliance for Tauri commands * feat: refactor app handle and command functions to use async/await for improved performance * feat: update async handling in profiles and logging functions for improved error handling and performance * fix: update TRACE_MINI_SIZE constant to improve task logging threshold * fix(windows): convert service management functions to async for improved performance * fix: convert service management functions to async for improved responsiveness * fix(ubuntu): convert install and reinstall service functions to async for improved performance * fix(linux): convert uninstall_service function to async for improved performance * fix: convert uninstall_service call to async for improved performance * fix: convert file and directory creation calls to async for improved performance * fix: convert hotkey functions to async for improved responsiveness * chore: update UPDATELOG.md for v2.4.1 with major improvements and performance optimizations
185 lines
6.4 KiB
Rust
185 lines
6.4 KiB
Rust
use super::CmdResult;
|
||
use crate::{
|
||
config::*,
|
||
core::*,
|
||
logging,
|
||
utils::{dirs, logging::Type},
|
||
wrap_err,
|
||
};
|
||
use tokio::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().await;
|
||
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)
|
||
};
|
||
|
||
// 保存新的配置文件
|
||
let file_data = file_data.ok_or("file_data is None")?;
|
||
wrap_err!(fs::write(&file_path, &file_data).await)?;
|
||
|
||
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).await)?;
|
||
// 发送合并文件专用错误通知
|
||
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).await)?;
|
||
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).await)?;
|
||
|
||
// 智能判断错误类型
|
||
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通知处理
|
||
logging!(
|
||
info,
|
||
Type::Config,
|
||
"[cmd配置save] YAML配置文件验证失败,发送通知"
|
||
);
|
||
let result = (false, error_msg.clone());
|
||
crate::cmd::validate::handle_yaml_validation_notice(&result, "YAML配置文件");
|
||
} else if is_script_error {
|
||
// 脚本错误使用专门的通知处理
|
||
logging!(
|
||
info,
|
||
Type::Config,
|
||
"[cmd配置save] 脚本文件验证失败,发送通知"
|
||
);
|
||
let result = (false, error_msg.clone());
|
||
crate::cmd::validate::handle_script_validation_notice(&result, "脚本文件");
|
||
} else {
|
||
// 普通配置错误使用一般通知
|
||
logging!(
|
||
info,
|
||
Type::Config,
|
||
"[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).await)?;
|
||
Err(e.to_string())
|
||
}
|
||
}
|
||
}
|