refactor: restructure async initialization and standardize logging system

### Major Improvements

- **Async initialization refactoring**: Complete async migration of init_config, improving app startup performance and stability
  - Change init_work_config from blocking to async execution
  - Optimize error handling for directory creation and config file initialization
  - Enhance structure and robustness of initialization process

- **Logging system standardization**: Unify usage of project's built-in logging! macro
  - Replace all log::info!/warn!/error!/debug! with logging!(level, Type::Setup, true, ...) format
  - Maintain consistency in log categorization and formatting
  - Improve convenience for log tracking and debugging

### Technical Optimizations

- **Error handling improvements**: Remove crate::log_err! macro, use standard Result error propagation
- **Directory management optimization**: Refactor ensure_directories function with clearer directory creation logic
- **Config initialization enhancement**: Separate initialize_config_files function for better code maintainability
- **Async task management**: Use AsyncHandler::spawn to optimize background log cleanup tasks

### Bug Fixes

- Fix potential race conditions in async config initialization
- Improve error feedback and logging during app startup
- Enhance error handling for DNS config and resource file initialization

### Updates

- Update wording in UPDATELOG.md issue descriptions
This commit is contained in:
Tunglies
2025-08-30 17:58:26 +08:00
Unverified
parent 3a7be3dfb7
commit c09066c0a3
3 changed files with 145 additions and 40 deletions

View File

@@ -25,7 +25,8 @@
- 修复订阅在某些情况下无法导入
- 修复无法新建订阅时使用远程链接
- 修复卸载服务后的 tun 开关状态问题
- 改善页面快速切换订阅时导致崩溃
- 修复页面快速切换订阅时导致崩溃
- 修复丢失工作目录时无法恢复环境
### 👙 界面样式

View File

@@ -1,7 +1,9 @@
use crate::{
config::*,
core::handle,
utils::{dirs, help},
logging,
process::AsyncHandler,
utils::{dirs, help, logging::Type},
};
use anyhow::Result;
use chrono::{Local, TimeZone};
@@ -85,7 +87,13 @@ pub async fn delete_log() -> Result<()> {
_ => return Ok(()),
};
log::info!(target: "app", "try to delete log files, day: {day}");
logging!(
info,
Type::Setup,
true,
"try to delete log files, day: {}",
day
);
// %Y-%m-%d to NaiveDateTime
let parse_time_str = |s: &str| {
@@ -120,7 +128,7 @@ pub async fn delete_log() -> Result<()> {
if duration.num_days() > day {
let file_path = file.path();
let _ = fs::remove_file(file_path).await;
log::info!(target: "app", "delete log file: {file_name}");
logging!(info, Type::Setup, true, "delete log file: {}", file_name);
}
}
Ok(())
@@ -247,7 +255,7 @@ async fn init_dns_config() -> Result<()> {
let dns_path = app_dir.join("dns_config.yaml");
if !dns_path.exists() {
log::info!(target: "app", "Creating default DNS config file");
logging!(info, Type::Setup, true, "Creating default DNS config file");
help::save_yaml(
&dns_path,
&default_dns_config,
@@ -259,54 +267,120 @@ async fn init_dns_config() -> Result<()> {
Ok(())
}
/// Initialize all the config files
/// before tauri setup
pub async fn init_config() -> Result<()> {
let _ = dirs::init_portable_flag();
let _ = init_log().await;
let _ = delete_log().await;
/// 确保目录结构存在
async fn ensure_directories() -> Result<()> {
let directories = [
("app_home", dirs::app_home_dir()?),
("app_profiles", dirs::app_profiles_dir()?),
("app_logs", dirs::app_logs_dir()?),
];
crate::log_err!(dirs::app_home_dir().map(|app_dir| async move {
if !app_dir.exists() {
std::mem::drop(fs::create_dir_all(&app_dir).await);
for (name, dir) in directories {
if !dir.exists() {
fs::create_dir_all(&dir).await.map_err(|e| {
anyhow::anyhow!("Failed to create {} directory {:?}: {}", name, dir, e)
})?;
logging!(
info,
Type::Setup,
true,
"Created {} directory: {:?}",
name,
dir
);
}
}));
}
crate::log_err!(dirs::app_profiles_dir().map(|profiles_dir| async move {
if !profiles_dir.exists() {
std::mem::drop(fs::create_dir_all(&profiles_dir).await);
}
}));
Ok(())
}
/// 初始化配置文件
async fn initialize_config_files() -> Result<()> {
if let Ok(path) = dirs::clash_path() {
if !path.exists() {
let result =
help::save_yaml(&path, &IClashTemp::template().0, Some("# Clash Vergeasu")).await;
crate::log_err!(result);
let template = IClashTemp::template().0;
help::save_yaml(&path, &template, Some("# Clash Verge"))
.await
.map_err(|e| anyhow::anyhow!("Failed to create clash config: {}", e))?;
logging!(
info,
Type::Setup,
true,
"Created clash config at {:?}",
path
);
}
}
if let Ok(path) = dirs::verge_path() {
if !path.exists() {
let result = help::save_yaml(&path, &IVerge::template(), Some("# Clash Verge")).await;
crate::log_err!(result);
let template = IVerge::template();
help::save_yaml(&path, &template, Some("# Clash Verge"))
.await
.map_err(|e| anyhow::anyhow!("Failed to create verge config: {}", e))?;
logging!(
info,
Type::Setup,
true,
"Created verge config at {:?}",
path
);
}
}
// 验证并修正verge.yaml中的clash_core配置
let result = IVerge::validate_and_fix_config().await;
crate::log_err!(result);
if let Ok(path) = dirs::profiles_path() {
if !path.exists() {
let result =
help::save_yaml(&path, &IProfiles::template(), Some("# Clash Verge")).await;
crate::log_err!(result);
let template = IProfiles::template();
help::save_yaml(&path, &template, Some("# Clash Verge"))
.await
.map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?;
logging!(
info,
Type::Setup,
true,
"Created profiles config at {:?}",
path
);
}
}
// 初始化DNS配置文件
let _ = init_dns_config().await;
// 验证并修正verge配置
IVerge::validate_and_fix_config()
.await
.map_err(|e| anyhow::anyhow!("Failed to validate verge config: {}", e))?;
Ok(())
}
/// Initialize all the config files
/// before tauri setup
pub async fn init_config() -> Result<()> {
let _ = dirs::init_portable_flag();
if let Err(e) = init_log().await {
eprintln!("Failed to initialize logging: {}", e);
}
ensure_directories().await?;
initialize_config_files().await?;
AsyncHandler::spawn(|| async {
if let Err(e) = delete_log().await {
logging!(warn, Type::Setup, true, "Failed to clean old logs: {}", e);
}
logging!(info, Type::Setup, true, "后台日志清理任务完成");
});
if let Err(e) = init_dns_config().await {
logging!(
warn,
Type::Setup,
true,
"DNS config initialization failed: {}",
e
);
}
Ok(())
}
@@ -331,13 +405,30 @@ pub async fn init_resources() -> Result<()> {
for file in file_list.iter() {
let src_path = res_dir.join(file);
let dest_path = app_dir.join(file);
log::debug!(target: "app", "src_path: {src_path:?}, dest_path: {dest_path:?}");
logging!(
debug,
Type::Setup,
true,
"src_path: {:?}, dest_path: {:?}",
src_path,
dest_path
);
let handle_copy = |src: PathBuf, dest: PathBuf, file: String| async move {
match fs::copy(&src, &dest).await {
Ok(_) => log::debug!(target: "app", "resources copied '{file}'"),
Ok(_) => {
logging!(debug, Type::Setup, true, "resources copied '{}'", file);
}
Err(err) => {
log::error!(target: "app", "failed to copy resources '{file}' to '{dest:?}', {err}")
logging!(
error,
Type::Setup,
true,
"failed to copy resources '{}' to '{:?}', {}",
file,
dest,
err
);
}
};
};
@@ -355,11 +446,23 @@ pub async fn init_resources() -> Result<()> {
if src_modified > dest_modified {
handle_copy(src_path.clone(), dest_path.clone(), file.to_string()).await;
} else {
log::debug!(target: "app", "skipping resource copy '{file}'");
logging!(
debug,
Type::Setup,
true,
"skipping resource copy '{}'",
file
);
}
}
_ => {
log::debug!(target: "app", "failed to get modified '{file}'");
logging!(
debug,
Type::Setup,
true,
"failed to get modified '{}'",
file
);
handle_copy(src_path.clone(), dest_path.clone(), file.to_string()).await;
}
};

View File

@@ -33,9 +33,10 @@ pub fn resolve_setup_async() {
std::thread::current().id()
);
AsyncHandler::spawn_blocking(|| AsyncHandler::block_on(init_work_config()));
// AsyncHandler::spawn_blocking(|| AsyncHandler::block_on(init_work_config()));
AsyncHandler::spawn(|| async {
init_work_config().await;
init_resources().await;
init_startup_script().await;