- 移除自定义时间戳+随机数ID生成逻辑 - 集成uuid包依赖并配置版本 - 使用Uuid.v4()替换原有next()方法实现 - 更新MessageIdGenerator类文档注释 - 在JSON协议层添加设备日志警告输出 - 修改pubspec.yaml添加uuid依赖声明
160 lines
4.3 KiB
Dart
160 lines
4.3 KiB
Dart
import 'dart:convert';
|
||
|
||
import 'package:uuid/uuid.dart';
|
||
|
||
/// 下位机消息类型
|
||
///
|
||
/// 对应《下位机交互数据模型.md》中定义的四种 type 字段。
|
||
enum DeviceMessageType {
|
||
/// 设备基本信息:门状态 / 任务运行状态 / 灯状态
|
||
deviceInfo('device_info'),
|
||
|
||
/// 下发任务:步骤列表 + 温度 + 吹气时间
|
||
createTask('create_task'),
|
||
|
||
/// 灯光控制:开 / 关
|
||
lightControl('light_control'),
|
||
|
||
/// 任务控制:继续 / 停止 / 暂停
|
||
control('control');
|
||
|
||
const DeviceMessageType(this.wireName);
|
||
|
||
/// 协议层使用的字符串名称
|
||
final String wireName;
|
||
|
||
/// 从协议字符串解析消息类型;未知值返回 null
|
||
static DeviceMessageType? fromWire(String? name) {
|
||
if (name == null) return null;
|
||
for (final t in values) {
|
||
if (t.wireName == name) return t;
|
||
}
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// 下位机消息
|
||
///
|
||
/// 完整对应数据模型:
|
||
/// ```json
|
||
/// {
|
||
/// "message_id": "uuid",
|
||
/// "type": "device_info",
|
||
/// "ack": "uuid-of-original",
|
||
/// "need_ack": true,
|
||
/// "data": { ... }
|
||
/// }
|
||
/// ```
|
||
class DeviceMessage {
|
||
/// 唯一识别码。发送时由调用方生成(UUID 字符串);
|
||
/// 接收时来自协议,便于 ack 关联。
|
||
final String messageId;
|
||
|
||
/// 消息类型
|
||
final DeviceMessageType type;
|
||
|
||
/// 当本条消息是某条消息的响应时,填写被响应的 message_id;否则为 null
|
||
final String? ack;
|
||
|
||
/// 是否需要对方响应
|
||
final bool needAck;
|
||
|
||
/// 业务负载;具体结构由 [type] 决定
|
||
final Map<String, dynamic> data;
|
||
|
||
const DeviceMessage({
|
||
required this.messageId,
|
||
required this.type,
|
||
required this.data,
|
||
this.ack,
|
||
this.needAck = false,
|
||
});
|
||
|
||
/// 构造主动请求时使用的便捷工厂
|
||
factory DeviceMessage.request({
|
||
required DeviceMessageType type,
|
||
required Map<String, dynamic> data,
|
||
required String messageId,
|
||
bool needAck = false,
|
||
}) {
|
||
return DeviceMessage(
|
||
messageId: messageId,
|
||
type: type,
|
||
data: data,
|
||
ack: null,
|
||
needAck: needAck,
|
||
);
|
||
}
|
||
|
||
/// 构造应答时使用的便捷工厂
|
||
factory DeviceMessage.ackFor(DeviceMessage original, Map<String, dynamic> data) {
|
||
return DeviceMessage(
|
||
messageId: '${original.messageId}-ack',
|
||
type: original.type,
|
||
data: data,
|
||
ack: original.messageId,
|
||
needAck: false,
|
||
);
|
||
}
|
||
|
||
/// 序列化为协议层 Map
|
||
Map<String, dynamic> toJson() => {
|
||
'message_id': messageId,
|
||
'type': type.wireName,
|
||
'ack': ack,
|
||
'need_ack': needAck,
|
||
'data': data,
|
||
};
|
||
|
||
/// 序列化为 JSON 字符串
|
||
String encode() => jsonEncode(toJson());
|
||
|
||
/// 从 JSON Map 解析;不抛异常,解析失败时返回 null
|
||
static DeviceMessage? fromJson(Map<String, dynamic> json) {
|
||
final type = DeviceMessageType.fromWire(json['type'] as String?);
|
||
if (type == null) return null;
|
||
final messageId = json['message_id'] as String?;
|
||
if (messageId == null || messageId.isEmpty) return null;
|
||
return DeviceMessage(
|
||
messageId: messageId,
|
||
type: type,
|
||
ack: (json['ack'] as String?)?.isEmpty == true ? null : json['ack'] as String?,
|
||
needAck: json['need_ack'] as bool? ?? false,
|
||
data: _coerceData(json['data']),
|
||
);
|
||
}
|
||
|
||
/// 从 JSON 字符串解析;解析失败时返回 null
|
||
static DeviceMessage? decode(String raw) {
|
||
try {
|
||
final map = jsonDecode(raw);
|
||
if (map is! Map<String, dynamic>) return null;
|
||
return fromJson(map);
|
||
} catch (_) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// JSON 中的 data 既可能是 Map,也可能是字符串(容错处理)
|
||
static Map<String, dynamic> _coerceData(dynamic raw) {
|
||
if (raw is Map<String, dynamic>) return raw;
|
||
if (raw is Map) return Map<String, dynamic>.from(raw);
|
||
return <String, dynamic>{};
|
||
}
|
||
|
||
@override
|
||
String toString() => 'DeviceMessage(id=$messageId, type=${type.wireName}, '
|
||
'ack=$ack, needAck=$needAck, data=${data.keys.toList()})';
|
||
}
|
||
|
||
/// 消息 ID 生成器
|
||
///
|
||
/// 基于 [Uuid.v4] 生成全局唯一 ID(128 位随机,标准 36 字符 hex-with-dashes 形式)。
|
||
/// 例如 `550e8400-e29b-41d4-a716-446655440000`。
|
||
class MessageIdGenerator {
|
||
static const Uuid _uuid = Uuid();
|
||
|
||
/// 生成下一个唯一 ID
|
||
String next() => _uuid.v4();
|
||
}
|