import 'dart:convert'; import 'dart:typed_data'; import 'package:star_lock/talk/starChart/constant/message_type_constant.dart'; import 'package:star_lock/talk/starChart/constant/payload_type_constant.dart'; import 'package:star_lock/talk/starChart/constant/protocol_flag_constant.dart'; import 'package:star_lock/talk/starChart/constant/udp_constant.dart'; import 'package:star_lock/talk/starChart/entity/scp_message.dart'; import 'package:star_lock/talk/starChart/proto/ble_message.pb.dart'; import 'package:star_lock/talk/starChart/proto/gateway_reset.pb.dart'; import 'package:star_lock/talk/starChart/proto/generic.pb.dart'; import 'package:star_lock/talk/starChart/proto/rbcu.pb.dart'; import 'package:star_lock/talk/starChart/proto/talk_accept.pb.dart'; import 'package:star_lock/talk/starChart/proto/talk_data.pb.dart'; import 'package:star_lock/talk/starChart/proto/talk_expect.pb.dart'; import 'package:star_lock/talk/starChart/proto/talk_hangup.pb.dart'; import 'package:star_lock/talk/starChart/proto/talk_ping.pb.dart'; import 'package:star_lock/talk/starChart/proto/talk_reject.pb.dart'; import 'package:star_lock/talk/starChart/proto/talk_request.pb.dart'; class MessageCommand { // 全局字典,用于存储每个 ToPeerId 对应的当前 messageId // 单个会话的messageId需要递增 static Map _messageIdMap = {}; static int _maxIntValue = 9223372036854775807; // Dart 中 int 的最大值 // 获取并递增消息ID static int getNextMessageId(String toPeerId, {bool increment = true}) { if (_messageIdMap.containsKey(toPeerId)) { if (increment) { _messageIdMap[toPeerId] = _messageIdMap[toPeerId]! + 1; // 如果 messageId 超过 int 的最大值,则重置为 1 if (_messageIdMap[toPeerId]! > _maxIntValue) { _messageIdMap[toPeerId] = 1; } } } else { _messageIdMap[toPeerId] = 1; } return _messageIdMap[toPeerId]!; } /// 客户端去中继上线命令 static List goOnlineRelay({ required String FromPeerId, required String ToPeerId, int? MessageId, }) { String serializedBytesString = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, PayloadCRC: 0, PayloadLength: 0, PayloadType: PayloadTypeConstant.goOnline, ).serialize(); return _hexToBytes(serializedBytesString); } // 回声测试消息 static List echoMessage({ required String ToPeerId, required String FromPeerId, List? payload, int? SpTotal, int? SpIndex, int? MessageId, }) { ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: SpTotal, SpIndex: SpIndex, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrcFromIntList(payload ?? []), PayloadLength: payload?.length ?? 0, PayloadType: PayloadTypeConstant.echoTest, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 心跳消息 static List heartbeatMessage({ required String FromPeerId, required String ToPeerId, int? MessageId, }) { String payload = 'hello'; ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(_stringToUint8List(payload)), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.heartbeat, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 网关初始化 static List gatewayResetMessage({ required int gatewayId, required String FromPeerId, required String ToPeerId, required int time, int? MessageId, }) { // 构建荷载 final gatewayResetReq = GatewayResetReq( iD: gatewayId, time: time, ); // 构建荷载长度 final payload = gatewayResetReq.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.gatewayReset, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 同意接听消息 static List talkAcceptMessage({ required String FromPeerId, required String ToPeerId, int? MessageId, }) { final talkAcceptReq = TalkAcceptReq(); final payload = talkAcceptReq.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.talkAccept, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 发送对话请求消息 static List talkRequestMessage({ required String FromPeerId, required String ToPeerId, int? MessageId, }) { final talkReq = TalkReq(); final payload = talkReq.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.callRequest, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 拒绝接听消息 static List talkRejectMessage({ required String FromPeerId, required String ToPeerId, int? MessageId, }) { final talkReject = TalkReject(); final payload = talkReject.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.talkReject, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 呼叫保持消息 static List talkPingMessage({ required String FromPeerId, required String ToPeerId, int? MessageId, }) { final talkPing = TalkPing(); final payload = talkPing.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.talkPing, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 通话中挂断 static List talkHangupMessage({ required String FromPeerId, required String ToPeerId, int? MessageId, }) { final talkHangup = TalkHangup(); final payload = talkHangup.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.talkHangup, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 音视频数据 static List talkDataMessage({ required String FromPeerId, required String ToPeerId, int? MessageId, required TalkData talkData, int? SpTotal, int? SpIndex, }) { final payload = talkData.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.RealTimeData, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrcFromIntList(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.talkData, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 预期接收消息 static List talkExpectMessage({ required String FromPeerId, required String ToPeerId, required TalkExpectReq talkExpect, int? MessageId, }) { final payload = talkExpect.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.talkExpect, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // GenericRespSuccess 消息 static List genericRespSuccessMessage({ required String FromPeerId, required String ToPeerId, required int PayloadType, int? MessageId, }) { final genericResp = GenericResp(); genericResp.message = UdpConstant.genericRespSuccessMsg; genericResp.code = UdpConstant.genericRespSuccessCode; final payload = genericResp.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Resp, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadType, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // GenericRespError 消息 static List genericRespErrorMessage({ required String FromPeerId, required String ToPeerId, required int PayloadType, int? MessageId, String? errorMessageText, }) { final genericResp = GenericResp(); genericResp.message = errorMessageText ?? UdpConstant.genericRespErrorMsg; genericResp.code = UdpConstant.genericRespErrorCode; final payload = genericResp.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Resp, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadType, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // RbcuInfo 地址交换消息 static List genericRbcuInfoMessage({ required String FromPeerId, required String ToPeerId, required RbcuInfo rbcuInfo, int? MessageId, String? errorMessageText, }) { final payload = rbcuInfo.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.RbcuInfo, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 蓝牙消息 static List bleMessage({ required String FromPeerId, required String ToPeerId, required String bluetoothDeviceName, required List bleStructData, int? MessageId, int? timeout = 30, int? IdleTimeout = 0, }) { final bleReq = BleReq( bluetoothDeviceName: bluetoothDeviceName, structData: bleStructData, timeout: timeout, idleTimeout: 0, ); final payload = bleReq.writeToBuffer(); ScpMessage message = ScpMessage( ProtocolFlag: ProtocolFlagConstant.scp01, MessageType: MessageTypeConstant.Req, MessageId: MessageId, SpTotal: 1, SpIndex: 1, FromPeerId: FromPeerId, ToPeerId: ToPeerId, Payload: payload, PayloadCRC: calculationCrcFromIntList(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.blePassthrough, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 辅助方法:将16进制字符串转换为字节列表 static List _hexToBytes(String hex) { // 清理输入字符串,移除所有非十六进制字符 hex = hex.replaceAll(RegExp(r'[^0-9a-fA-F]'), ''); // 如果字符串长度为奇数,在前面补 0 if (hex.length % 2 != 0) { hex = '0$hex'; } final bytes = []; for (int i = 0; i < hex.length; i += 2) { // 确保 i + 2 不超过 hex 的长度 final end = i + 2 <= hex.length ? i + 2 : hex.length; final hexByte = hex.substring(i, end); // 解析十六进制字符串为整数 try { bytes.add(int.parse(hexByte, radix: 16)); } catch (e) { // 如果解析失败,抛出异常或记录日志 throw FormatException('Invalid hex byte: $hexByte'); } } return bytes; } static int calculationCrc(Uint8List uint8Payload) { // 使用自定义 CRC32 算法 final int crc32Value = _crc32Uint16(uint8Payload); return crc32Value; } // 重载的方法,接受 List static int calculationCrcFromIntList(List intList) { // 将 List 转换为 Uint8List final Uint8List uint8Payload = Uint8List.fromList(intList); // 调用现有的 calculationCrc 方法 return calculationCrc(uint8Payload); } // 将字符串转换为 Uint8List static Uint8List _stringToUint8List(String input) { return Uint8List.fromList(utf8.encode(input)); } // 自定义 CRC32 实现 static int _crc32Uint16(Uint8List data) { const int polynomial = 0xD5828281; // 创建 CRC32 表 final List table = List.generate(256, (i) { int crc = i; for (int j = 0; j < 8; j++) { if ((crc & 1) != 0) { crc = (crc >> 1) ^ polynomial; } else { crc >>= 1; } } return crc; }); // 计算 CRC32 校验值 int crc = 0xFFFFFFFF; for (final int byte in data) { crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF]; } crc ^= 0xFFFFFFFF; // 返回 CRC32 的低 16 位 return crc & 0xFFFF; } }