fix(client): 看门狗返工 — 意外掉线捕获+服务端down轮询,撤销TUN下假阳性的TCP探测

测试暴露:全局TUN下App的socket到节点IP被本地TUN当场接住(假1ms),客户端TCP探数据口
不可行;且节点死时内核先掉线、提示被kernel off覆盖、节点页status不刷新显示绿色。返工:
- 撤销 DataPlaneProber/livePingMs;延迟改回内核urltest(sing-box经REALITY真实直连数据面
  探出的RTT,唯一可靠口径),连接态urltest=0→显示—不回退旧ping。
- 看门狗两条可靠路径:A 捕获「非用户主动的内核掉线」→置「节点异常」+刷列表;
  B 连接态周期刷/v1/nodes,所连节点被判down→智能切/手动断。
- _offNotice 让显式断开与kernel off读同一提示字段,不再互相覆盖(修「断开但没报错」)。
- 节点页周期15s刷新,让服务端down状态浮现(tile已按isDown置灰)。
返工测试:意外掉线提示/服务端down切/断/健康保持,全过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-29 23:21:09 +08:00
parent cd143af248
commit d9378b6729
4 changed files with 142 additions and 152 deletions
+13
View File
@@ -1,4 +1,6 @@
// nodes_page.dart — 节点页(置顶智能选择推荐卡 + 搜索 + 列表/双列网格)
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -27,6 +29,7 @@ class NodesPage extends ConsumerStatefulWidget {
class _NodesPageState extends ConsumerState<NodesPage> {
String _q = '';
bool _refreshing = false;
Timer? _poll;
@override
void initState() {
@@ -35,6 +38,16 @@ class _NodesPageState extends ConsumerState<NodesPage> {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) _refresh();
});
// 在页期间周期刷新,让服务端节点 status(如 down)及时浮现到列表(置灰/不可用)。
_poll = Timer.periodic(const Duration(seconds: 15), (_) {
if (mounted) ref.read(nodesProvider.notifier).refresh();
});
}
@override
void dispose() {
_poll?.cancel();
super.dispose();
}
Future<void> _refresh() async {