import 'dart:async'; import 'dart:convert'; import 'package:web_socket_channel/web_socket_channel.dart'; import '../domain/signal_message.dart'; /// 信令客户端,封装 WebSocket 连接与消息收发。 /// /// 鉴权方式:浏览器/移动端原生 WebSocket 均可在握手阶段通过子协议 /// (Sec-WebSocket-Protocol)传递 Bearer token: /// WebSocketChannel.connect(uri, protocols: ['signal.v1', 'auth.``']) /// 服务端从首子协议取出 auth.`` 进行校验。 /// /// 不再发送 REGISTER —— 连接由服务端根据令牌身份自动完成,并下发 REGISTER_SUCCESS。 class SignalingClient { final String serverUrl; final String? token; WebSocketChannel? _channel; Timer? _heartbeatTimer; /// 收到信令消息回调(已解析为 SignalMessage)。 void Function(SignalMessage message)? onMessage; /// 连接成功回调。 void Function()? onConnected; /// 连接断开回调。 void Function()? onDisconnected; /// 连接错误回调。 void Function(String error)? onError; /// 令牌失效(关闭码 4001):调用方应刷新令牌后重连。 void Function()? onTokenExpired; /// 强制下线(关闭码 4003):调用方应停止重连并跳登录。 void Function()? onForceLogout; SignalingClient({required this.serverUrl, this.token}); /// 建立 WebSocket 连接(携带 Bearer 子协议,不再发送 REGISTER)。 void connect() { try { final uri = Uri.parse(serverUrl); final protocols = ['signal.v1']; if (token != null && token!.isNotEmpty) { protocols.add('auth.$token'); } _channel = WebSocketChannel.connect(uri, protocols: protocols); _channel!.stream.listen( _onData, onDone: _onDone, onError: (Object e) => onError?.call(e.toString()), cancelOnError: false, ); _startHeartbeat(); onConnected?.call(); } catch (e) { onError?.call(e.toString()); } } void _onData(dynamic data) { if (data is! String) return; try { final map = jsonDecode(data) as Map; final message = SignalMessage.fromJson(map); onMessage?.call(message); } catch (_) { // 忽略无法解析的消息。 } } void _onDone() { _stopHeartbeat(); final code = _channel?.closeCode; if (code == 4001) { onTokenExpired?.call(); return; } if (code == 4003) { onForceLogout?.call(); return; } onDisconnected?.call(); } void _startHeartbeat() { _stopHeartbeat(); _heartbeatTimer = Timer.periodic(const Duration(seconds: 25), (_) { if (_channel != null) { try { _channel!.sink.add(jsonEncode({'type': 'PING'})); } catch (_) {} } }); } void _stopHeartbeat() { _heartbeatTimer?.cancel(); _heartbeatTimer = null; } /// 发送信令消息。 void send(SignalMessage message) => _send(message); void _send(SignalMessage message) { _channel?.sink.add(jsonEncode(message.toJson())); } /// 关闭连接。 void disconnect() { _stopHeartbeat(); _channel?.sink.close(); _channel = null; } bool get isConnected => _channel != null; }