diff --git a/src-tauri/src/feat/backup.rs b/src-tauri/src/feat/backup.rs index df2e42395..11f82f78b 100644 --- a/src-tauri/src/feat/backup.rs +++ b/src-tauri/src/feat/backup.rs @@ -33,6 +33,8 @@ async fn finalize_restored_verge_config( webdav_username: Option, webdav_password: Option, ) -> Result<()> { + let config_write = Config::lock_config_write().await; + // A broken restored `verge.yaml` is a restore failure, not a reason to load defaults. let mut restored = help::read_yaml::(&verge_path()?).await?; restored.webdav_url = webdav_url; @@ -55,14 +57,10 @@ async fn finalize_restored_verge_config( profiles_draft.apply(); let verge_draft = Config::verge().await; - { - // Hold the write lock so a concurrent patch cannot stage a draft the proxy write reads. - let _config_write = Config::lock_config_write().await; - verge_draft.edit_draft(|d| { - *d = restored.clone(); - }); - verge_draft.apply(); - } + verge_draft.edit_draft(|d| { + *d = restored.clone(); + }); + verge_draft.apply(); // Turn it off here; a failing core side effect below would otherwise skip this step. if !restored.enable_system_proxy.unwrap_or_default() { @@ -80,6 +78,9 @@ async fn finalize_restored_verge_config( } } + // `patch_verge` re-acquires the configuration write lock. + drop(config_write); + // Run configuration side effects without rewriting the already-restored file. if let Err(err) = super::patch_verge(&restored, true).await { logging!(error, Type::Backup, "Failed to apply restored verge config: {err:#}"); @@ -145,10 +146,17 @@ async fn restore_backup_archive(path: PathBuf) -> Result<()> { ) }; - let file = AsyncHandler::spawn_blocking(move || std::fs::File::open(&path)).await??; - let mut zip = zip::ZipArchive::new(file)?; + let home_dir = app_home_dir()?; + AsyncHandler::spawn_blocking(move || -> Result<()> { + let file = std::fs::File::open(&path)?; + let mut zip = zip::ZipArchive::new(file)?; + zip.extract(&home_dir)?; + Ok(()) + }) + .await + .map_err(|join| anyhow!("backup extraction task failed: {join}"))??; + let _profile_write = crate::config::profiles::PROFILE_WRITE_LOCK.lock().await; - zip.extract(app_home_dir()?)?; finalize_restored_verge_config(webdav_url, webdav_username, webdav_password).await } diff --git a/src-tauri/src/feat/clash.rs b/src-tauri/src/feat/clash.rs index 9b1d84b3c..6fdcb681c 100644 --- a/src-tauri/src/feat/clash.rs +++ b/src-tauri/src/feat/clash.rs @@ -67,11 +67,13 @@ pub async fn change_clash_mode(mode: String) -> Result<(), String> { } let clash = Config::clash().await; - clash.edit_draft(|d| d.patch_config(&mapping)); - clash.apply(); - - let clash_data = clash.data_arc(); - if clash_data.save_config().await.is_ok() { + let save_result = { + let _config_write = Config::lock_config_write().await; + clash.edit_draft(|d| d.patch_config(&mapping)); + clash.apply(); + clash.data_arc().save_config().await + }; + if save_result.is_ok() { announce(Refresh::Clash); tray::Tray::global().update_menu_and_icon().await; }