diff --git a/Changelog.md b/Changelog.md index 7c4b8dba2..997049c1e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ - 修复 首页 网站测速失败后卡片一直显示测试中 - 修复 代理 页展开分组后不显示最新测速结果,需切换节点才刷新 - 修复 代理 在全局模式下无法展开节点组 +- 修复恢复备份的同时修改配置,可能导致配置丢失或错乱的问题 **🐧 Linux** diff --git a/src-tauri/src/feat/backup.rs b/src-tauri/src/feat/backup.rs index 7c246d36a..38745f635 100644 --- a/src-tauri/src/feat/backup.rs +++ b/src-tauri/src/feat/backup.rs @@ -33,6 +33,9 @@ async fn finalize_restored_verge_config( webdav_username: Option, webdav_password: Option, ) -> Result<()> { + // The lock must cover every restored layer; an unlocked apply races a concurrently staged draft. + 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; @@ -43,43 +46,42 @@ async fn finalize_restored_verge_config( let restored_clash = IClashTemp::new().await; let clash_draft = Config::clash().await; clash_draft.edit_draft(|d| { - *d = restored_clash.clone(); + *d = restored_clash; }); clash_draft.apply(); let restored_profiles = IProfiles::new().await; let profiles_draft = Config::profiles().await; profiles_draft.edit_draft(|d| { - *d = restored_profiles.clone(); + *d = restored_profiles; }); 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() { - let result = async { - let _lifecycle = CoreManager::global().lifecycle_lock.lock().await; - proxy_control::apply().await?; - proxy_control::refresh_guard().await - } - .await; - if let Err(err) = result { - logging!(error, Type::Backup, "Failed to turn the system proxy off: {err:#}"); - if SystemProxyStateUnknown::is_in(&err) { - return Err(err); - } + // Turn it off here; a failing core side effect below would otherwise skip this step. + if !restored.enable_system_proxy.unwrap_or_default() { + let result = async { + let _lifecycle = CoreManager::global().lifecycle_lock.lock().await; + proxy_control::apply().await?; + proxy_control::refresh_guard().await + } + .await; + if let Err(err) = result { + logging!(error, Type::Backup, "Failed to turn the system proxy off: {err:#}"); + if SystemProxyStateUnknown::is_in(&err) { + return Err(err); } } } + // `patch_verge` re-acquires the lock through `try_lock_config_write`. + 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:#}");