fix(client): statsStream/statusStream 缓存为共享广播流,修延迟不回写

根因:VpnNativeBridge.statsStream getter 每次访问都 receiveBroadcastStream(),多订阅者
(连接页速度 + ConnectionController._onStats 回写 urltest 延迟)各起一条原生订阅;但
EventChannel 原生侧只留一个 sink(StatsStreamHandler.onListen 覆盖),后订阅者赢、先订阅者
变哑。速度订阅赢了 sink → _onStats 收不到 → urltest 实测(已确认到达 native:reality-out=595)
永不回写 node.ping → 连接页延迟一直 —。

修复:receiveBroadcastStream() 只调一次、缓存成 asBroadcastStream() 共享流,所有 Dart
订阅者复用同一条原生订阅。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-30 17:57:37 +08:00
parent e6e7d5db10
commit e00163e2d9
+16 -6
View File
@@ -223,18 +223,28 @@ class VpnNativeBridge implements VpnBridge {
Future<void> setKillSwitch({required bool on}) =>
_method.invokeMethod<void>('setKillSwitch', on);
@override
Stream<VpnStatus> get statusStream => _statusRaw
// ⚠️ EventChannel 原生侧只保留「一个」sink:每次 receiveBroadcastStream() + listen 都会
// 触发 onListen 覆盖原生 sink → 多个订阅者(连接页速度 + ConnectionController 回写延迟)
// 互相抢,后订阅的赢、先订阅的流变哑。必须只调一次 receiveBroadcastStream()、缓存成共享
// 广播流,所有 Dart 订阅者复用同一条原生订阅。
late final Stream<VpnStatus> _statusStream = _statusRaw
.receiveBroadcastStream()
.map((e) => VpnStatus.fromString(e?.toString() ?? 'error'));
.map((e) => VpnStatus.fromString(e?.toString() ?? 'error'))
.asBroadcastStream();
@override
Stream<VpnStatsEvent> get statsStream => _statsRaw
late final Stream<VpnStatsEvent> _statsStream = _statsRaw
.receiveBroadcastStream()
.where((e) => e is Map)
.map((e) => VpnStatsEvent.fromNativeMap(
Map<Object?, Object?>.from(e as Map),
));
))
.asBroadcastStream();
@override
Stream<VpnStatus> get statusStream => _statusStream;
@override
Stream<VpnStatsEvent> get statsStream => _statsStream;
@override
void dispose() {