“DaisyWu” 5b56557444 Merge branch 'develop_liyi' of http://code.star-lock.cn/StarlockTeam/app-starlock into develop_liyi
# Conflicts:
#	lib/main/lockMian/lockMain/lockMain_page.dart
2024-12-23 18:26:49 +08:00

564 lines
19 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:get/get.dart';
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/handle/other/talk_data_repository.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 {
/// 分包缓冲区
// 存储每个 messageId 对应的分包数据
static Map<int, List<List<int>>> _packetBuffer = {};
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 if (Payload != null) {
// 如果不是字符串则需要外部转为字节数组,这里直接添加
bytes.addAll(Payload);
}
// 转16进制字符串
final bytesToHexString = bytesToHex(bytes);
return bytesToHexString;
}
static ScpMessage deserialize(List<int> bytes) {
final message = ScpMessage();
int offset = 0;
// Convert byte array to hex string with zero padding and without spaces
String hexString =
bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
// Log the hex string
_log(text: '原始字节数组: $hexString');
// 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,
);
// if (message.Payload != null && message.Payload is List<int>) {
// message.PayloadLength = message.Payload.length;
// }
} 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:
// 回声测试
if (spTotal != null &&
spTotal > 1 &&
messageId != null &&
spIndex != null) {
// 分包处理
return _handleFragmentedPayload(
messageId: messageId,
spTotal: spTotal,
spIndex: spIndex,
byte: byte,
payloadType: payloadType,
);
} else {
// 如果 spTotal 为 1 或者没有分包信息,直接处理 byte 数据
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 &&
messageId != null &&
spIndex != null) {
// 分包处理
return _handleFragmentedPayload(
messageId: messageId,
spTotal: spTotal,
spIndex: spIndex,
byte: byte,
payloadType: payloadType,
);
} 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, stackTrace) {
// 打印异常信息
_log(text: '❌反序列化udp数据时遇到错误----》$e');
// 打印堆栈跟踪信息
_log(text: '堆栈跟踪:\n$stackTrace');
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}');
}
/// 处理分包逻辑
/// 如果没有收到所有包则返回null
static dynamic _handleFragmentedPayload({
required int messageId,
required int spTotal,
required int spIndex,
required List<int> byte,
required int payloadType,
}) {
// 初始化分包列表
if (!_packetBuffer.containsKey(messageId)) {
_packetBuffer[messageId] = List.filled(spTotal, []);
}
// 检查分包索引是否在合法范围内
if (spIndex < 1 || spIndex > spTotal) {
print('Invalid spIndex: $spIndex for messageId: $messageId');
return null;
}
// 存储当前分包
_packetBuffer[messageId]![spIndex - 1] = byte;
// 检查是否接收到所有分包
if (_packetBuffer[messageId]!.every((packet) => packet.isNotEmpty)) {
// 重组所有分包
List<int> completePayload = _packetBuffer[messageId]!.expand((packet) => packet).toList();
// 清除已重组的分包数据
_packetBuffer.remove(messageId);
// 解析完整的 payload
if (payloadType == PayloadTypeConstant.talkData) {
final TalkData talkData = TalkData.fromBuffer(completePayload);
return talkData;
} else {
String payload = utf8.decode(completePayload);
return payload;
}
} else {
// 如果分包尚未接收完全,返回 null 或其他指示符
return null;
}
}
}