fix(client): 刷新节点列表时保留已有 ping,修延迟被 refresh 清成 — 的根因
日志实证:urltest 回写正常(best=561ms→setLivePing),但看门狗/节点页每15s refresh() 重拉服务端列表、解析时 ping=0(占位),state=result 把刚写进去的延迟清零 → 显示 —, 下一帧 setLivePing 又写回 → 来回闪。修:refresh 用 _mergePings 按 uuid 保留已有 ping (ping 是客户端实测,服务端列表不带)。去掉诊断日志。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -87,7 +87,6 @@ class ConnectionController extends StateNotifier<ConnectionState> {
|
||||
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<ConnectionState> {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,9 @@ class NodesNotifier extends AsyncNotifier<List<Node>> {
|
||||
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<List<Node>> {
|
||||
if (result.hasValue) state = result; // 成功才换;失败保留旧列表
|
||||
}
|
||||
|
||||
/// 用当前 state 里各节点已有的 ping 回填新拉到的列表(按 uuid;已有>0 才覆盖占位 0)。
|
||||
List<Node> _mergePings(List<Node> 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) {
|
||||
|
||||
Reference in New Issue
Block a user