starwork_flutter/lib/ble/command/ble_command_manager.dart

271 lines
11 KiB
Dart
Raw Normal View History

import 'dart:convert';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/ble/ble_service.dart';
import 'package:starwork_flutter/ble/command/base/base_ble_command.dart';
import 'package:starwork_flutter/ble/command/base/base_ble_response_parser.dart';
2025-09-09 15:42:31 +08:00
import 'package:starwork_flutter/ble/command/response/ble_cmd_add_admin_parser.dart';
import 'package:starwork_flutter/ble/command/response/ble_cmd_get_private_key_parser.dart';
import 'package:starwork_flutter/ble/command/response/ble_cmd_get_public_key_parser.dart';
2025-09-08 18:16:48 +08:00
import 'package:starwork_flutter/ble/command/response/ble_cmd_read_lock_status_parser.dart';
import 'package:starwork_flutter/common/constant/cache_keys.dart';
import 'package:starwork_flutter/common/sm4_encipher/sm4.dart';
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
/// ✨✨✨ 蓝牙命令管理器 - 统一管理所有命令解析器 ✨✨✨
class BleCommandManager {
// 私有构造函数
BleCommandManager._() {
// ✅ 这里就是单例初始化的地方
// 只会执行一次(第一次获取实例时)
_initialize();
}
// 单例实例
static final BleCommandManager _instance = BleCommandManager._();
// 工厂构造函数,提供全局访问点
factory BleCommandManager() => _instance;
/// 所有已注册的命令解析器
final Map<int, BaseBleResponseParser> _parsers = {};
/// ✨✨✨ 初始化命令管理器 ✨✨✨
void _initialize() {
AppLogger.highlight('✨✨✨ 🚀 初始化蓝牙命令管理器 ✨✨✨');
// 注册所有命令解析器
_registerParsers();
AppLogger.info('📋 已注册命令解析器数量: ${_parsers.length}');
_parsers.forEach((commandId, parser) {
AppLogger.debug(' • 0x${commandId.toRadixString(16).padLeft(4, '0')}: ${parser.commandName}');
});
AppLogger.highlight('✨✨✨ ✅ 蓝牙命令管理器初始化完成 ✨✨✨');
}
/// ✨✨✨ 注册所有命令解析器 ✨✨✨
void _registerParsers() {
// 注册获取公钥命令解析器
registerParser(BleCmdGetPublicKeyParser());
registerParser(BleCmdGetPrivateKeyParser());
2025-09-08 18:16:48 +08:00
registerParser(BleCmdReadLockStatusParser());
2025-09-09 15:42:31 +08:00
registerParser(BleCmdAddAdminParser());
// TODO: 在这里注册其他命令解析器
// registerParser(BleCmdSetPasswordParser());
// registerParser(BleCmdUnlockParser());
// 等等...
}
/// ✨✨✨ 注册命令解析器 ✨✨✨
void registerParser(BaseBleResponseParser parser) {
_parsers[parser.commandId] = parser;
AppLogger.debug('📝 注册命令解析器: 0x${parser.commandId.toRadixString(16).padLeft(4, '0')} - ${parser.commandName}');
}
/// ✨✨✨ 移除命令解析器 ✨✨✨
void unregisterParser(int commandId) {
BaseBleResponseParser? removed = _parsers.remove(commandId);
if (removed != null) {
AppLogger.debug('🗑️ 移除命令解析器: 0x${commandId.toRadixString(16).padLeft(4, '0')} - ${removed.commandName}');
}
}
/// ✨✨✨ 处理接收到的应答数据包 ✨✨✨
/// [rawPacketData] 完整的原始数据包
/// 返回解析后的业务数据如果没有匹配的解析器则返回null
2025-09-08 18:16:48 +08:00
dynamic handleResponse(List<int> rawPacketData) {
AppLogger.debug('📊 收到蓝牙数据 (${rawPacketData.length}字节): ${rawPacketData.map((b) => '0x${b.toRadixString(16).padLeft(2, '0')}').join(' ')}');
try {
// ✨✨✨ 首先解析数据包以获取命令ID ✨✨✨
var parsedPacket = BaseBleCommand.parsePacket(rawPacketData);
// 检查数据包是否有效
if (!parsedPacket.isValid) {
AppLogger.warn('⚠️ 数据包无效: ${parsedPacket.errorMessage}');
return null;
}
// 检查数据长度是否足够包含命令ID
if (parsedPacket.data.length < 2) {
AppLogger.warn('⚠️ 应答数据长度不足无法包含命令ID: ${parsedPacket.data.length}字节');
return null;
}
// ✨✨✨ 根据加密类型进行解密处理 ✨✨✨
2025-09-08 18:16:48 +08:00
List<int> processedData = _decryptDataIfNeededSync(parsedPacket);
// ✨✨✨ 提取命令ID (大端序) ✨✨✨
int commandId = (processedData[0] << 8) | processedData[1];
AppLogger.debug('🔍 提取命令ID: 0x${commandId.toRadixString(16).padLeft(4, '0')}');
// ✨✨✨ 直接通过命令ID查找对应的解析器 ✨✨✨
BaseBleResponseParser? parser = _parsers[commandId];
if (parser != null) {
AppLogger.debug('🎯 找到匹配的解析器: ${parser.commandName}');
// 创建一个新的ParsedPacket对象使用解密后的数据
ParsedPacket decryptedPacket = ParsedPacket(
isValid: parsedPacket.isValid,
packetType: parsedPacket.packetType,
packetSequence: parsedPacket.packetSequence,
version: parsedPacket.version,
encryptType: parsedPacket.encryptType,
encryptedDataLength: parsedPacket.encryptedDataLength,
originalDataLength: parsedPacket.originalDataLength,
data: processedData,
crc16: parsedPacket.crc16,
errorMessage: parsedPacket.errorMessage,
);
// 传递解密后的数据给解析器
dynamic result = parser.parseResponse(decryptedPacket, processedData);
return result;
} else {
// 没有找到匹配的解析器
AppLogger.warn('⚠️ 未找到命令ID 0x${commandId.toRadixString(16).padLeft(4, '0')} 对应的解析器');
_logUnknownPacket(rawPacketData);
return null;
}
} catch (e, stackTrace) {
AppLogger.error('❌ 处理蓝牙应答异常', error: e, stackTrace: stackTrace);
return null;
}
}
2025-09-08 18:16:48 +08:00
/// ✨✨✨ 根据加密类型解密数据(同步版本) ✨✨✨
/// [parsedPacket] 已解析的数据包
/// 返回解密后的数据或原始数据(如果不需要解密)
List<int> _decryptDataIfNeededSync(ParsedPacket parsedPacket) {
// 如果是明文,直接返回原始数据
if (parsedPacket.encryptType == BaseBleCommand.ENCRYPT_TYPE_PLAIN) {
AppLogger.debug('🔓 数据未加密,直接使用原始数据');
return parsedPacket.data;
}
switch (parsedPacket.encryptType) {
case BaseBleCommand.ENCRYPT_TYPE_AES128:
return parsedPacket.data;
case BaseBleCommand.ENCRYPT_TYPE_SM4_PRESET:
var connectedDevice = BleService().connectedDevice;
var platformName = connectedDevice?.platformName ?? '';
if (platformName.isEmpty) {
AppLogger.warn('⚠️ 解密数据时未找到设备名称');
return parsedPacket.data;
}
var decrypt = SM4.decrypt(
parsedPacket.data,
key: utf8.encode(platformName),
mode: SM4CryptoMode.ECB,
);
return decrypt;
case BaseBleCommand.ENCRYPT_TYPE_SM4_DEVICE:
// 使用缓存的私钥进行解密
var cachedPrivateKey = BleService.cachedPrivateKey;
if (cachedPrivateKey == null || cachedPrivateKey.isEmpty) {
AppLogger.warn('⚠️ 解密数据时未找到缓存的私钥');
return parsedPacket.data;
}
var decrypt = SM4.decrypt(
parsedPacket.data,
key: cachedPrivateKey,
mode: SM4CryptoMode.ECB,
);
return decrypt;
default:
AppLogger.warn('⚠️ 未知的加密类型: ${parsedPacket.encryptType},使用原始数据');
return parsedPacket.data;
}
}
/// ✨✨✨ 根据加密类型解密数据 ✨✨✨
/// [parsedPacket] 已解析的数据包
/// 返回解密后的数据或原始数据(如果不需要解密)
Future<List<int>> _decryptDataIfNeeded(ParsedPacket parsedPacket) async {
// 如果是明文,直接返回原始数据
if (parsedPacket.encryptType == BaseBleCommand.ENCRYPT_TYPE_PLAIN) {
AppLogger.debug('🔓 数据未加密,直接使用原始数据');
return parsedPacket.data;
}
switch (parsedPacket.encryptType) {
case BaseBleCommand.ENCRYPT_TYPE_AES128:
return parsedPacket.data;
case BaseBleCommand.ENCRYPT_TYPE_SM4_PRESET:
var connectedDevice = BleService().connectedDevice;
var platformName = connectedDevice?.platformName;
var decrypt = SM4.decrypt(
parsedPacket.data,
key: utf8.encode(platformName!),
mode: SM4CryptoMode.ECB,
);
return decrypt;
case BaseBleCommand.ENCRYPT_TYPE_SM4_DEVICE:
var lockCommKey = await SharedPreferencesUtils.getString(CacheKeys.lockCommKey);
if (lockCommKey == null) {
AppLogger.warn('⚠️ 解密订阅数据时未找到私钥');
return parsedPacket.data;
}
var decrypt = SM4.decrypt(
parsedPacket.data,
key: utf8.encode(lockCommKey),
mode: SM4CryptoMode.ECB,
);
return decrypt;
default:
AppLogger.warn('⚠️ 未知的加密类型: ${parsedPacket.encryptType},使用原始数据');
return parsedPacket.data;
}
}
/// ✨✨✨ 根据命令ID获取解析器 ✨✨✨
BaseBleResponseParser? getParser(int commandId) {
return _parsers[commandId];
}
/// ✨✨✨ 获取所有已注册的命令ID ✨✨✨
List<int> getRegisteredCommandIds() {
return _parsers.keys.toList();
}
/// ✨✨✨ 获取所有已注册的解析器信息 ✨✨✨
Map<int, String> getRegisteredParsersInfo() {
return _parsers.map((commandId, parser) => MapEntry(commandId, parser.commandName));
}
/// ✨✨✨ 记录未知数据包信息 ✨✨✨
void _logUnknownPacket(List<int> rawPacketData) {
try {
// 尝试基本解析以获取更多信息
var parsedPacket = BaseBleCommand.parsePacket(rawPacketData);
if (parsedPacket.isValid && parsedPacket.data.length >= 2) {
int commandId = (parsedPacket.data[0] << 8) | parsedPacket.data[1];
AppLogger.warn('🔍 未知命令应答: 命令ID=0x${commandId.toRadixString(16).padLeft(4, '0')}, ' +
'包类型=0x${parsedPacket.packetType.toRadixString(16).padLeft(2, '0')}, ' +
'数据长度=${parsedPacket.data.length}字节');
} else {
AppLogger.warn('🔍 无效或无法识别的数据包');
}
} catch (e) {
AppLogger.warn('🔍 无法解析的数据包: $e');
}
}
/// ✨✨✨ 清除所有解析器 ✨✨✨
void clear() {
AppLogger.info('🧹 清除所有命令解析器');
_parsers.clear();
}
/// ✨✨✨ 重新初始化 ✨✨✨
void reinitialize() {
AppLogger.info('🔄 重新初始化命令管理器');
clear();
_initialize();
}
}