522 lines
18 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'package:protobuf/protobuf.dart';
import 'package:star_lock/app_settings/app_settings.dart';
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/entity/heartbeat_response.dart';
import 'package:star_lock/talk/startChart/entity/login_response.dart';
import 'package:star_lock/talk/startChart/proto/ble_message.pb.dart';
import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart';
import 'package:star_lock/talk/startChart/proto/gateway_transfer.pb.dart';
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
import 'package:star_lock/talk/startChart/proto/remote_unlock.pb.dart';
import 'package:star_lock/talk/startChart/proto/talk_accept.pbserver.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_push.pbserver.dart';
import 'package:star_lock/talk/startChart/proto/talk_receiver_transfer.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 ScpMessage {
/// 分包缓冲区
/// keyMessageId
static Map<int, List<int>> _buffer = {};
ScpMessage({
this.ProtocolFlag,
this.MessageType,
this.MessageId,
this.SpTotal,
this.SpIndex,
this.FromPeerId,
this.ToPeerId,
this.PayloadType,
this.PayloadCRC,
this.PayloadLength,
this.Payload,
});
String? ProtocolFlag;
int? MessageType;
int? MessageId;
int? SpTotal;
int? SpIndex;
String? FromPeerId;
String? ToPeerId;
int? PayloadType;
int? PayloadCRC;
int? PayloadLength;
dynamic Payload; // Payload可以是任何类型这里用dynamic表示
ScpMessage.fromJson(dynamic json) {
ProtocolFlag = json['ProtocolFlag'];
MessageType = json['MessageType'];
MessageId = json['MessageId'];
SpTotal = json['SpTotal'];
SpIndex = json['SpIndex'];
FromPeerId = json['FromPeerId'];
ToPeerId = json['ToPeerId'];
PayloadType = json['PayloadType'];
PayloadCRC = json['PayloadCRC'];
PayloadLength = json['PayloadLength'];
Payload = json['Payload'];
}
Map<String, dynamic> toJson() {
return {
'ProtocolFlag': ProtocolFlag,
'MessageType': MessageType,
'MessageId': MessageId,
'SpTotal': SpTotal,
'SpIndex': SpIndex,
'FromPeerId': FromPeerId,
'ToPeerId': ToPeerId,
'PayloadType': PayloadType,
'PayloadCRC': PayloadCRC,
'PayloadLength': PayloadLength,
'Payload': Payload,
};
}
@override
String toString() {
return 'ScpMessage{ProtocolFlag: $ProtocolFlag, MessageType: $MessageType, MessageId: $MessageId, SpTotal: $SpTotal, SpIndex: $SpIndex, FromPeerId: $FromPeerId, ToPeerId: $ToPeerId, PayloadType: $PayloadType, PayloadCRC: $PayloadCRC, PayloadLength: $PayloadLength, Payload: $Payload}';
}
String serialize() {
final bytes = <int>[];
// ProtocolFlag (4 bytes)
if (ProtocolFlag != null) {
bytes.addAll(utf8.encode(ProtocolFlag!));
}
// MessageType (1 byte)
if (MessageType != null) {
bytes.add(MessageType!);
}
// MessageId (2 bytes)
if (MessageId != null) {
final highByteMessageId = (MessageId! >> 8) & 0xFF;
final lowByteMessageId = MessageId! & 0xFF;
bytes.add(lowByteMessageId); // 交换位置
bytes.add(highByteMessageId); // 交换位置
}
// SpTotal (1 byte)
if (SpTotal != null) {
bytes.add(SpTotal!);
}
// SpIndex (1 byte)
if (SpIndex != null) {
bytes.add(SpIndex!);
}
// FromPeerId (字符串,记录长度)
if (FromPeerId != null) {
bytes.addAll(utf8.encode(FromPeerId!));
}
// ToPeerId (字符串假设长度固定为32字节)
if (ToPeerId != null) {
bytes.addAll(utf8.encode(ToPeerId!));
}
// PayloadType (2 bytes)
if (PayloadType != null) {
final highBytePayloadType = (PayloadType! >> 8) & 0xFF;
final lowBytePayloadType = PayloadType! & 0xFF;
bytes.add(lowBytePayloadType); // 交换位置
bytes.add(highBytePayloadType); // 交换位置
}
// 计算 PayloadCRC (2 bytes)
if (PayloadCRC != null) {
final highBytePayloadCRC = (PayloadCRC! >> 8) & 0xFF;
final lowBytePayloadCRC = PayloadCRC! & 0xFF;
bytes.add(lowBytePayloadCRC); // 交换位置
bytes.add(highBytePayloadCRC); // 交换位置
}
// PayloadLength (4 bytes)
if (PayloadLength != null) {
bytes.add(PayloadLength! & 0xFF);
bytes.add((PayloadLength! >> 8) & 0xFF);
bytes.add((PayloadLength! >> 16) & 0xFF);
bytes.add((PayloadLength! >> 24) & 0xFF);
}
// Payload (字符串,转换为字节)
if (Payload != null && Payload is String) {
bytes.addAll(utf8.encode(Payload!));
} else {
// 如果不是字符串则需要外部转为字节数组,这里直接添加
bytes.addAll(Payload);
}
// 转16进制字符串
final bytesToHexString = bytesToHex(bytes);
return bytesToHexString;
}
static ScpMessage deserialize(List<int> bytes) {
final message = ScpMessage();
int offset = 0;
_log(
text:
'原始字节数组: ${bytes.sublist(0, 20).map((b) => b.toRadixString(16)).join(" ")}');
// ProtocolFlag (4 bytes)
if (bytes.length - offset >= 4) {
message.ProtocolFlag = utf8.decode(bytes.sublist(offset, offset + 4));
offset += 4;
} else {
throw FormatException("Invalid ProtocolFlag length");
}
// MessageType (1 byte)
if (bytes.length - offset >= 1) {
message.MessageType = bytes[offset];
offset += 1;
} else {
throw FormatException("Invalid MessageType length");
}
// MessageId (2 bytes, little-endian)
if (bytes.length - offset >= 2) {
message.MessageId = (bytes[offset + 1] << 8) | bytes[offset];
offset += 2;
} else {
throw FormatException("Invalid MessageId length");
}
// SpTotal (1 byte)
if (bytes.length - offset >= 1) {
message.SpTotal = bytes[offset];
offset += 1;
} else {
throw FormatException("Invalid SpTotal length");
}
// SpIndex (1 byte)
if (bytes.length - offset >= 1) {
message.SpIndex = bytes[offset];
offset += 1;
} else {
throw FormatException("Invalid SpIndex length");
}
// FromPeerId (字符串长度固定为44字节)
if (bytes.length - offset >= 44) {
message.FromPeerId =
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
offset += 44;
} else {
throw FormatException("Invalid FromPeerId length");
}
// ToPeerId (字符串长度固定为44字节)
if (bytes.length - offset >= 44) {
message.ToPeerId =
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
offset += 44;
} else {
throw FormatException("Invalid ToPeerId length");
}
// PayloadType (2 bytes, little-endian)
if (bytes.length - offset >= 2) {
message.PayloadType = (bytes[offset + 1] << 8) | bytes[offset];
offset += 2;
} else {
throw FormatException("Invalid PayloadType length");
}
// PayloadCRC (2 bytes, little-endian)
if (bytes.length - offset >= 2) {
message.PayloadCRC = (bytes[offset + 1] << 8) | bytes[offset];
offset += 2;
} else {
throw FormatException("Invalid PayloadCRC length");
}
// PayloadLength (4 bytes, little-endian)
if (bytes.length - offset >= 4) {
message.PayloadLength = (bytes[offset] |
(bytes[offset + 1] << 8) |
(bytes[offset + 2] << 16) |
(bytes[offset + 3] << 24)); // 修正为 little-endian
offset += 4;
} else {
throw FormatException("Invalid PayloadLength length");
}
// 处理其他类型的Payload
if (message.PayloadLength != null &&
bytes.length - offset >= message.PayloadLength!) {
final sublist = bytes.sublist(offset, offset + message.PayloadLength!);
offset += message.PayloadLength!;
message.Payload = _handlePayLoad(
payloadType: message.PayloadType ?? 0,
messageType: message.MessageType ?? 0,
byte: sublist,
offset: offset,
PayloadLength: message.PayloadLength,
spIndex: message.SpIndex,
spTotal: message.SpTotal,
messageId: message.MessageId,
);
} else {
throw FormatException("Invalid Payload or PayloadLength");
}
return message;
}
// 根据不同payloadType序列化对应的payload结构体
static dynamic _handlePayLoad({
required int payloadType,
required int messageType,
required List<int> byte,
int? offset,
int? PayloadLength,
int? spTotal,
int? spIndex,
int? messageId,
}) {
try {
switch (payloadType) {
case PayloadTypeConstant.goOnline:
// 上线
LoginResponse loginResp = LoginResponse.fromBytes(byte);
return loginResp;
case PayloadTypeConstant.heartbeat:
// 心跳
HeartbeatResponse heartbeatResponse =
HeartbeatResponse.fromBytes(byte);
return heartbeatResponse;
case PayloadTypeConstant.echoTest:
// 回声测试
String payload = utf8.decode(byte);
return payload;
case PayloadTypeConstant.gatewayReset:
// 初始化网关
if (messageType == MessageTypeConstant.Resp) {
final GatewayResetResp gatewayResetResp =
GatewayResetResp.fromBuffer(byte);
return gatewayResetResp;
} else if (messageType == MessageTypeConstant.Req) {
final GatewayResetReq gatewayResetReq =
GatewayResetReq.fromBuffer(byte);
return gatewayResetReq;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.callRequest:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final TalkReq talkReq = TalkReq.fromBuffer(byte);
return talkReq;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.talkAccept:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final TalkAcceptReq talkAccept = TalkAcceptReq.fromBuffer(byte);
return talkAccept;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.gatewayTransfer:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final GatewayTransferReq gatewayTransferReq =
GatewayTransferReq.fromBuffer(byte);
return gatewayTransferReq;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.blePassthrough:
final BleResp bleResp = BleResp.fromBuffer(byte);
return bleResp;
case PayloadTypeConstant.remoteUnlock:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final RemoteUnlockResp remoteUnlockResp =
RemoteUnlockResp.fromBuffer(byte);
return remoteUnlockResp;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.talkReceiverTransfer:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final TalkReceiverTransfer talkReceiverTransfer =
TalkReceiverTransfer.fromBuffer(byte);
return talkReceiverTransfer;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.talkPush:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final TalkPush talkPush = TalkPush.fromBuffer(byte);
return talkPush;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.talkReject:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final TalkReject talkReject = TalkReject.fromBuffer(byte);
return talkReject;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.talkPing:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final TalkPing talkPing = TalkPing.fromBuffer(byte);
return talkPing;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.talkExpect:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.Req) {
final TalkExpect talkExpect = TalkExpect.fromBuffer(byte);
return talkExpect;
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.talkData:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.RealTimeData) {
if (spTotal != null && spTotal > 1) {
// 处理分包
final List<int> subPackageBytes = _subPackage(
spTotal: spTotal!,
spIndex: spIndex!,
bytes: byte,
messageId: messageId!,
);
// 没有分包直接解析
final TalkData talkData = TalkData.fromBuffer(subPackageBytes);
return talkData;
} else {
// 没有分包直接解析
final TalkData talkData = TalkData.fromBuffer(byte);
return talkData;
}
} else {
String payload = utf8.decode(byte);
return payload;
}
case PayloadTypeConstant.talkHangup:
if (messageType == MessageTypeConstant.Resp) {
final GenericResp genericResp = GenericResp.fromBuffer(byte);
return genericResp;
} else if (messageType == MessageTypeConstant.RealTimeData) {
final TalkHangup talkHangup = TalkHangup.fromBuffer(byte);
return talkHangup;
} else {
String payload = utf8.decode(byte);
return payload;
}
default:
print('❌未知的payloadType类型,按照字符串解析');
String payload = utf8.decode(byte);
return payload;
}
} catch (e) {
// _log(text: '❌反序列化udp数据时遇到错误----》$e');
// // 尝试打印原始字节数组以供调试
_log(
text:
'原始字节数组: ${byte.sublist(0, 20).map((b) => b.toRadixString(16)).join(" ")}');
//
// // 如果是Protobuf相关的异常尝试提供更多信息
// if (e is InvalidProtocolBufferException || e is FormatException) {
// _log(
// text:
// '反序列化失败的payloadType: $payloadType, messageType: $messageType');
// }
return '';
}
}
static String bytesToHex(List<int> bytes) {
return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join('');
}
// 辅助函数将16进制字符串转换为字节数组
static List<int> hexToBytes(String hexString) {
final bytes = <int>[];
for (int i = 0; i < hexString.length; i += 2) {
final hexByte = hexString.substring(i, i + 2);
bytes.add(int.parse(hexByte, radix: 16));
}
return bytes;
}
static void _log({required String text}) {
AppLog.log('=====${text}');
}
/// 处理分包情况
static List<int> _subPackage({
required int messageId,
required int spTotal,
required int spIndex,
required List<int> bytes,
}) {
if (_buffer.containsKey(messageId)) {
// 存在这个key就追加
final List<int> bytesList = _buffer[messageId]!;
bytesList.addAll(bytes);
_buffer[messageId] = bytesList;
} else {
// 如果不存在这个key就新增进去
_buffer.putIfAbsent(messageId, () => bytes);
}
return [];
}
}