import 'dart:convert'; import 'dart:typed_data'; import 'package:star_lock/talk/startChart/constant/message_type_constant.dart'; import 'package:star_lock/talk/startChart/constant/payload_type_constant.dart'; import 'package:star_lock/talk/startChart/constant/protocol_flag_constant.dart'; import 'package:star_lock/talk/startChart/entity/scp_message.dart'; import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart'; import 'package:star_lock/talk/startChart/proto/generic.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_accept.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_hangup.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_ping.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_reject.pb.dart'; import 'package:star_lock/talk/startChart/proto/talk_request.pb.dart'; class MessageCommand { // 全局字典,用于存储每个 ToPeerId 对应的当前 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, Payload: 'hello', PayloadCRC: 55230, PayloadLength: 5, 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, required TalkData talkData, int? MessageId, }) { 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: calculationCrc(payload), PayloadLength: payload.length, PayloadType: PayloadTypeConstant.talkData, ); String serializedBytesString = message.serialize(); return _hexToBytes(serializedBytesString); } // 预期接收消息 static List talkExpectMessage({ required String FromPeerId, required String ToPeerId, required TalkExpect 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 = 'ok'; genericResp.code = 0; 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, }) { final genericResp = GenericResp(); genericResp.message = 'error'; genericResp.code = -1; 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); } // 辅助方法:将16进制字符串转换为字节列表 static List _hexToBytes(String hex) { final bytes = []; for (int i = 0; i < hex.length; i += 2) { bytes.add(int.parse(hex.substring(i, i + 2), radix: 16)); } 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; } }