app-starlock/lib/talk/startChart/start_chart_manage.dart

961 lines
31 KiB
Dart
Raw Normal View History

2024-11-28 14:57:49 +08:00
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:convert/convert.dart';
import 'package:fast_rsa/fast_rsa.dart' as fastRsa;
2024-12-13 14:30:33 +08:00
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:pointycastle/export.dart' as pc;
2024-11-28 14:57:49 +08:00
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/flavors.dart';
import 'package:star_lock/login/login/entity/LoginEntity.dart';
import 'package:star_lock/network/api_repository.dart';
2024-11-28 14:57:49 +08:00
import 'package:star_lock/network/start_chart_api.dart';
import 'package:star_lock/talk/startChart/command/message_command.dart';
import 'package:star_lock/talk/startChart/constant/ip_constant.dart';
import 'package:star_lock/talk/startChart/constant/listen_addr_type_constant.dart';
import 'package:star_lock/talk/startChart/constant/message_type_constant.dart';
import 'package:star_lock/talk/startChart/constant/payload_type_constant.dart';
2024-11-28 14:57:49 +08:00
import 'package:star_lock/talk/startChart/entity/relay_info_entity.dart';
import 'package:star_lock/talk/startChart/entity/report_information_data.dart';
import 'package:star_lock/talk/startChart/entity/scp_message.dart';
2024-11-28 14:57:49 +08:00
import 'package:star_lock/talk/startChart/entity/star_chart_register_node_entity.dart';
import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart';
import 'package:star_lock/talk/startChart/handle/scp_message_handler_factory.dart';
2024-12-13 14:30:33 +08:00
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
2024-12-09 11:37:27 +08:00
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
import 'package:star_lock/tools/baseGetXController.dart';
2024-11-28 14:57:49 +08:00
import 'package:star_lock/tools/deviceInfo_utils.dart';
import 'package:star_lock/tools/storage.dart';
import 'package:uuid/uuid.dart';
import 'dart:convert';
import 'package:asn1lib/asn1lib.dart' as asn1lib; // Prefix for asn1lib
2024-11-28 14:57:49 +08:00
class StartChartManage {
// 私有构造函数防止外部直接new对象
StartChartManage._internal();
// 单例对象
static final StartChartManage _instance = StartChartManage._internal();
// 工厂构造函数,返回单例对象
factory StartChartManage() {
return _instance;
}
// 产品昵称
final String _productName = F.navTitle;
RawDatagramSocket? _udpSocket;
2024-12-23 15:21:48 +08:00
final Map<String, Completer<void>> _completers = {}; // 发送消息的请求是否完成
final Uuid _uuid = Uuid(); // 用于区分发送的消息的唯一id
int _messageMaxTimeout = 5; // 消息最大超时时间s
2024-11-28 14:57:49 +08:00
late String remoteHost = ''; // 远程主机地址(服务器返回)
late int remotePort = 0; // 远程主机端口(服务器返回)
final int localPort = 62289; // 本地端口
String localPublicHost = ''; // 本地公网ip地址
2024-11-28 14:57:49 +08:00
int heartbeatIntervalTime = 1; // 心跳包间隔时间s
2024-12-23 15:21:48 +08:00
2024-11-28 14:57:49 +08:00
Timer? _heartBeatTimer; // 心跳包定时器
bool _heartBeatTimerRunning = false; // 心跳包定时任务发送状态
String ToPeerId = ''; // 对端ID
String FromPeerId = ''; // 我的ID
// echo测试peer对端
final String echoPeerId = '3phX8Ng2cZHz5NtP8xAf6nYy2z1BYytoejgjoHrWMGhH';
bool isOnlineStartChartServer = false; // 星图是否上线成功
int reStartOnlineStartChartServerIntervalTime = 1; // 重新上线星图服务任务间隔(s)
Timer? reStartOnlineStartChartServerTimer; // 重新上线定时器
int talkPingIntervalTime = 1; // 发送通话保持消息间隔(s)
Timer? talkPingTimer; // 发送通话保持消息定时器
2024-12-09 11:06:35 +08:00
int talkExpectIntervalTime = 1; // 发送通话预期数据的消息间隔(s)
Timer? talkExpectTimer; // 发送通话预期消息定时器
2024-12-13 14:30:33 +08:00
int talkDataIntervalTime = 10; // 通话数据的消息间隔(ms)
Timer? talkDataTimer; // 发送通话数据消息定时器
2024-12-23 17:13:32 +08:00
final int _maxPayloadSize = 8 * 1024; // 分包大小
2024-12-09 11:06:35 +08:00
// 默认通话的期望数据格式
TalkExpect defaultTalkExpect = TalkExpect(
videoType: [TalkExpect_VideoTypeE.IMAGE],
2024-12-23 09:56:12 +08:00
audioType: [TalkExpect_AudioTypeE.G711],
2024-12-09 11:06:35 +08:00
);
2024-12-13 14:30:33 +08:00
// 默认通话数据
TalkData defaultTalkData = TalkData();
2024-12-09 11:06:35 +08:00
String relayPeerId = ''; // 中继peerId
2024-12-09 11:37:27 +08:00
// 获取 StartChartTalkStatus 的唯一实例
StartChartTalkStatus talkStatus = StartChartTalkStatus.instance;
// 星图服务初始化
Future<void> init() async {
if (isOnlineStartChartServer && _udpSocket != null) {
// 如果已经上线就不进行初始化
return;
}
// 节点注册
await _clientRegister();
// 中继查询
await _relayQuery();
// 初始化udp服务
await _onlineRelayService();
// 上报
await reportInformation();
}
2024-11-28 14:57:49 +08:00
/// 客户端注册
Future<void> _clientRegister() async {
final StarChartRegisterNodeEntity? registerNodeEntity =
await Storage.getStarChartRegisterNodeInfo();
if (registerNodeEntity != null && registerNodeEntity.peer?.id != null) {
_log(text: '获取到星图注册节点信息:$registerNodeEntity');
FromPeerId = registerNodeEntity.peer!.id ?? '';
} else {
_log(text: '开始注册客户端');
final StarChartRegisterNodeEntity requestStarChartRegisterNode =
await _requestStarChartRegisterNode();
await _saveStarChartRegisterNodeToStorage(requestStarChartRegisterNode);
FromPeerId = requestStarChartRegisterNode.peer!.id ?? '';
bindUserStarchart();
}
}
//绑定星图配置
Future<void> bindUserStarchart() async {
try {
final StarChartRegisterNodeEntity? registerNodeEntity =
await Storage.getStarChartRegisterNodeInfo();
final LoginEntity entity = await ApiRepository.to.bindUserStarchart(
starchartId: registerNodeEntity?.peer?.id ?? '',
starchartPeerPublicKey: registerNodeEntity?.peer?.publicKey ?? '',
starchartPeerPrivateKey: registerNodeEntity?.peer?.privateKey ?? '',
);
if (entity.errorCode!.codeIsSuccessful) {
AppLog.log('绑定成功');
} else {
AppLog.log('绑定失败');
}
} catch (e) {
AppLog.log('Error bindUserStarchart: $e');
}
2024-11-28 14:57:49 +08:00
}
// 中继查询
Future<void> _relayQuery() async {
2024-11-28 14:57:49 +08:00
final RelayInfoEntity relayInfoEntity =
await StartChartApi.to.relayQueryInfo();
_saveRelayInfoEntityToStorage(relayInfoEntity);
if (relayInfoEntity.client_addr != null) {
localPublicHost = relayInfoEntity.client_addr!;
}
2024-12-10 16:31:56 +08:00
if (relayInfoEntity.relay_list != null &&
relayInfoEntity.relay_list!.length > 0) {
for (int i = 0; i <= relayInfoEntity.relay_list!.length; i++) {
final data = relayInfoEntity.relay_list?[i];
if (data?.peerID != FromPeerId) {
final parseUdpUrl = _parseUdpUrl(data?.listenAddr ?? '');
remoteHost = parseUdpUrl['host'] ?? '';
remotePort = parseUdpUrl['port'] ?? '';
relayPeerId = data?.peerID ?? '';
ToPeerId = relayPeerId;
_log(text: '中继信息----》${relayInfoEntity}');
break;
}
}
2024-12-10 17:27:37 +08:00
} else {
2024-12-10 16:31:56 +08:00
_log(text: '未查询到中继信息----》');
2024-11-28 14:57:49 +08:00
}
}
void closeUdpSocket() {
if (_udpSocket != null) {
_udpSocket?.close();
}
}
// 初始化udp
Future<void> _onlineRelayService() async {
2024-11-28 14:57:49 +08:00
var addressIListenFrom = InternetAddress.anyIPv4;
RawDatagramSocket.bind(addressIListenFrom, localPort)
.then((RawDatagramSocket socket) {
_udpSocket = socket;
/// 广播功能
_udpSocket!.broadcastEnabled = true;
/// 设置数据接收回调
_onReceiveData(_udpSocket!);
}).catchError((error) {
_log(text: 'Failed to bind UDP socket: $error');
});
}
// 上报信息至发现服务
Future<void> reportInformation() async {
_log(text: '上报信息至发现服务');
// 构建参数
ReportInformationData data = await _makeReportInformationData();
final response = await StartChartApi.to.reportInformation(
2024-11-28 14:57:49 +08:00
reportInformationData: data,
);
if (response.statusCode == 200) {
2024-12-09 11:37:27 +08:00
talkStatus.setInitializationCompleted();
// 发送心跳消息
_sendHeartbeatMessage();
// 发送送上线消息
await reStartOnlineStartChartServer();
}
2024-11-28 14:57:49 +08:00
}
// 发送上线消息
Future<void> _sendOnlineMessage() async {
if (isOnlineStartChartServer) {
_log(text: '星图已上线,请勿重复发送上线消息');
return;
}
2024-11-28 14:57:49 +08:00
// 组装上线消息
final message = MessageCommand.goOnlineRelay(
2024-11-28 14:57:49 +08:00
FromPeerId: FromPeerId,
ToPeerId: ToPeerId,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
2024-11-28 14:57:49 +08:00
);
await _sendMessage(message: message);
2024-11-28 14:57:49 +08:00
}
// 发送对讲请求消息
Future<void> sendCallRequestMessage({required String ToPeerId}) async {
2024-12-12 10:28:03 +08:00
if (talkStatus.status == TalkStatus.duringCall) {
_log(text: '已经在通话中,请勿重复发送对讲请求');
return;
}
// 组装上线消息
final message = MessageCommand.talkRequestMessage(
FromPeerId: FromPeerId,
ToPeerId: ToPeerId,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
);
await _sendMessage(message: message);
}
2024-11-28 14:57:49 +08:00
2024-12-13 14:30:33 +08:00
// 发送对讲数据
Future<void> sendTalkDataMessage({required TalkData talkData}) async {
// 组装上线消息
final message = MessageCommand.talkDataMessage(
FromPeerId: FromPeerId,
ToPeerId: ToPeerId,
talkData: talkData,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
2024-12-13 14:30:33 +08:00
);
await _sendMessage(message: message);
}
2024-11-28 14:57:49 +08:00
// 发送心跳包消息
void _sendHeartbeatMessage() async {
2024-11-28 14:57:49 +08:00
if (_heartBeatTimerRunning) {
_log(text: '心跳已经开始了. 请勿重复发送心跳包消息');
return;
}
_heartBeatTimer ??= Timer.periodic(
Duration(
seconds: heartbeatIntervalTime,
2024-11-28 14:57:49 +08:00
),
(Timer timer) async {
final List<int> message = MessageCommand.heartbeatMessage(
FromPeerId: FromPeerId,
ToPeerId: relayPeerId,
MessageId:
MessageCommand.getNextMessageId(relayPeerId, increment: true),
);
await _sendMessage(message: message);
2024-11-28 14:57:49 +08:00
},
);
_heartBeatTimerRunning = true;
}
// 发送回声测试消息
void sendEchoMessage(
{required List<int> payload, required String toPeerId}) async {
// 计算需要分多少个包发送
final int totalPackets = (payload.length / _maxPayloadSize).ceil();
// 循环遍历
for (int i = 0; i < totalPackets; i++) {
int start = i * _maxPayloadSize;
int end = (i + 1) * _maxPayloadSize;
if (end > payload.length) {
end = payload.length;
}
// 取到分包数据
List<int> packet = payload.sublist(start, end);
2024-12-24 15:38:36 +08:00
// 分包数据不递增messageID
2024-12-23 09:56:12 +08:00
final messageId =
MessageCommand.getNextMessageId(toPeerId, increment: false);
// 组装分包数据
final message = MessageCommand.echoMessage(
ToPeerId: toPeerId,
FromPeerId: FromPeerId,
payload: packet,
SpTotal: totalPackets,
SpIndex: i + 1,
MessageId: messageId,
);
// 发送消息
await _sendMessage(message: message);
}
// 分包发送完了递增一下id
MessageCommand.getNextMessageId(toPeerId);
}
// 发送网关初始化消息
void sendGatewayResetMessage(
{required String ToPeerId, required int gatewayId}) async {
final message = MessageCommand.gatewayResetMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
gatewayId: gatewayId,
time: DateTime.now().millisecondsSinceEpoch ~/ 1000,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
);
await _sendMessage(message: message);
}
// 发送同意接听消息
void sendTalkAcceptMessage() async {
final message = MessageCommand.talkAcceptMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
);
await _sendMessage(message: message);
2024-12-09 12:05:34 +08:00
talkStatus.setWaitingAnswer();
}
// 发送拒绝接听消息
void sendTalkRejectMessage() async {
final message = MessageCommand.talkRejectMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
);
await _sendMessage(message: message);
}
// 发送期望接受消息
2024-12-09 11:06:35 +08:00
void sendTalkExpectMessage({required TalkExpect talkExpect}) async {
final message = MessageCommand.talkExpectMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
2024-12-09 11:06:35 +08:00
talkExpect: talkExpect,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
);
await _sendMessage(message: message);
}
// 回复成功消息
void sendGenericRespSuccessMessage(
{required String ToPeerId,
required String FromPeerId,
required int PayloadType}) async {
final message = MessageCommand.genericRespSuccessMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
PayloadType: PayloadType,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: false),
);
await _sendMessage(message: message);
}
// 回复失败消息
void sendGenericRespErrorMessage(
{required String ToPeerId,
required String FromPeerId,
required int PayloadType}) async {
final message = MessageCommand.genericRespErrorMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
PayloadType: PayloadType,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: false),
);
await _sendMessage(message: message);
}
// 发送通话保持消息
Future<void> sendTalkPingMessage(
{required String ToPeerId, required String FromPeerId}) async {
final message = MessageCommand.talkPingMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
);
await _sendMessage(message: message);
}
2024-12-10 17:27:37 +08:00
// 发送通话中挂断消息
Future<void> sendTalkHangupMessage() async {
final message = MessageCommand.talkHangupMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
2024-12-10 17:27:37 +08:00
);
await _sendMessage(message: message);
}
// 重新上线
Future<void> reStartOnlineStartChartServer() async {
if (isOnlineStartChartServer) {
_log(text: '星图已上线,请勿重复发送上线消息');
return;
}
reStartOnlineStartChartServerTimer ??= Timer.periodic(
Duration(
seconds: reStartOnlineStartChartServerIntervalTime,
),
(Timer timer) async {
// 重新发送上线消息
await _sendOnlineMessage();
},
);
}
// 重新发送心跳
void reStartHeartBeat() {
stopHeartbeat();
_sendHeartbeatMessage();
}
2024-11-28 14:57:49 +08:00
// 停止定时发送心跳包
void stopHeartbeat() {
_heartBeatTimer?.cancel();
_heartBeatTimer = null; // 清除定时器引用
_heartBeatTimerRunning = false;
}
// 停止重新上线
void stopReStartOnlineStartChartServer() {
reStartOnlineStartChartServerTimer?.cancel();
reStartOnlineStartChartServerTimer = null; // 清除定时器引用
2024-11-28 14:57:49 +08:00
}
// 发送消息
Future<void> _sendMessage({required List<int> message}) async {
var result = await _udpSocket?.send(
message, InternetAddress(remoteHost), remotePort);
if (result != message.length) {
AppLog.log('❌Udp send data error----> $result ${message.length}');
// _udpSocket = null;
}
2024-11-28 14:57:49 +08:00
}
// 请求注册节点
Future<StarChartRegisterNodeEntity> _requestStarChartRegisterNode() async {
// 获取设备信息
final Map<String, String> deviceInfo = await _getDeviceInfo();
// 发送注册节点请求
final StarChartRegisterNodeEntity response =
await StartChartApi.to.starChartRegisterNode(
product: _productName,
model: '${deviceInfo['brand']}_${deviceInfo['model']}',
name: '${deviceInfo['id']}',
unique: deviceInfo['id'] ?? Uuid().v1(),
);
return response;
}
// 保存星图注册节点信息至缓存
Future<void> _saveStarChartRegisterNodeToStorage(
StarChartRegisterNodeEntity starChartRegisterNodeEntity) async {
if (starChartRegisterNodeEntity != null) {
await Storage.saveStarChartRegisterNodeInfo(starChartRegisterNodeEntity);
_log(text: '注册成功');
}
}
// 保存星图中继服务器信息至缓存
Future<void> _saveRelayInfoEntityToStorage(
RelayInfoEntity relayInfoEntity) async {
if (relayInfoEntity != null) {
await Storage.saveRelayInfo(relayInfoEntity);
}
}
// 构造上报信息数据参数
Future<ReportInformationData> _makeReportInformationData() async {
// 从缓存中获取中继信息
final RelayInfoEntity? relayInfoEntity = await Storage.getRelayInfo();
2024-11-28 14:57:49 +08:00
// 获取公钥
final publicKey = await getPublicKey();
// 获取私钥
final privateKey = await getPrivateKey();
// 生成签名
final sign = await _generateSign(
currentTimestamp: relayInfoEntity!.time ?? 0,
privateKeyHex: privateKey,
2024-11-28 14:57:49 +08:00
);
// 获取本机所有ip地址和中继返回的外网地址
final List<ListenAddrData> listenAddrDataList =
await _makeListenAddrDataList();
//
2024-11-28 14:57:49 +08:00
final RelayServiceData relayServiceData = RelayServiceData(
name: relayInfoEntity?.relay_list?[0].name ?? '',
listen_addr: relayInfoEntity?.relay_list?[0].listenAddr ?? '',
peers_max: relayInfoEntity?.relay_list?[0].peerMax ?? 0,
peers_current: relayInfoEntity?.relay_list?[0].peerCurrent ?? 0,
);
ReportInformationData data = ReportInformationData(
id: FromPeerId,
public_key: publicKey,
listen_addr: listenAddrDataList,
relay_service: relayServiceData,
time: relayInfoEntity.time ?? 0,
2024-11-28 14:57:49 +08:00
sign: sign,
);
return data;
}
// 解析对端数据
Future<void> analyzeInformationOtherEnd() async {
await StartChartApi.to.analyzeInformationOtherEnd(peerId: ToPeerId);
}
2024-11-28 14:57:49 +08:00
// 获取本机所有ip地址和中继返回的外网地址
Future<List<ListenAddrData>> _makeListenAddrDataList() async {
final List<ListenAddrData> listenAddrDataList = [];
final List<String> localIp = await _getAllIpAddresses();
// 从缓存中获取中继信息取出返回的客户端ip地址
2024-11-28 14:57:49 +08:00
final RelayInfoEntity? relayInfoEntity = await Storage.getRelayInfo();
if (relayInfoEntity != null && relayInfoEntity.client_addr != null) {
listenAddrDataList.add(
ListenAddrData(
type: ListenAddrTypeConstant.relay,
address: relayInfoEntity.relay_list!.last!.listenAddr!,
2024-11-28 14:57:49 +08:00
),
);
}
localIp.forEach((element) {
listenAddrDataList.add(
ListenAddrData(
type: ListenAddrTypeConstant.local,
address: IpConstant.udpUrl + element + ':' + localPort.toString(),
),
);
});
return listenAddrDataList ?? [];
}
/// 获取本机所有 IP 地址
2024-11-28 14:57:49 +08:00
Future<List<String>> _getAllIpAddresses() async {
final List<String> ipAddresses = [];
try {
final List<NetworkInterface> interfaces = await NetworkInterface.list(
includeLoopback: true,
type: InternetAddressType.any,
);
for (final interface in interfaces) {
for (final address in interface.addresses) {
// 获取原始 IP 地址
String ipAddress = address.address;
// 移除 IPv6 地址中的接口标识符(如果有)
if (ipAddress.contains('%')) {
ipAddress = ipAddress.split('%').first;
}
// 确保 IP 地址不为空且不在排除列表中
if (ipAddress.isNotEmpty &&
!IpConstant.reportExcludeIp.contains(ipAddress)) {
ipAddresses.add(ipAddress);
2024-11-28 14:57:49 +08:00
}
}
}
} catch (e) {
_log(text: '❌--->获取本机IP时出现错误: $e');
}
return ipAddresses; // 注意:这里不需要 `?? []`,因为 `ipAddresses` 已经初始化为一个空列表。
2024-11-28 14:57:49 +08:00
}
void _log({required String text}) {
AppLog.log('$_productName=====${text}');
}
/// 获取设备信息
Future<Map<String, String>> _getDeviceInfo() async {
final Map<String, String> deviceInfo =
await DeviceInfoUtils.getDeviceInfo();
return deviceInfo;
}
/// 解析 UDP URL 并提取 IP 地址和端口号
Map<String, dynamic> _parseUdpUrl(String url) {
// 使用正则表达式匹配 IP 地址和端口号
final regex = RegExp(r'udp://(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)')
.firstMatch(url);
if (regex != null) {
final ip = regex.group(1);
final portStr = regex.group(2);
final port = int.tryParse(portStr ?? '');
if (ip != null && port != null) {
return {'host': ip, 'port': port};
}
}
throw FormatException('无法解析 URL 格式: $url');
}
String bytesToHex(List<int> bytes) {
return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join('');
}
// 生成签名sing
Future<String> _generateSign({
required int currentTimestamp,
required String privateKeyHex,
2024-11-28 14:57:49 +08:00
}) async {
String resultSign = '';
try {
// 1. 将 32 位时间戳以小端字节序编码为二进制数据
Uint8List signData = encodeTimestampToLittleEndianBytes(currentTimestamp);
// 2.将十六进制字符串转换为字节数组
List<int> privateKeyBytes = hexToBytes(privateKeyHex);
// 3.将私钥转换为 PEM 格式
final pemPrivateKey =
convertToPemPrivateKey(privateKeyBytes, isPKCS8: true);
// 4.签名
var result = await fastRsa.RSA
.signPKCS1v15Bytes(signData, fastRsa.Hash.SHA256, pemPrivateKey);
resultSign = hex.encode(result);
2024-11-28 14:57:49 +08:00
} catch (e) {
_log(text: '❌--->上报信息生成签名时出现错误: $e');
e.printError();
2024-11-28 14:57:49 +08:00
}
return resultSign ?? '';
}
// 将 32 位时间戳以小端字节序编码为二进制数据
Uint8List encodeTimestampToLittleEndianBytes(int timestamp) {
// 创建一个 4 字节的 ByteData 对象
ByteData byteData = ByteData(4);
// 将 32 位时间戳写入 ByteData使用小端字节序
byteData.setUint32(0, timestamp, Endian.little);
// 将 ByteData 转换为 Uint8List
Uint8List bytes = byteData.buffer.asUint8List();
return bytes;
}
/// 转换私钥格式
String convertToPemPrivateKey(List<int> privateKeyBytes,
{bool isPKCS8 = true}) {
// 将字节数组转换为Base64编码的字符串
String base64PrivateKey = base64Encode(privateKeyBytes);
// 添加PEM格式的头尾标签
String pemHeader;
String pemFooter;
if (isPKCS8) {
pemHeader = "-----BEGIN PRIVATE KEY-----";
pemFooter = "-----END PRIVATE KEY-----";
} else {
pemHeader = "-----BEGIN RSA PRIVATE KEY-----";
pemFooter = "-----END RSA PRIVATE KEY-----";
}
// 将Base64字符串分行为每行64个字符
const lineLength = 64;
List<String> lines = []; // 用于存储每一行
for (int i = 0; i < base64PrivateKey.length; i += lineLength) {
int end = (i + lineLength < base64PrivateKey.length)
? i + lineLength
: base64PrivateKey.length;
lines.add(base64PrivateKey.substring(i, end));
}
// 组合成完整的PEM格式字符串
return "$pemHeader\n${lines.join('\n')}\n$pemFooter";
}
/// 自定义 PEM 格式的 RSA 私钥解析器
pc.RSAPrivateKey loadPrivateKey(String privateKeyHex) {
// 将十六进制字符串转换为字节数组
final uint8list = Uint8List.fromList(hexToBytes(privateKeyHex));
try {
// 使用 asn1lib 的 ASN1Parser 解析
final asn1Parser = asn1lib.ASN1Parser(uint8list);
final topLevelSeq = asn1Parser.nextObject() as asn1lib.ASN1Sequence;
final modulus = bytesToBigInt(
(topLevelSeq.elements[1] as asn1lib.ASN1Integer).valueBytes());
final privateExponent = bytesToBigInt(
(topLevelSeq.elements[3] as asn1lib.ASN1Integer).valueBytes());
final p = bytesToBigInt(
(topLevelSeq.elements[4] as asn1lib.ASN1Integer).valueBytes());
final q = bytesToBigInt(
(topLevelSeq.elements[5] as asn1lib.ASN1Integer).valueBytes());
return pc.RSAPrivateKey(modulus, privateExponent, p, q);
} catch (e) {
// 如果发生解码错误,打印错误信息
print("Error decoding private key: $e");
rethrow;
}
}
// 将十六进制字符串转换为字节数组
List<int> hexToBytes(String hex) {
return List<int>.generate(hex.length ~/ 2,
(i) => int.parse(hex.substring(i * 2, i * 2 + 2), radix: 16));
}
BigInt bytesToBigInt(Uint8List bytes) {
return BigInt.parse(
bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(),
radix: 16,
);
}
/// 获取公钥
2024-11-28 14:57:49 +08:00
Future<String> getPublicKey() async {
// 从缓存中获取星图注册节点信息
final StarChartRegisterNodeEntity? starChartRegisterNodeInfo =
await Storage.getStarChartRegisterNodeInfo();
return starChartRegisterNodeInfo?.peer?.publicKey ?? '';
}
/// 获取私钥
2024-11-28 14:57:49 +08:00
Future<String> getPrivateKey() async {
// 从缓存中获取星图注册节点信息
final StarChartRegisterNodeEntity? starChartRegisterNodeInfo =
await Storage.getStarChartRegisterNodeInfo();
return starChartRegisterNodeInfo?.peer?.privateKey ?? '';
}
// 接收返回的数据
void _onReceiveData(RawDatagramSocket socket) {
socket.listen((RawSocketEvent event) {
if (event == RawSocketEvent.read) {
Datagram? dg = socket.receive();
try {
if (dg?.data != null) {
final deserialize = ScpMessage.deserialize(dg!.data);
if (deserialize != null) {
// 处理返回数据
_handleUdpResultData(deserialize);
}
2024-12-10 17:27:37 +08:00
if (deserialize.PayloadType != PayloadTypeConstant.heartbeat) {
if (deserialize.Payload != null) {
_log(text: 'Udp收到结构体数据---》$deserialize');
}
// _log(text: 'text---》${utf8.decode(deserialize.Payload)}');
2024-12-10 17:27:37 +08:00
}
}
2024-12-23 15:21:48 +08:00
} catch (e, stackTrace) {
_log(text: '❌ Udp result data error ----> $e');
2024-12-23 15:21:48 +08:00
_log(text: '堆栈跟踪:\n$stackTrace');
}
}
});
}
// 处理udp返回的数据
void _handleUdpResultData(ScpMessage scpMessage) {
final int payloadType = scpMessage.PayloadType ?? 0;
final int messageType = scpMessage.MessageType ?? 0;
try {
final ScpMessageHandler handler =
ScpMessageHandlerFactory.createHandler(payloadType);
if (messageType == MessageTypeConstant.Req) {
handler.handleReq(scpMessage);
} else if (messageType == MessageTypeConstant.Resp) {
handler.handleResp(scpMessage);
} else if (messageType == MessageTypeConstant.RealTimeData) {
handler.handleRealTimeData(scpMessage);
} else {
handler.handleInvalidReq(scpMessage);
}
} catch (e, stackTrace) {
_log(text: '❌ 处理udp返回数据时遇到错误---> $e\n,$stackTrace');
}
}
/// 通话保持定时器
void startTalkPingMessageTimer() {
talkPingTimer ??= Timer.periodic(
Duration(
seconds: talkPingIntervalTime,
),
(Timer timer) async {
await sendTalkPingMessage(
ToPeerId: ToPeerId,
FromPeerId: FromPeerId,
);
},
);
}
// 停止通话保持
void stopTalkPingMessageTimer() {
talkPingTimer?.cancel();
talkPingTimer = null; // 清除定时器引用
}
2024-12-09 11:06:35 +08:00
/// 通话期望数据定时器
void startTalkExpectTimer() {
talkExpectTimer ??= Timer.periodic(
Duration(
seconds: talkExpectIntervalTime,
),
(Timer timer) {
// 发送期望接受消息
sendTalkExpectMessage(
talkExpect: defaultTalkExpect,
);
},
);
}
2024-12-13 14:30:33 +08:00
/// 通话数据定时器
void startTalkDataTimer() async {
// 如果已经启动了就不运行
if (talkDataTimer != null) return;
// 读取 assets 文件
final ByteData data = await rootBundle.load('assets/talk.h264');
final List<int> byteData = data.buffer.asUint8List();
int current = 0;
int start = 0;
int end = 0;
final List<int> chunks = extractChunks(byteData);
talkDataTimer ??= Timer.periodic(
Duration(
milliseconds: talkDataIntervalTime,
),
(Timer timer) {
if (current >= chunks.length) {
print('数据已经发完');
start = 0;
end = 0;
current = 0;
timer.cancel();
return;
}
// 提取 NALU 边界并生成 chunks
end = chunks[current];
current++;
List<int> frameData = byteData.sublist(start, end);
if (frameData.length == 0) timer.cancel();
defaultTalkData = TalkData(
content: frameData,
contentType: TalkData_ContentTypeE.H264,
);
start = end;
// 发送童话数据
sendTalkDataMessage(talkData: defaultTalkData);
},
);
}
List<int> extractChunks(List<int> byteData) {
int i = 0;
int length = byteData.length;
int naluCount = 0;
int value;
int state = 0;
int lastIndex = 0;
List<int> result = [];
const minNaluPerChunk = 22; // 每个数据块包含的最小NALU数量
while (i < length) {
value = byteData[i++];
// finding 3 or 4-byte start codes (00 00 01 OR 00 00 00 01)
switch (state) {
case 0:
if (value == 0) {
state = 1;
}
break;
case 1:
if (value == 0) {
state = 2;
} else {
state = 0;
}
break;
case 2:
case 3:
if (value == 0) {
state = 3;
} else if (value == 1 && i < length) {
if (lastIndex > 0) {
naluCount++;
}
if (naluCount >= minNaluPerChunk) {
result.add(lastIndex - state - 1);
naluCount = 0;
}
state = 0;
lastIndex = i;
} else {
state = 0;
}
break;
default:
break;
}
}
if (naluCount > 0) {
result.add(lastIndex);
}
return result;
}
// 停止发送通话数据
void stopTalkDataTimer() {
talkDataTimer?.cancel();
talkDataTimer = null; // 清除定时器引用
}
2024-12-09 11:06:35 +08:00
// 停止发送通话期望数据
void stopTalkExpectMessageTimer() {
talkExpectTimer?.cancel();
talkExpectTimer = null; // 清除定时器引用
}
/// 修改预期接收到的数据
void changeTalkExpectDataType({required TalkExpect talkExpect}) {
defaultTalkExpect = talkExpect;
}
2024-12-09 12:05:34 +08:00
/// 销毁资源
void destruction() async {
2024-12-23 17:13:32 +08:00
isOnlineStartChartServer = false;
2024-12-09 12:05:34 +08:00
stopTalkExpectMessageTimer();
stopTalkPingMessageTimer();
stopHeartbeat();
stopReStartOnlineStartChartServer();
2024-12-13 14:30:33 +08:00
stopTalkDataTimer();
2024-12-23 17:13:32 +08:00
// await Storage.removerRelayInfo();
// await Storage.removerStarChartRegisterNodeInfo();
2024-12-09 12:05:34 +08:00
}
2024-11-28 14:57:49 +08:00
}