411 lines
12 KiB
Dart
411 lines
12 KiB
Dart
import 'dart:convert';
|
||
import 'dart:typed_data';
|
||
import 'package:star_lock/app_settings/app_settings.dart';
|
||
import 'package:star_lock/talk/starChart/exception/start_chart_message_exception.dart';
|
||
import 'package:star_lock/talk/starChart/handle/impl/udp_heart_beat_handler.dart';
|
||
import 'package:star_lock/talk/starChart/handle/scp_message_handle.dart';
|
||
import 'package:star_lock/talk/starChart/handle/scp_message_handler_factory.dart';
|
||
|
||
class ScpMessage {
|
||
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}';
|
||
}
|
||
|
||
// 辅助函数:定长字符串编码
|
||
List<int> encodeFixedLengthString(String? str, int length) {
|
||
final bytes = utf8.encode(str ?? '');
|
||
if (bytes.length > length) {
|
||
return bytes.sublist(0, length);
|
||
} else if (bytes.length < length) {
|
||
return bytes + List.filled(length - bytes.length, 0);
|
||
} else {
|
||
return bytes;
|
||
}
|
||
}
|
||
|
||
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 (字符串,长度固定为44字节)
|
||
if (FromPeerId != null) {
|
||
bytes.addAll(utf8.encode(FromPeerId!));
|
||
}
|
||
// FromPeerId (44字节定长)
|
||
// bytes.addAll(encodeFixedLengthString(FromPeerId, 44));
|
||
|
||
// ToPeerId (字符串,长度固定为44字节)
|
||
if (ToPeerId != null) {
|
||
bytes.addAll(utf8.encode(ToPeerId!));
|
||
}
|
||
// ToPeerId (44字节定长)
|
||
// bytes.addAll(encodeFixedLengthString(ToPeerId, 44));
|
||
|
||
// 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 if (Payload != null) {
|
||
// 如果不是字符串则需要外部转为字节数组,这里直接添加
|
||
bytes.addAll(Payload);
|
||
}
|
||
|
||
// 转16进制字符串
|
||
final bytesToHexString = bytesToHex(bytes);
|
||
|
||
return bytesToHexString;
|
||
}
|
||
|
||
static ScpMessage deserialize(Uint8List bytes) {
|
||
final message = ScpMessage();
|
||
final length = bytes.length;
|
||
int offset = 0;
|
||
|
||
// 提前检查字节数组长度是否足够
|
||
if (length < 4 + 1 + 2 + 1 + 1 + 44 + 44 + 2 + 2 + 4) {
|
||
throw FormatException("Invalid message length");
|
||
}
|
||
|
||
// 使用 ByteData 读取多字节数据
|
||
final byteData = ByteData.sublistView(bytes);
|
||
|
||
// ProtocolFlag (4 bytes)
|
||
message.ProtocolFlag = utf8.decode(bytes.sublist(offset, offset + 4));
|
||
offset += 4;
|
||
|
||
// MessageType (1 byte)
|
||
message.MessageType = bytes[offset];
|
||
offset += 1;
|
||
|
||
// MessageId (2 bytes, little-endian)
|
||
message.MessageId = byteData.getUint16(offset, Endian.little);
|
||
offset += 2;
|
||
|
||
// SpTotal (1 byte)
|
||
message.SpTotal = bytes[offset];
|
||
offset += 1;
|
||
|
||
// SpIndex (1 byte)
|
||
message.SpIndex = bytes[offset];
|
||
offset += 1;
|
||
|
||
// FromPeerId (44 bytes)
|
||
message.FromPeerId =
|
||
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
||
offset += 44;
|
||
|
||
// ToPeerId (44 bytes)
|
||
message.ToPeerId =
|
||
utf8.decode(bytes.sublist(offset, offset + 44)).trimRight();
|
||
offset += 44;
|
||
|
||
// PayloadType (2 bytes, little-endian)
|
||
message.PayloadType = byteData.getUint16(offset, Endian.little);
|
||
offset += 2;
|
||
|
||
// PayloadCRC (2 bytes, little-endian)
|
||
message.PayloadCRC = byteData.getUint16(offset, Endian.little);
|
||
offset += 2;
|
||
|
||
// PayloadLength (4 bytes, little-endian)
|
||
message.PayloadLength = byteData.getUint32(offset, Endian.little);
|
||
offset += 4;
|
||
|
||
// 检查 Payload 长度是否有效
|
||
if (message.PayloadLength == null ||
|
||
length - offset < message.PayloadLength!) {
|
||
throw FormatException("Invalid Payload or PayloadLength");
|
||
}
|
||
|
||
// 处理 Payload
|
||
final payloadBytes = bytes.sublist(offset, offset + message.PayloadLength!);
|
||
offset += message.PayloadLength!;
|
||
message.Payload = _handlePayLoad(
|
||
payloadType: message.PayloadType ?? 0,
|
||
messageType: message.MessageType ?? 0,
|
||
byte: payloadBytes,
|
||
offset: offset,
|
||
PayloadLength: message.PayloadLength,
|
||
spIndex: message.SpIndex,
|
||
spTotal: message.SpTotal,
|
||
messageId: message.MessageId,
|
||
);
|
||
|
||
return message;
|
||
}
|
||
|
||
// static ScpMessage deserialize(Uint8List bytes) {
|
||
// final message = ScpMessage();
|
||
// int offset = 0;
|
||
//
|
||
// // String hexString =
|
||
// // bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
|
||
// // // _log(text: 'result bytes hex: ${hexString}');
|
||
// // _log(
|
||
// // text:
|
||
// // '\n result bytes hex: ${hexString} \n payload hex: ${hexString.substring(210)}');
|
||
//
|
||
// // 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 {
|
||
// 构造工厂
|
||
final ScpMessageHandler handler =
|
||
ScpMessageHandlerFactory.createHandler(payloadType);
|
||
// 处理荷载信息并返回
|
||
final payload = handler.deserializePayload(
|
||
payloadType: payloadType,
|
||
messageType: messageType,
|
||
byte: byte,
|
||
offset: offset,
|
||
PayloadLength: PayloadLength,
|
||
spTotal: spTotal,
|
||
spIndex: spIndex,
|
||
messageId: messageId,
|
||
);
|
||
return payload;
|
||
} catch (e, stackTrace) {
|
||
throw StartChartMessageException('❌反序列化udp数据时遇到错误----》$e \n$stackTrace');
|
||
}
|
||
}
|
||
|
||
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}');
|
||
}
|
||
}
|