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
parent 3a7be3dfb7
commit c09066c0a3
3 changed files with 145 additions and 40 deletions

View File

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

View File

@@ -1,7 +1,9 @@
use crate::{ use crate::{
config::*, config::*,
core::handle, core::handle,
utils::{dirs, help}, logging,
process::AsyncHandler,
utils::{dirs, help, logging::Type},
}; };
use anyhow::Result; use anyhow::Result;
use chrono::{Local, TimeZone}; use chrono::{Local, TimeZone};
@@ -85,7 +87,13 @@ pub async fn delete_log() -> Result<()> {
_ => return Ok(()), _ => 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 // %Y-%m-%d to NaiveDateTime
let parse_time_str = |s: &str| { let parse_time_str = |s: &str| {
@@ -120,7 +128,7 @@ pub async fn delete_log() -> Result<()> {
if duration.num_days() > day { if duration.num_days() > day {
let file_path = file.path(); let file_path = file.path();
let _ = fs::remove_file(file_path).await; 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(()) Ok(())
@@ -247,7 +255,7 @@ async fn init_dns_config() -> Result<()> {
let dns_path = app_dir.join("dns_config.yaml"); let dns_path = app_dir.join("dns_config.yaml");
if !dns_path.exists() { 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( help::save_yaml(
&dns_path, &dns_path,
&default_dns_config, &default_dns_config,
@@ -259,54 +267,120 @@ async fn init_dns_config() -> Result<()> {
Ok(()) Ok(())
} }
/// Initialize all the config files /// 确保目录结构存在
/// before tauri setup async fn ensure_directories() -> Result<()> {
pub async fn init_config() -> Result<()> { let directories = [
let _ = dirs::init_portable_flag(); ("app_home", dirs::app_home_dir()?),
let _ = init_log().await; ("app_profiles", dirs::app_profiles_dir()?),
let _ = delete_log().await; ("app_logs", dirs::app_logs_dir()?),
];
crate::log_err!(dirs::app_home_dir().map(|app_dir| async move { for (name, dir) in directories {
if !app_dir.exists() { if !dir.exists() {
std::mem::drop(fs::create_dir_all(&app_dir).await); 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 { Ok(())
if !profiles_dir.exists() { }
std::mem::drop(fs::create_dir_all(&profiles_dir).await);
}
}));
/// 初始化配置文件
async fn initialize_config_files() -> Result<()> {
if let Ok(path) = dirs::clash_path() { if let Ok(path) = dirs::clash_path() {
if !path.exists() { if !path.exists() {
let result = let template = IClashTemp::template().0;
help::save_yaml(&path, &IClashTemp::template().0, Some("# Clash Vergeasu")).await; help::save_yaml(&path, &template, Some("# Clash Verge"))
crate::log_err!(result); .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 let Ok(path) = dirs::verge_path() {
if !path.exists() { if !path.exists() {
let result = help::save_yaml(&path, &IVerge::template(), Some("# Clash Verge")).await; let template = IVerge::template();
crate::log_err!(result); 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 let Ok(path) = dirs::profiles_path() {
if !path.exists() { if !path.exists() {
let result = let template = IProfiles::template();
help::save_yaml(&path, &IProfiles::template(), Some("# Clash Verge")).await; help::save_yaml(&path, &template, Some("# Clash Verge"))
crate::log_err!(result); .await
.map_err(|e| anyhow::anyhow!("Failed to create profiles config: {}", e))?;
logging!(
info,
Type::Setup,
true,
"Created profiles config at {:?}",
path
);
} }
} }
// 初始化DNS配置文件 // 验证并修正verge配置
let _ = init_dns_config().await; 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(()) Ok(())
} }
@@ -331,13 +405,30 @@ pub async fn init_resources() -> Result<()> {
for file in file_list.iter() { for file in file_list.iter() {
let src_path = res_dir.join(file); let src_path = res_dir.join(file);
let dest_path = app_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 { let handle_copy = |src: PathBuf, dest: PathBuf, file: String| async move {
match fs::copy(&src, &dest).await { 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) => { 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 { if src_modified > dest_modified {
handle_copy(src_path.clone(), dest_path.clone(), file.to_string()).await; handle_copy(src_path.clone(), dest_path.clone(), file.to_string()).await;
} else { } 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; 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() 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 { AsyncHandler::spawn(|| async {
init_work_config().await;
init_resources().await; init_resources().await;
init_startup_script().await; init_startup_script().await;