322d806876
- 新增 client/windows/build.ps1:拉内核→带 --dart-define 构建→出安装包一键串联, 规避 Release 漏 --dart-define 导致默认连 localhost、登录「网络请求失败」的坑。 - README:Release 命令补回 --dart-define 并加显式警告,指向一键脚本。 - 清 4 个 lint warning:desktop_vpn_bridge 多余 cast→pattern match、去多余非空断言; nav_sidebar 删未用 import;vpn_bridge_mock 加 killSwitchEnabled getter。 - 同步 window_manager/tray_manager/screen_retriever 插件注册生成文件(win+macos)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
141 lines
3.9 KiB
Dart
141 lines
3.9 KiB
Dart
// vpn_bridge_mock.dart — 假内核实现,供 UI 层先行联调
|
||
//
|
||
// 行为:
|
||
// start() → 立即 emit connecting,[connectDelay] 后 emit on,启动统计计时器
|
||
// stop() → 立即 emit off,停止统计计时器
|
||
// stats → on 状态下按 [statsInterval] 周期推假数据帧
|
||
//
|
||
// 用法示例(UI 联调):
|
||
// final bridge = VpnBridgeMock();
|
||
//
|
||
// 用法示例(测试):
|
||
// final bridge = VpnBridgeMock(
|
||
// connectDelay: Duration(milliseconds: 50),
|
||
// statsInterval: Duration(milliseconds: 50),
|
||
// );
|
||
|
||
import 'dart:async';
|
||
import 'dart:math';
|
||
import 'vpn_bridge.dart';
|
||
|
||
class VpnBridgeMock implements VpnBridge {
|
||
VpnBridgeMock({
|
||
this.connectDelay = const Duration(milliseconds: 1500),
|
||
this.statsInterval = const Duration(seconds: 1),
|
||
});
|
||
|
||
final Duration connectDelay;
|
||
final Duration statsInterval;
|
||
|
||
// 内部状态
|
||
VpnStatus _status = VpnStatus.off;
|
||
String _activeOutbound = 'auto';
|
||
bool _killSwitch = false;
|
||
|
||
final _statusCtrl = StreamController<VpnStatus>.broadcast();
|
||
final _statsCtrl = StreamController<VpnStatsEvent>.broadcast();
|
||
|
||
Timer? _connectTimer;
|
||
Timer? _statsTimer;
|
||
|
||
int _tickCount = 0;
|
||
final _rng = Random();
|
||
|
||
// ── helpers ───────────────────────────────────────────────────
|
||
|
||
void _emitStatus(VpnStatus s) {
|
||
_status = s;
|
||
if (!_statusCtrl.isClosed) _statusCtrl.add(s);
|
||
}
|
||
|
||
void _startStats() {
|
||
_tickCount = 0;
|
||
_statsTimer?.cancel();
|
||
_statsTimer = Timer.periodic(statsInterval, (_) {
|
||
_tickCount++;
|
||
if (!_statsCtrl.isClosed) _statsCtrl.add(_fakeTick(_tickCount));
|
||
});
|
||
}
|
||
|
||
VpnStatsEvent _fakeTick(int t) {
|
||
// 模拟稳定带宽 + 微抖动
|
||
final upSpeed = 10240.0 + _rng.nextDouble() * 2048;
|
||
final downSpeed = 51200.0 + _rng.nextDouble() * 8192;
|
||
return VpnStatsEvent(
|
||
uploadBytes: (upSpeed * t * statsInterval.inMilliseconds / 1000).round(),
|
||
downloadBytes: (downSpeed * t * statsInterval.inMilliseconds / 1000).round(),
|
||
uploadSpeed: upSpeed,
|
||
downloadSpeed: downSpeed,
|
||
urltestResults: const [
|
||
UrltestResult(tag: 'hk-01', delayMs: 18),
|
||
UrltestResult(tag: 'jp-01', delayMs: 32),
|
||
UrltestResult(tag: 'sg-01', delayMs: 54),
|
||
],
|
||
);
|
||
}
|
||
|
||
// ── VpnBridge methods ─────────────────────────────────────────
|
||
|
||
@override
|
||
Future<void> start(String configJson) async {
|
||
_connectTimer?.cancel();
|
||
_statsTimer?.cancel();
|
||
_emitStatus(VpnStatus.connecting);
|
||
_connectTimer = Timer(connectDelay, () {
|
||
_emitStatus(VpnStatus.on);
|
||
_startStats();
|
||
});
|
||
}
|
||
|
||
@override
|
||
Future<void> stop() async {
|
||
_connectTimer?.cancel();
|
||
_statsTimer?.cancel();
|
||
_connectTimer = null;
|
||
_statsTimer = null;
|
||
_emitStatus(VpnStatus.off);
|
||
}
|
||
|
||
@override
|
||
Future<VpnStatus> getStatus() async => _status;
|
||
|
||
@override
|
||
Future<void> selectOutbound(String tag) async {
|
||
_activeOutbound = tag;
|
||
// 切换出口时模拟短暂重连
|
||
if (_status == VpnStatus.on) {
|
||
_statsTimer?.cancel();
|
||
_emitStatus(VpnStatus.connecting);
|
||
_connectTimer = Timer(connectDelay ~/ 2, () {
|
||
_emitStatus(VpnStatus.on);
|
||
_startStats();
|
||
});
|
||
}
|
||
}
|
||
|
||
@override
|
||
Future<String> getActiveOutbound() async => _activeOutbound;
|
||
|
||
@override
|
||
Future<void> setKillSwitch({required bool on}) async {
|
||
_killSwitch = on;
|
||
}
|
||
|
||
/// 测试可读:mock 记录的 kill-switch 状态。
|
||
bool get killSwitchEnabled => _killSwitch;
|
||
|
||
@override
|
||
Stream<VpnStatus> get statusStream => _statusCtrl.stream;
|
||
|
||
@override
|
||
Stream<VpnStatsEvent> get statsStream => _statsCtrl.stream;
|
||
|
||
@override
|
||
void dispose() {
|
||
_connectTimer?.cancel();
|
||
_statsTimer?.cancel();
|
||
_statusCtrl.close();
|
||
_statsCtrl.close();
|
||
}
|
||
}
|