fix(client): 看门狗 path A 仅在「连上(on)后掉线」触发,排除 connecting 握手瞬态

macOS NE 连接序列是 off→connecting→off→connecting→on,connecting 期有瞬态 off。原 path A
条件 wasActive 含 connecting → 一连接就在握手瞬态 off 上误报「节点异常」(实际连上了)。
改:仅 phase==on(真正连上过)再非用户主动掉线才判节点异常;connecting→off(握手抖动/
连接失败)不触发。跨端修复(桌面也更稳)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-30 07:01:13 +08:00
parent 48bc5c6b39
commit 7f070a0693
+6 -5
View File
@@ -216,12 +216,13 @@ class ConnectionController extends StateNotifier<ConnectionState> {
_stopWatchdog();
case VpnStatus.off:
case VpnStatus.error:
final wasActive = state.phase == VpnPhase.on || state.phase == VpnPhase.connecting;
// 路径 A:非用户主动、且本来在连/已连 → 节点数据面死导致的意外掉线。
// 给原因(节点异常)+ 刷节点列表让服务端 down 浮现。_offNotice 让显式断开与本回调统一
if (!_userDisconnect && wasActive && _offNotice == null) {
// 路径 A:仅「真正连上过(on)再非用户主动掉线」才判节点异常(数据面死/REALITY 断)。
// 必须排除 connecting 握手期的瞬态 off——macOS NE 连接序列是 off→connecting→off→
// connecting→on,connecting 期的 off 是握手抖动、不是异常(否则一连接就误报「节点异常」)
final wasConnected = state.phase == VpnPhase.on;
if (!_userDisconnect && wasConnected && _offNotice == null) {
_offNotice = _ref.read(appTextProvider).nodeUnhealthyError;
logLine('Watchdog', 'unexpected kernel ${s.name} while $wasActive → node interrupted');
logLine('Watchdog', 'unexpected kernel ${s.name} after connected → node interrupted');
unawaited(_ref.read(nodesProvider.notifier).refresh());
}
state = ConnectionState(phase: VpnPhase.off, error: _offNotice);