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 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 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 data) { return DeviceMessage( messageId: '${original.messageId}-ack', type: original.type, data: data, ack: original.messageId, needAck: false, ); } /// 序列化为协议层 Map Map 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 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) return null; return fromJson(map); } catch (_) { return null; } } /// JSON 中的 data 既可能是 Map,也可能是字符串(容错处理) static Map _coerceData(dynamic raw) { if (raw is Map) return raw; if (raw is Map) return Map.from(raw); return {}; } @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(); }