fix(proxy): tighten takeover detection and use fallback restore on disable

Two related drift bugs in the takeover state machine:

1. The "already taken over?" guard used has_backup OR live_taken_over, so
   either condition alone would short-circuit. After a user or anomalous
   flow restores Live manually the backup row still made set_takeover
   return success, leaving the UI claiming takeover while requests bypass
   the local proxy. Tighten to AND so the rebuild branch repairs the two
   "split brain" states (backup-only and placeholder-only).

2. Disabling takeover called the bare restore_live_config_for_app, which
   silently Ok()s when the backup is missing. If the backup was lost while
   Live still held proxy placeholders (PROXY_MANAGED token / local proxy
   URL), the client config was left broken with no error surfaced. Route
   the disable path through the already-existing
   restore_live_config_for_app_with_fallback (backup → SSOT → cleanup).
   The line 354 takeover-failure rollback intentionally keeps the bare
   variant since that path must preserve the backup for retry.
This commit is contained in:
Jason
2026-05-13 23:12:15 +08:00
Unverified
parent 9a8f52021d
commit c3d810a22b
+10 -3
View File
@@ -327,12 +327,15 @@ impl ProxyService {
};
let live_taken_over = self.detect_takeover_in_live_config_for_app(&app);
if has_backup || live_taken_over {
// 必须 backup AND live 占位符同时存在才算真接管。
// 只看其一会出现「UI 显示已接管但 Live 已被恢复」或「Live 仍是占位符但备份丢失」
// 两种脏角落,下面的重建分支会把这些情况修复成一致状态。
if has_backup && live_taken_over {
return Ok(());
}
log::warn!(
"{app_type_str} 标记为已接管,但缺少备份或占位符,正在重新接管并补齐备份"
"{app_type_str} 标记为已接管,但 backup={has_backup} live_taken_over={live_taken_over},正在重新接管并补齐备份"
);
}
@@ -411,7 +414,11 @@ impl ProxyService {
}
// 1) 恢复 Live 配置
self.restore_live_config_for_app(&app).await?;
//
// 必须走 with_fallback 版本:备份 → SSOT → 清理占位符 的三层兜底。
// 简版 restore_live_config_for_app 在备份缺失时会静默 Ok(()),
// 留下接管时写入的占位符(代理地址/PROXY_MANAGED token),客户端无法工作。
self.restore_live_config_for_app_with_fallback(&app).await?;
// 2) 删除该 app 的备份(避免长期存储敏感 Token)
self.db