fix(clash): take config write lock when changing mode

change_clash_mode committed the clash draft and saved config.yaml without
claiming CONFIG_WRITE_LOCK, so a concurrent patch_clash transaction could
have its staged draft committed here or its file-snapshot rollback swallow
the mode change. Take lock_config_write (waiting) rather than
try_lock_config_write: two of the three callers (hotkey, tray) discard the
result, so fail-fast would silently drop the switch, and the lock is only
attempted after the mihomo patch already applied, where an Err would roll
the frontend back while the core runs the new mode.
This commit is contained in:
Tunglies
2026-10-27 22:40:33 +08:00
parent 3a892043c4
commit c5dcef6f1e
2 changed files with 9 additions and 5 deletions
+1
View File
@@ -9,6 +9,7 @@
- 修复 代理 页展开分组后不显示最新测速结果,需切换节点才刷新
- 修复 代理 在全局模式下无法展开节点组
- 修复恢复备份的同时修改配置,可能导致配置丢失或错乱的问题
- 修复切换规则模式与配置变更并发时可能丢失或错乱的问题
**🐧 Linux**
+8 -5
View File
@@ -67,11 +67,14 @@ 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() {
// Serialize with patch transactions: an unlocked commit can flush a staged draft mid-rollback.
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;
}