fix(config): stop rewriting unchanged configs on exit (#8017)

* fix(config): stop rewriting unchanged configs on exit

apply_all_and_save_file() committed the drafts and then saved clash.yaml,
verge.yaml and profiles.yaml unconditionally. With nothing staged that write
replaced each file with content equal to what was already on disk - fields are
encrypted with a fresh nonce, so the bytes differ every time - which reset the
files' creation time on every exit (#7759).

Draft::apply now reports whether it committed a draft, and the exit path saves
only the configs that had one.

* refactor(tests): remove test snippets

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>

* docs(changelog): add entry of the PR modifications

Assisted-by: Gemini 3.8 Flash Medium (VSCode Copilot Chat)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>

---------

Signed-off-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
Co-authored-by: sdhfsl <sdhfsl@users.noreply.github.com>
Co-authored-by: ❤是纱雾酱哟~ <49941141+Dragon1573@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
sdhfsl
2026-11-11 17:33:03 +00:00
committed by GitHub
co-authored by Copilot sdhfsl ❤是纱雾酱哟~
parent 2c60f55f45
commit 4adac9e4b6
3 changed files with 20 additions and 10 deletions
+2
View File
@@ -24,6 +24,8 @@
<details>
<summary><strong> 🐞 修复问题 </strong></summary>
- 修复应用退出时无条件重写 `clash.yaml`、`verge.yaml` 和 `profiles.yaml` 导致文件创建时间丢失的问题
- 修复检测更新后又发布新版时,应用内更新失败
- 修复订阅响应过大导致内存占用过高,限制单次下载为 4 MiB
- 修复全局模式默认停在 `DIRECT` 或 `REJECT` 导致流量未经代理,现自动切换到第一个策略组
+8 -4
View File
@@ -74,12 +74,16 @@ impl<T: Clone> Draft<T> {
result
}
/// Commits and clears the draft.
/// Commits and clears the draft, reporting whether one was staged.
#[inline]
pub fn apply(&self) {
pub fn apply(&self) -> bool {
let mut guard = self.inner.data.lock();
if let Some(d) = guard.1.take() {
guard.0 = d;
match guard.1.take() {
Some(d) => {
guard.0 = d;
true
}
None => false,
}
}
+10 -6
View File
@@ -280,25 +280,29 @@ impl Config {
}
/// Commits drafts during exit/restart/shutdown so user changes are not lost.
/// A config with nothing staged keeps its file, so its timestamps stay put.
pub async fn apply_all_and_save_file() {
logging!(debug, Type::Config, "save all draft data");
let save_clash_task = AsyncHandler::spawn(|| async {
let clash = Self::clash().await;
clash.apply();
logging_error!(Type::Config, clash.data_arc().save_config().await);
if clash.apply() {
logging_error!(Type::Config, clash.data_arc().save_config().await);
}
});
let save_verge_task = AsyncHandler::spawn(|| async {
let verge = Self::verge().await;
verge.apply();
logging_error!(Type::Config, verge.data_arc().save_file().await);
if verge.apply() {
logging_error!(Type::Config, verge.data_arc().save_file().await);
}
});
let save_profiles_task = AsyncHandler::spawn(|| async {
let _profile_write = super::profiles::PROFILE_WRITE_LOCK.lock().await;
let profiles = Self::profiles().await;
profiles.apply();
logging_error!(Type::Config, profiles.data_arc().save_file().await);
if profiles.apply() {
logging_error!(Type::Config, profiles.data_arc().save_file().await);
}
});
let _ = tokio::join!(save_clash_task, save_verge_task, save_profiles_task);