From 795082066e97be23a7b7a049e77dd4d2351a4db2 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Tue, 30 Jun 2026 00:50:58 +0800 Subject: [PATCH] =?UTF-8?q?fix(client):=20=E5=88=B7=E6=96=B0=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=88=97=E8=A1=A8=E6=97=B6=E4=BF=9D=E7=95=99=E5=B7=B2?= =?UTF-8?q?=E6=9C=89=20ping,=E4=BF=AE=E5=BB=B6=E8=BF=9F=E8=A2=AB=20refresh?= =?UTF-8?q?=20=E6=B8=85=E6=88=90=20=E2=80=94=20=E7=9A=84=E6=A0=B9=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 日志实证:urltest 回写正常(best=561ms→setLivePing),但看门狗/节点页每15s refresh() 重拉服务端列表、解析时 ping=0(占位),state=result 把刚写进去的延迟清零 → 显示 —, 下一帧 setLivePing 又写回 → 来回闪。修:refresh 用 _mergePings 按 uuid 保留已有 ping (ping 是客户端实测,服务端列表不带)。去掉诊断日志。 Co-Authored-By: Claude Opus 4.8 --- client/lib/state/connection_provider.dart | 11 +---------- client/lib/state/nodes_provider.dart | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/client/lib/state/connection_provider.dart b/client/lib/state/connection_provider.dart index 9b758e8..da31aa8 100644 --- a/client/lib/state/connection_provider.dart +++ b/client/lib/state/connection_provider.dart @@ -87,7 +87,6 @@ class ConnectionController extends StateNotifier { Timer? _elapsed; Timer? _watchdog; bool _probing = false; - int _statsTick = 0; // 仅诊断:_onStats 限频打日志 // 本次 off 的提示语(节点异常/自动切换);kernel off 与显式断开都读它,避免被互相覆盖。 // 仅 _connect 开始时清空。用户主动断开则保持 null(无提示)。 String? _offNotice; @@ -233,16 +232,8 @@ class ConnectionController extends StateNotifier { final node = _connectedNode; if (node == null || node.uuid.isEmpty) return; final ds = e.urltestResults.where((r) => r.delayMs > 0).map((r) => r.delayMs); - if (ds.isEmpty) { - // 诊断:urltest 为空(每 ~10 帧打一次,免刷屏)。 - if (_statsTick++ % 10 == 0) { - logLine('Latency', - 'urltest empty: rawResults=${e.urltestResults.length} node=${node.code} nodePing=${node.ping}'); - } - return; - } + if (ds.isEmpty) return; final best = ds.reduce((a, b) => a < b ? a : b); - if (_statsTick++ % 10 == 0) logLine('Latency', 'urltest best=${best}ms → setLivePing ${node.code}'); _ref.read(nodesProvider.notifier).setLivePing(node.uuid, best); } diff --git a/client/lib/state/nodes_provider.dart b/client/lib/state/nodes_provider.dart index 92f29c6..44e1071 100644 --- a/client/lib/state/nodes_provider.dart +++ b/client/lib/state/nodes_provider.dart @@ -46,7 +46,9 @@ class NodesNotifier extends AsyncNotifier> { return; // 限流:10s 内不重复请求远端 } final result = await AsyncValue.guard(() async { - final list = await _fetchNodes(auth.accessToken!); + // ping 是客户端实测(direct TCP / 连接态 urltest 回写),服务端列表不带它(渲染为 0)。 + // 刷新时保留已有 ping,否则会把刚测/回写的延迟清成 0 → 连接页延迟闪成 —。 + final list = _mergePings(await _fetchNodes(auth.accessToken!)); _lastFetch = DateTime.now(); unawaited(_measure(list)); return list; @@ -55,6 +57,17 @@ class NodesNotifier extends AsyncNotifier> { if (result.hasValue) state = result; // 成功才换;失败保留旧列表 } + /// 用当前 state 里各节点已有的 ping 回填新拉到的列表(按 uuid;已有>0 才覆盖占位 0)。 + List _mergePings(List fresh) { + final cur = state.valueOrNull; + if (cur == null) return fresh; + final byUuid = {for (final n in cur) n.uuid: n.ping}; + return [ + for (final n in fresh) + (byUuid[n.uuid] ?? 0) > 0 ? n.copyWith(ping: byUuid[n.uuid]!) : n + ]; + } + /// 回写某节点的实测延迟(ms)。连接态由 ConnectionController 用内核 urltest 回填连接节点, /// 让「连接页延迟」与「节点列表延迟」同源(都读 node.ping)、显示一致。ms<=0 忽略。 void setLivePing(String uuid, int ms) {