235 lines
8.2 KiB
Dart
235 lines
8.2 KiB
Dart
import 'dart:async';
|
||
import 'dart:convert';
|
||
import 'dart:typed_data';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:get_it/get_it.dart';
|
||
|
||
import '../../../../core/logging/i_logger_service.dart';
|
||
import '../../../../core/network/protocol_decoder.dart';
|
||
import '../../../../core/network/tcp/tcp_client.dart';
|
||
import '../../../../core/protocol/machine_protocol_constants.dart';
|
||
import '../../../../core/storage/user_storage.dart';
|
||
|
||
/// 远程遥控 TCP 数据源
|
||
/// 负责通过 TCP 协议发送控制指令和权限请求
|
||
class RemoteTcpDatasource {
|
||
final TcpClient _tcpClient;
|
||
final UserStorage _userStorage;
|
||
final ILoggerService _logger = GetIt.I<ILoggerService>();
|
||
|
||
RemoteTcpDatasource(this._tcpClient, this._userStorage);
|
||
|
||
/// 发送 switch_control 权限请求(对应 Android 的 requestSwitchControl)
|
||
///
|
||
/// 这是获取设备控制权的第一步:
|
||
/// 1. 先发送 TCP 0x12 指令携带 switch_control 请求
|
||
/// 2. 等待服务端响应
|
||
/// 3. 再调用 HTTP API 确认控制权
|
||
Future<void> sendSwitchControlRequest(String deviceName) async {
|
||
if (!_tcpClient.isConnected) {
|
||
debugPrint('❌sendSwitchControlRequest [TCP] 无法发送权限请求:Socket 未连接');
|
||
throw Exception('sendSwitchControlRequest TCP 未连接');
|
||
}
|
||
|
||
try {
|
||
// 获取用户信息
|
||
final user = await _userStorage.getUser();
|
||
if (user == null || user.token == null) {
|
||
debugPrint(
|
||
'❌ sendSwitchControlRequest[TCP] 认证失败:用户未登录或 Token 为空,无法发送认证包',
|
||
);
|
||
throw Exception('用户未登录或 Token 无效');
|
||
}
|
||
|
||
final username = user.username;
|
||
final token = user.token;
|
||
final currentDeviceId = deviceName;
|
||
|
||
// 构造 JSON 请求体(参考 Android 代码)
|
||
final request = {
|
||
'request': 'switch_control',
|
||
'deviceId': currentDeviceId,
|
||
'userId': username,
|
||
'platform': 'app',
|
||
'token': token,
|
||
};
|
||
|
||
final jsonStr = jsonEncode(request);
|
||
final jsonBytes = utf8.encode(jsonStr);
|
||
|
||
debugPrint('sendSwitchControlRequest[TCP] 发送权限请求指令:$jsonStr');
|
||
_logger.logWithLevel(
|
||
'🔑 [TCP][获取权限] 发送权限请求指令:$jsonStr',
|
||
shouldLog: true,
|
||
);
|
||
|
||
// 使用 0x12 指令发送(cmdGetAuth)
|
||
// 注意:根据你的协议文档,这里可能是 0x04 或 0x12
|
||
// Android 代码中使用的是 0x12
|
||
// _tcpClient.sendnew(
|
||
// // MachineProtocolConstants.cmdGetAuth, // 0x04 或 0x12,根据实际协议调整
|
||
// jsonBytes,
|
||
// );
|
||
// 构造完整的协议包
|
||
final packet = buildSwitchControlPacket(jsonBytes);
|
||
|
||
debugPrint(
|
||
'sendSwitchControlRequest[TCP] 完整数据包:${packet.map((b) => '0x${b.toRadixString(16)}').join(' ')}',
|
||
);
|
||
|
||
// 发送数据包
|
||
_tcpClient.sendnew(packet);
|
||
|
||
debugPrint(
|
||
'✅ sendSwitchControlRequest[TCP] 已发送 switch_control 权限请求 (0x${MachineProtocolConstants.cmdGetAuth.toRadixString(16)})',
|
||
);
|
||
_logger.logWithLevel(
|
||
'✅ [TCP][获取权限] 已发送 switch_control 权限请求 (0x${MachineProtocolConstants.cmdGetAuth.toRadixString(16)})',
|
||
shouldLog: true,
|
||
);
|
||
} catch (e) {
|
||
debugPrint('❌ sendSwitchControlRequest[TCP] 发送权限请求失败:$e');
|
||
_logger.logWithLevel(
|
||
'❌ [TCP][获取权限] 发送权限请求失败:$e',
|
||
level: 'ERROR',
|
||
shouldLog: true,
|
||
);
|
||
rethrow;
|
||
}
|
||
}
|
||
|
||
/// 监听 TCP 回包流
|
||
/// 用于接收权限响应、状态更新等
|
||
Stream<RawPacket> get responseStream => _tcpClient.packetStream;
|
||
|
||
/// 检查 TCP 连接状态
|
||
bool get isConnected => _tcpClient.isConnected;
|
||
|
||
/// 构建 switch_control 协议包
|
||
///
|
||
/// 包结构:
|
||
/// - 帧头:0xAB, 0xAA (2 字节)
|
||
/// - 命令字:0x12 (1 字节)
|
||
/// - 数据载荷:JSON UTF-8 字节 (N 字节)
|
||
/// - 帧尾:0x00, 0x00, 0xAA, 0xAB (4 字节)
|
||
List<int> buildSwitchControlPacket(List<int> jsonBytes) {
|
||
final builder = BytesBuilder()
|
||
..addByte(MachineProtocolConstants.header1) // 0xAB
|
||
..addByte(MachineProtocolConstants.header2) // 0xAA
|
||
..addByte(0x12) // 命令字:switch_control
|
||
..add(jsonBytes) // JSON 数据
|
||
..addByte(0x00) // CRC 占位 1
|
||
..addByte(0x00) // CRC 占位 2
|
||
..addByte(MachineProtocolConstants.endFlag1) // 0xAA
|
||
..addByte(MachineProtocolConstants.endFlag2); // 0xAB
|
||
|
||
return builder.takeBytes();
|
||
}
|
||
|
||
// TODO: 同意授权和拒绝授权
|
||
void sendSwitchControlResponse(bool agreed, String deviceId) {
|
||
debugPrint(
|
||
'📤 [进入了TCP层==== 被调用 - agreed=$agreed, deviceId=$deviceId',
|
||
);
|
||
|
||
// 🔥 添加详细的连接状态日志
|
||
debugPrint(
|
||
'📤 [进入了TCP层==== 当前 TCP 连接状态: isConnected=${_tcpClient.isConnected}',
|
||
);
|
||
|
||
if (!_tcpClient.isConnected) {
|
||
debugPrint('❌ [TCP DataSource] 无法发送权限响应: Socket 未连接');
|
||
debugPrint('❌ [TCP DataSource] isConnected=${_tcpClient.isConnected}');
|
||
throw Exception('sendSwitchControlResponse TCP 未连接');
|
||
}
|
||
|
||
try {
|
||
debugPrint('📡 [TCP DataSource] TCP 连接正常,准备发送数据...');
|
||
|
||
// 构造响应 JSON(参考 Android 代码)
|
||
final response = agreed
|
||
? {
|
||
'respond': {
|
||
'switchResult': true,
|
||
'deviceId': deviceId,
|
||
'holder': 'you',
|
||
},
|
||
}
|
||
: {
|
||
'respond': {
|
||
'switchResult': false,
|
||
'deviceId': deviceId,
|
||
'reason': 'holder_denied',
|
||
},
|
||
};
|
||
|
||
debugPrint(
|
||
'📝 [TCP DataSource] ${agreed ? "同意" : "拒绝"}授权: deviceId=$deviceId',
|
||
);
|
||
|
||
final jsonStr = jsonEncode(response);
|
||
final jsonBytes = utf8.encode(jsonStr);
|
||
|
||
debugPrint('📦 [TCP DataSource] JSON 数据: $jsonStr');
|
||
debugPrint('📦 [TCP DataSource] JSON 字节长度: ${jsonBytes.length} 字节');
|
||
|
||
// 构造完整的协议包
|
||
final packet = buildSwitchControlPacket(jsonBytes);
|
||
|
||
_logger.logWithLevel('TCP DataSource] JSON 数据: $jsonStr' ,shouldLog: true);
|
||
|
||
debugPrint(
|
||
'📦 [TCP DataSource] 完整数据包(${packet.length}字节): ${packet.map((b) => '0x${b.toRadixString(16).padLeft(2, "0")}').join(' ')}',
|
||
);
|
||
|
||
// 🔥 发送前再次检查连接状态
|
||
if (!_tcpClient.isConnected) {
|
||
debugPrint('❌ [TCP DataSource] 发送前检查: Socket 已断开连接!');
|
||
throw Exception('TCP 连接在发送前断开');
|
||
}
|
||
|
||
// 发送数据包
|
||
debugPrint('🚀 [TCP DataSource] 正在调用 SendNew 发送数据...');
|
||
|
||
// 🔥 添加详细日志:记录发送的完整数据包(十六进制)
|
||
final hexString = packet
|
||
.map((byte) => '0x${byte.toRadixString(16).padLeft(2, '0')}')
|
||
.join(' ');
|
||
debugPrint('📦 [TCP DataSource] 完整数据包(${packet.length}字节): $hexString');
|
||
|
||
// 🔥 使用ILoggerService记录日志
|
||
_logger.logWithLevel(
|
||
'📦 [TCP DataSource] 完整数据包(${packet.length}字节): $hexString',
|
||
shouldLog: true,
|
||
);
|
||
|
||
// 🔥 记录JSON内容和字节数
|
||
_logger.logWithLevel(
|
||
'📝 [TCP DataSource] 发送内容: $jsonStr',
|
||
shouldLog: true,
|
||
);
|
||
_logger.logWithLevel(
|
||
'📊 [TCP DataSource] JSON字节数: ${jsonBytes.length}, 完整包字节数: ${packet.length}',
|
||
shouldLog: true,
|
||
);
|
||
|
||
_tcpClient.sendnew(packet);
|
||
|
||
debugPrint('✅ [TCP DataSource] TCP 响应已成功发送');
|
||
debugPrint('✅ [TCP DataSource] 发送字节数: ${packet.length}');
|
||
|
||
// 🔥 发送成功后的日志
|
||
_logger.logWithLevel(
|
||
'✅ [TCP DataSource] TCP 响应已成功发送 - agreed=$agreed, deviceId=$deviceId, 字节数=${packet.length}',
|
||
shouldLog: true,
|
||
);
|
||
} catch (e) {
|
||
debugPrint('❌ [TCP DataSource] 响应权限请求失败: $e');
|
||
debugPrint('❌ [TCP DataSource] 错误类型: ${e.runtimeType}');
|
||
debugPrint('❌ [TCP DataSource] 错误堆栈: ${StackTrace.current}');
|
||
rethrow;
|
||
}
|
||
}
|
||
}
|