- * 基于 MQTT 协议规范实现的标准消息格式,兼容 Alink 协议
- *
- * @author haohao
- */
-@Data
-@Builder
-public class IotMqttMessage {
-
- /**
- * 消息 ID
- */
- private String id;
-
- /**
- * 协议版本
- */
- @Builder.Default
- private String version = "1.0";
-
- /**
- * 消息方法
- */
- private String method;
-
- /**
- * 消息参数
- */
- private Map
- * 用于统一 MQTT 和 HTTP 的响应格式
- *
- * @author haohao
- */
-@Data
-public class IotStandardResponse {
-
- /**
- * 消息 ID
- */
- private String id;
-
- /**
- * 状态码
- */
- private Integer code;
-
- /**
- * 响应数据
- */
- private Object data;
-
- /**
- * 响应消息
- */
- private String message;
-
- /**
- * 方法名
- */
- private String method;
-
- /**
- * 协议版本
- */
- private String version;
-
- /**
- * 创建成功响应
- *
- * @param id 消息 ID
- * @param method 方法名
- * @return 成功响应
- */
- public static IotStandardResponse success(String id, String method) {
- return success(id, method, null);
- }
-
- /**
- * 创建成功响应
- *
- * @param id 消息 ID
- * @param method 方法名
- * @param data 响应数据
- * @return 成功响应
- */
- public static IotStandardResponse success(String id, String method, Object data) {
- return new IotStandardResponse()
- .setId(id)
- .setCode(200)
- .setData(data)
- .setMessage("success")
- .setMethod(method)
- .setVersion("1.0");
- }
-
- /**
- * 创建错误响应
- *
- * @param id 消息 ID
- * @param method 方法名
- * @param code 错误码
- * @param message 错误消息
- * @return 错误响应
- */
- public static IotStandardResponse error(String id, String method, Integer code, String message) {
- return new IotStandardResponse()
- .setId(id)
- .setCode(code)
- .setData(null)
- .setMessage(StrUtil.blankToDefault(message, "error"))
- .setMethod(method)
- .setVersion("1.0");
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-emqx/pom.xml b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-emqx/pom.xml
deleted file mode 100644
index 7bb896e229..0000000000
--- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-emqx/pom.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
- * 默认值:5000 毫秒
- */
- private Integer reconnectDelayMs = 5000;
-
- /**
- * 连接超时时间(毫秒)
- *
- * 默认值:10000 毫秒
- */
- private Integer connectionTimeoutMs = 10000;
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-emqx/src/main/java/cn/iocoder/yudao/module/iot/net/component/emqx/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-emqx/src/main/java/cn/iocoder/yudao/module/iot/net/component/emqx/downstream/IotDeviceDownstreamHandlerImpl.java
deleted file mode 100644
index d8e91a676f..0000000000
--- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-emqx/src/main/java/cn/iocoder/yudao/module/iot/net/component/emqx/downstream/IotDeviceDownstreamHandlerImpl.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package cn.iocoder.yudao.module.iot.net.component.emqx.downstream;
-
-// TODO @芋艿:后续再支持下;@haohao;改成消费者
-///**
-// * EMQX 网络组件的 {@link IotDeviceDownstreamHandler} 实现类
-// *
-// * @author 芋道源码
-// */
-//@Slf4j
-//public class IotDeviceDownstreamHandlerImpl {
-//
-// /**
-// * MQTT 客户端
-// */
-// private final MqttClient mqttClient;
-//
-// /**
-// * 构造函数
-// *
-// * @param mqttClient MQTT 客户端
-// */
-// public IotDeviceDownstreamHandlerImpl(MqttClient mqttClient) {
-// this.mqttClient = mqttClient;
-// }
-//
-// @Override
-// public CommonResult
- * 协议:HTTP、MQTT
- *
- * @author haohao
- */
-@Slf4j
-public class IotDeviceUpstreamServer {
-
- /**
- * 默认 QoS 级别
- */
- private static final MqttQoS DEFAULT_QOS = MqttQoS.AT_LEAST_ONCE;
-
- private final Vertx vertx;
- private final HttpServer server;
- private final MqttClient client;
- private final IotNetComponentEmqxProperties emqxProperties;
- private final IotDeviceMqttMessageHandler mqttMessageHandler;
-
- /**
- * 服务运行状态标志
- */
- private volatile boolean isRunning = false;
-
- public IotDeviceUpstreamServer(IotNetComponentEmqxProperties emqxProperties,
- IotDeviceUpstreamApi deviceUpstreamApi,
- Vertx vertx,
- MqttClient client) {
- this.vertx = vertx;
- this.emqxProperties = emqxProperties;
- this.client = client;
-
- // 创建 Router 实例
- Router router = Router.router(vertx);
- router.route().handler(BodyHandler.create()); // 处理 Body
- router.post(IotDeviceAuthVertxHandler.PATH)
- // MQTT 认证不必须通过 HTTP 进行,但 HTTP 认证是 EMQX 等 MQTT 服务器支持的一种灵活的认证方式
- .handler(new IotDeviceAuthVertxHandler(deviceUpstreamApi));
- // 添加 Webhook 处理器,用于处理设备连接和断开连接事件
- router.post(IotDeviceWebhookVertxHandler.PATH)
- .handler(new IotDeviceWebhookVertxHandler(deviceUpstreamApi));
- // 创建 HttpServer 实例
- this.server = vertx.createHttpServer().requestHandler(router);
- this.mqttMessageHandler = new IotDeviceMqttMessageHandler(deviceUpstreamApi, client);
- }
-
- /**
- * 启动 HTTP 服务器、MQTT 客户端
- */
- public void start() {
- if (isRunning) {
- log.warn("[start][服务已经在运行中,请勿重复启动]");
- return;
- }
- log.info("[start][开始启动服务]");
-
- // 检查 authPort 是否为 null
- // TODO @haohao:authPort 里面搞默认值?包括下面,这个类不搞任何默认值,都交给 emqxProperties
- Integer authPort = emqxProperties.getAuthPort();
- if (authPort == null) {
- log.warn("[start][authPort 为 null,使用默认端口 8080]");
- authPort = 8080; // 默认端口
- }
-
- // 获取连接超时时间
- int connectionTimeoutMs = emqxProperties.getConnectionTimeoutMs() != null
- ? emqxProperties.getConnectionTimeoutMs()
- : 10000;
-
- // 1. 启动 HTTP 服务器
- final Integer finalAuthPort = authPort; // 为 lambda 表达式创建 final 变量
- CompletableFuture
- * 参考:EMQX HTTP
- *
- * 注意:该处理器需要返回特定格式:{"result": "allow"} 或 {"result": "deny"},
- * 以符合 EMQX 认证插件的要求,因此不使用 IotStandardResponse 实体类
- *
- * @author haohao
- */
-@RequiredArgsConstructor
-@Slf4j
-public class IotDeviceAuthVertxHandler implements Handler
- * 参考:设备属性、事件、服务
- */
-@Slf4j
-public class IotDeviceMqttMessageHandler {
-
- // TODO @haohao:下面的,有办法也抽到 IotDeviceTopicEnum 么?想的是,尽量把这些 method、topic、url 统一化;
- private static final String PROPERTY_METHOD = "thing.event.property.post";
- private static final String EVENT_METHOD_PREFIX = "thing.event.";
- private static final String EVENT_METHOD_SUFFIX = ".post";
-
- private final IotDeviceUpstreamApi deviceUpstreamApi;
- private final MqttClient mqttClient;
-
- public IotDeviceMqttMessageHandler(IotDeviceUpstreamApi deviceUpstreamApi, MqttClient mqttClient) {
- this.deviceUpstreamApi = deviceUpstreamApi;
- this.mqttClient = mqttClient;
- }
-
- /**
- * 处理MQTT消息
- *
- * @param message MQTT发布消息
- */
- public void handle(MqttPublishMessage message) {
- String topic = message.topicName();
- String payload = message.payload().toString();
- log.info("[messageHandler][接收到消息][topic: {}][payload: {}]", topic, payload);
-
- try {
- if (StrUtil.isEmpty(payload)) {
- log.warn("[messageHandler][消息内容为空][topic: {}]", topic);
- return;
- }
- handleMessage(topic, payload);
- } catch (Exception e) {
- log.error("[messageHandler][处理消息失败][topic: {}][payload: {}]", topic, payload, e);
- }
- }
-
- /**
- * 根据主题类型处理消息
- *
- * @param topic 主题
- * @param payload 消息内容
- */
- private void handleMessage(String topic, String payload) {
- // 校验前缀
- if (!topic.startsWith(IotDeviceTopicEnum.SYS_TOPIC_PREFIX.getTopic())) {
- log.warn("[handleMessage][未知的消息类型][topic: {}]", topic);
- return;
- }
-
- // 处理设备属性上报消息
- if (topic.endsWith(IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic())) {
- log.info("[handleMessage][接收到设备属性上报][topic: {}]", topic);
- handlePropertyPost(topic, payload);
- return;
- }
-
- // 处理设备事件上报消息
- if (topic.contains(IotDeviceTopicEnum.EVENT_POST_TOPIC_PREFIX.getTopic()) &&
- topic.endsWith(IotDeviceTopicEnum.EVENT_POST_TOPIC_SUFFIX.getTopic())) {
- log.info("[handleMessage][接收到设备事件上报][topic: {}]", topic);
- handleEventPost(topic, payload);
- return;
- }
-
- // 未知消息类型
- log.warn("[handleMessage][未知的消息类型][topic: {}]", topic);
- }
-
- /**
- * 处理设备属性上报消息
- *
- * @param topic 主题
- * @param payload 消息内容
- */
- private void handlePropertyPost(String topic, String payload) {
- try {
- // 解析消息内容
- JSONObject jsonObject = JSONUtil.parseObj(payload);
- String[] topicParts = parseTopic(topic);
- if (topicParts == null) {
- return;
- }
-
- // 构建设备属性上报请求对象
- IotDevicePropertyReportReqDTO reportReqDTO = buildPropertyReportDTO(jsonObject, topicParts);
-
- // 调用上游 API 处理设备上报数据
- deviceUpstreamApi.reportDeviceProperty(reportReqDTO);
- log.info("[handlePropertyPost][处理设备属性上报成功][topic: {}]", topic);
-
- // 发送响应消息
- sendResponse(topic, jsonObject, PROPERTY_METHOD, null);
- } catch (Exception e) {
- log.error("[handlePropertyPost][处理设备属性上报失败][topic: {}][payload: {}]", topic, payload, e);
- }
- }
-
- /**
- * 处理设备事件上报消息
- *
- * @param topic 主题
- * @param payload 消息内容
- */
- private void handleEventPost(String topic, String payload) {
- try {
- // 解析消息内容
- JSONObject jsonObject = JSONUtil.parseObj(payload);
- String[] topicParts = parseTopic(topic);
- if (topicParts == null) {
- return;
- }
-
- // 构建设备事件上报请求对象
- IotDeviceEventReportReqDTO reportReqDTO = buildEventReportDTO(jsonObject, topicParts);
-
- // 调用上游 API 处理设备上报数据
- deviceUpstreamApi.reportDeviceEvent(reportReqDTO);
- log.info("[handleEventPost][处理设备事件上报成功][topic: {}]", topic);
-
- // 从 topic 中获取事件标识符
- String eventIdentifier = getEventIdentifier(topicParts, topic);
- if (eventIdentifier == null) {
- return;
- }
-
- // 发送响应消息
- String method = EVENT_METHOD_PREFIX + eventIdentifier + EVENT_METHOD_SUFFIX;
- sendResponse(topic, jsonObject, method, null);
- } catch (Exception e) {
- log.error("[handleEventPost][处理设备事件上报失败][topic: {}][payload: {}]", topic, payload, e);
- }
- }
-
- /**
- * 解析主题,获取主题各部分
- *
- * @param topic 主题
- * @return 主题各部分数组,如果解析失败返回null
- */
- private String[] parseTopic(String topic) {
- String[] topicParts = topic.split("/");
- if (topicParts.length < 7) {
- log.warn("[parseTopic][主题格式不正确][topic: {}]", topic);
- return null;
- }
- return topicParts;
- }
-
- /**
- * 从主题部分中获取事件标识符
- *
- * @param topicParts 主题各部分
- * @param topic 原始主题,用于日志
- * @return 事件标识符,如果获取失败返回null
- */
- private String getEventIdentifier(String[] topicParts, String topic) {
- try {
- return topicParts[6];
- } catch (ArrayIndexOutOfBoundsException e) {
- log.warn("[getEventIdentifier][无法从主题中获取事件标识符][topic: {}][topicParts: {}]",
- topic, Arrays.toString(topicParts));
- return null;
- }
- }
-
- /**
- * 发送响应消息
- *
- * @param topic 原始主题
- * @param jsonObject 原始消息JSON对象
- * @param method 响应方法
- * @param customData 自定义数据,可为 null
- */
- private void sendResponse(String topic, JSONObject jsonObject, String method, Object customData) {
- String replyTopic = IotDeviceTopicEnum.getReplyTopic(topic);
-
- // 响应结果
- IotStandardResponse response = IotStandardResponse.success(
- jsonObject.getStr("id"), method, customData);
- try {
- mqttClient.publish(replyTopic, Buffer.buffer(JsonUtils.toJsonString(response)),
- MqttQoS.AT_LEAST_ONCE, false, false);
- log.info("[sendResponse][发送响应消息成功][topic: {}]", replyTopic);
- } catch (Exception e) {
- log.error("[sendResponse][发送响应消息失败][topic: {}][response: {}]", replyTopic, response, e);
- }
- }
-
- /**
- * 构建设备属性上报请求对象
- *
- * @param jsonObject 消息内容
- * @param topicParts 主题部分
- * @return 设备属性上报请求对象
- */
- private IotDevicePropertyReportReqDTO buildPropertyReportDTO(JSONObject jsonObject, String[] topicParts) {
- // TODO @haohao:IotDevicePropertyReportReqDTO 可以考虑链式哈。其它也是,尽量让同类参数在一行;这样,阅读起来更聚焦;
- IotDevicePropertyReportReqDTO reportReqDTO = new IotDevicePropertyReportReqDTO();
- reportReqDTO.setRequestId(jsonObject.getStr("id"));
- reportReqDTO.setProcessId(IotNetComponentCommonUtils.getProcessId());
- reportReqDTO.setReportTime(LocalDateTime.now());
- reportReqDTO.setProductKey(topicParts[2]);
- reportReqDTO.setDeviceName(topicParts[3]);
-
- // 只使用标准 JSON格式处理属性数据
- JSONObject params = jsonObject.getJSONObject("params");
- if (params == null) {
- log.warn("[buildPropertyReportDTO][消息格式不正确,缺少params字段][jsonObject: {}]", jsonObject);
- params = new JSONObject();
- }
-
- // 将标准格式的params转换为平台需要的properties格式
- Map
- * 参考:EMQX Webhook
- *
- * 注意:该处理器需要返回特定格式:{"result": "success"} 或 {"result": "error"},
- * 以符合 EMQX Webhook 插件的要求,因此不使用 IotStandardResponse 实体类。
- *
- * @author haohao
- */
-@RequiredArgsConstructor
-@Slf4j
-public class IotDeviceWebhookVertxHandler implements Handler
- * 如果用户没有自定义协议转换器,则使用默认实现
- * 默认会注册 MQTT 和 HTTP 协议解析器
- *
- * @param iotMqttMessageParser MQTT 协议解析器
- * @param iotHttpMessageParser HTTP 协议解析器
- * @return 默认协议转换器
- */
- @Bean
- @ConditionalOnMissingBean
- public IotProtocolConverter iotProtocolConverter(IotMessageParser iotMqttMessageParser,
- IotMessageParser iotHttpMessageParser) {
- DefaultIotProtocolConverter converter = new DefaultIotProtocolConverter();
-
- // 注册 MQTT 协议解析器(默认实现)
- converter.registerParser(IotProtocolTypeEnum.MQTT.getCode(), iotMqttMessageParser);
-
- // 注册 HTTP 协议解析器
- converter.registerParser(IotProtocolTypeEnum.HTTP.getCode(), iotHttpMessageParser);
-
- return converter;
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotHttpConstants.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotHttpConstants.java
deleted file mode 100644
index aeb4b3240f..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotHttpConstants.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.constants;
-
-/**
- * IoT HTTP 协议常量类
- *
- * 用于统一管理 HTTP 协议中的常量,包括路径、字段名、默认值等
- *
- * @author haohao
- */
-public class IotHttpConstants {
-
- /**
- * 路径常量
- */
- public static class Path {
- /**
- * 认证路径
- */
- public static final String AUTH = "/auth";
-
- /**
- * 主题路径前缀
- */
- public static final String TOPIC_PREFIX = "/topic";
- }
-
- /**
- * 认证字段常量
- */
- public static class AuthField {
- /**
- * 产品Key
- */
- public static final String PRODUCT_KEY = "productKey";
-
- /**
- * 设备名称
- */
- public static final String DEVICE_NAME = "deviceName";
-
- /**
- * 客户端ID
- */
- public static final String CLIENT_ID = "clientId";
-
- /**
- * 时间戳
- */
- public static final String TIMESTAMP = "timestamp";
-
- /**
- * 签名
- */
- public static final String SIGN = "sign";
-
- /**
- * 签名方法
- */
- public static final String SIGN_METHOD = "signmethod";
-
- /**
- * 版本
- */
- public static final String VERSION = "version";
- }
-
- /**
- * 消息字段常量
- */
- public static class MessageField {
- /**
- * 消息ID
- */
- public static final String ID = "id";
-
- /**
- * 方法名
- */
- public static final String METHOD = "method";
-
- /**
- * 版本
- */
- public static final String VERSION = "version";
-
- /**
- * 参数
- */
- public static final String PARAMS = "params";
-
- /**
- * 数据
- */
- public static final String DATA = "data";
- }
-
- /**
- * 响应字段常量
- */
- public static class ResponseField {
- /**
- * 状态码
- */
- public static final String CODE = "code";
-
- /**
- * 消息
- */
- public static final String MESSAGE = "message";
-
- /**
- * 信息
- */
- public static final String INFO = "info";
-
- /**
- * 令牌
- */
- public static final String TOKEN = "token";
-
- /**
- * 消息ID
- */
- public static final String MESSAGE_ID = "messageId";
- }
-
- /**
- * 默认值常量
- */
- public static class DefaultValue {
- /**
- * 默认签名方法
- */
- public static final String SIGN_METHOD = "hmacmd5";
-
- /**
- * 默认版本
- */
- public static final String VERSION = "default";
-
- /**
- * 默认消息版本
- */
- public static final String MESSAGE_VERSION = "1.0";
-
- /**
- * 未知方法名
- */
- public static final String UNKNOWN_METHOD = "unknown";
- }
-
- /**
- * 方法名常量
- */
- public static class Method {
- /**
- * 设备认证
- */
- public static final String DEVICE_AUTH = "device.auth";
-
- /**
- * 自定义消息
- */
- public static final String CUSTOM_MESSAGE = "custom.message";
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotLogConstants.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotLogConstants.java
deleted file mode 100644
index 05b7179870..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotLogConstants.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.constants;
-
-/**
- * IoT 协议日志消息常量类
- *
- * 用于统一管理协议模块中的日志消息常量
- *
- * @author haohao
- */
-public class IotLogConstants {
-
- /**
- * HTTP 协议日志消息
- */
- public static class Http {
- /**
- * 收到空消息内容
- */
- public static final String RECEIVED_EMPTY_MESSAGE = "[HTTP] 收到空消息内容, topic={}";
-
- /**
- * 不支持的路径格式
- */
- public static final String UNSUPPORTED_PATH_FORMAT = "[HTTP] 不支持的路径格式, topic={}";
-
- /**
- * 解析消息失败
- */
- public static final String PARSE_MESSAGE_FAILED = "[HTTP] 解析消息失败, topic={}";
-
- /**
- * 认证消息非JSON格式
- */
- public static final String AUTH_MESSAGE_NOT_JSON = "[HTTP] 认证消息非JSON格式, message={}";
-
- /**
- * 认证消息缺少必需字段
- */
- public static final String AUTH_MESSAGE_MISSING_REQUIRED_FIELDS = "[HTTP] 认证消息缺少必需字段, message={}";
-
- /**
- * 格式化响应失败
- */
- public static final String FORMAT_RESPONSE_FAILED = "[HTTP] 格式化响应失败";
- }
-
- /**
- * 协议转换器日志消息
- */
- public static class Converter {
- /**
- * 注册协议解析器
- */
- public static final String REGISTER_PARSER = "[协议转换器] 注册协议解析器: protocol={}, parser={}";
-
- /**
- * 移除协议解析器
- */
- public static final String REMOVE_PARSER = "[协议转换器] 移除协议解析器: protocol={}";
-
- /**
- * 不支持的协议类型
- */
- public static final String UNSUPPORTED_PROTOCOL = "[协议转换器] 不支持的协议类型: protocol={}";
-
- /**
- * 转换消息失败
- */
- public static final String CONVERT_MESSAGE_FAILED = "[协议转换器] 转换消息失败: protocol={}, topic={}";
-
- /**
- * 格式化响应失败
- */
- public static final String FORMAT_RESPONSE_FAILED = "[协议转换器] 格式化响应失败: protocol={}";
-
- /**
- * 自动选择协议
- */
- public static final String AUTO_SELECT_PROTOCOL = "[协议转换器] 自动选择协议: protocol={}, topic={}";
-
- /**
- * 协议解析失败,尝试下一个
- */
- public static final String PROTOCOL_PARSE_FAILED_TRY_NEXT = "[协议转换器] 协议解析失败,尝试下一个: protocol={}, topic={}";
-
- /**
- * 无法自动识别协议
- */
- public static final String CANNOT_AUTO_RECOGNIZE_PROTOCOL = "[协议转换器] 无法自动识别协议: topic={}";
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotTopicConstants.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotTopicConstants.java
deleted file mode 100644
index 59453518cd..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/constants/IotTopicConstants.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.constants;
-
-/**
- * IoT 设备主题常量类
- *
- * 用于统一管理 MQTT 协议中的主题常量,基于 Alink 协议规范
- *
- * @author haohao
- */
-public class IotTopicConstants {
-
- /**
- * 系统主题前缀
- */
- public static final String SYS_TOPIC_PREFIX = "/sys/";
-
- /**
- * 服务调用主题前缀
- */
- public static final String SERVICE_TOPIC_PREFIX = "/thing/service/";
-
- /**
- * 设备属性设置主题
- * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/set
- * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply
- */
- public static final String PROPERTY_SET_TOPIC = "/thing/service/property/set";
-
- /**
- * 设备属性获取主题
- * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/get
- * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/get_reply
- */
- public static final String PROPERTY_GET_TOPIC = "/thing/service/property/get";
-
- /**
- * 设备配置设置主题
- * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/config/set
- * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/config/set_reply
- */
- public static final String CONFIG_SET_TOPIC = "/thing/service/config/set";
-
- /**
- * 设备OTA升级主题
- * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/ota/upgrade
- * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/ota/upgrade_reply
- */
- public static final String OTA_UPGRADE_TOPIC = "/thing/service/ota/upgrade";
-
- /**
- * 设备属性上报主题
- * 请求Topic:/sys/${productKey}/${deviceName}/thing/event/property/post
- * 响应Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply
- */
- public static final String PROPERTY_POST_TOPIC = "/thing/event/property/post";
-
- /**
- * 设备事件上报主题前缀
- */
- public static final String EVENT_POST_TOPIC_PREFIX = "/thing/event/";
-
- /**
- * 设备事件上报主题后缀
- */
- public static final String EVENT_POST_TOPIC_SUFFIX = "/post";
-
- /**
- * 响应主题后缀
- */
- public static final String REPLY_SUFFIX = "_reply";
-
- /**
- * 方法名前缀常量
- */
- public static class MethodPrefix {
- /**
- * 物模型服务前缀
- */
- public static final String THING_SERVICE = "thing.service.";
-
- /**
- * 物模型事件前缀
- */
- public static final String THING_EVENT = "thing.event.";
- }
-
- /**
- * 完整方法名常量
- */
- public static class Method {
- /**
- * 属性设置方法
- */
- public static final String PROPERTY_SET = "thing.service.property.set";
-
- /**
- * 属性获取方法
- */
- public static final String PROPERTY_GET = "thing.service.property.get";
-
- /**
- * 属性上报方法
- */
- public static final String PROPERTY_POST = "thing.event.property.post";
-
- /**
- * 配置设置方法
- */
- public static final String CONFIG_SET = "thing.service.config.set";
-
- /**
- * OTA升级方法
- */
- public static final String OTA_UPGRADE = "thing.service.ota.upgrade";
-
- /**
- * 设备上线方法
- */
- public static final String DEVICE_ONLINE = "device.online";
-
- /**
- * 设备下线方法
- */
- public static final String DEVICE_OFFLINE = "device.offline";
-
- /**
- * 心跳方法
- */
- public static final String HEARTBEAT = "heartbeat";
- }
-
- /**
- * 主题关键字常量
- */
- public static class Keyword {
- /**
- * 事件关键字
- */
- public static final String EVENT = "event";
-
- /**
- * 服务关键字
- */
- public static final String SERVICE = "service";
-
- /**
- * 属性关键字
- */
- public static final String PROPERTY = "property";
-
- /**
- * 上报关键字
- */
- public static final String POST = "post";
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/convert/IotProtocolConverter.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/convert/IotProtocolConverter.java
deleted file mode 100644
index b942feb97f..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/convert/IotProtocolConverter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.convert;
-
-import cn.iocoder.yudao.module.iot.protocol.message.IotMqttMessage;
-import cn.iocoder.yudao.module.iot.protocol.message.IotStandardResponse;
-
-/**
- * IoT 协议转换器接口
- *
- * 用于在不同协议之间进行转换
- *
- * @author haohao
- */
-public interface IotProtocolConverter {
-
- /**
- * 将字节数组转换为标准消息
- *
- * @param topic 主题
- * @param payload 消息负载
- * @param protocol 协议类型
- * @return 标准消息对象,转换失败返回 null
- */
- IotMqttMessage convertToStandardMessage(String topic, byte[] payload, String protocol);
-
- /**
- * 将标准响应转换为字节数组
- *
- * @param response 标准响应
- * @param protocol 协议类型
- * @return 字节数组,转换失败返回空数组
- */
- byte[] convertFromStandardResponse(IotStandardResponse response, String protocol);
-
- /**
- * 检查是否支持指定协议
- *
- * @param protocol 协议类型
- * @return 如果支持返回 true,否则返回 false
- */
- boolean supportsProtocol(String protocol);
-
- /**
- * 获取支持的协议类型列表
- *
- * @return 协议类型数组
- */
- String[] getSupportedProtocols();
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/convert/impl/DefaultIotProtocolConverter.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/convert/impl/DefaultIotProtocolConverter.java
deleted file mode 100644
index 798eca01a0..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/convert/impl/DefaultIotProtocolConverter.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.convert.impl;
-
-import cn.iocoder.yudao.module.iot.protocol.constants.IotLogConstants;
-import cn.iocoder.yudao.module.iot.protocol.convert.IotProtocolConverter;
-import cn.iocoder.yudao.module.iot.protocol.enums.IotProtocolTypeEnum;
-import cn.iocoder.yudao.module.iot.protocol.message.IotMessageParser;
-import cn.iocoder.yudao.module.iot.protocol.message.IotMqttMessage;
-import cn.iocoder.yudao.module.iot.protocol.message.IotStandardResponse;
-import cn.iocoder.yudao.module.iot.protocol.message.impl.IotMqttMessageParser;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * 默认 IoT 协议转换器实现
- *
- * 支持多种协议的转换,可以通过注册不同的消息解析器来扩展支持的协议
- *
- * @author haohao
- */
-@Slf4j
-public class DefaultIotProtocolConverter implements IotProtocolConverter {
-
- /**
- * 消息解析器映射
- * Key: 协议类型,Value: 消息解析器
- */
- private final Map
- * 用于解析不同协议的消息内容
- *
- * @author haohao
- */
-public interface IotMessageParser {
-
- /**
- * 解析消息
- *
- * @param topic 主题
- * @param payload 消息负载
- * @return 解析后的标准消息,如果解析失败返回 null
- */
- IotMqttMessage parse(String topic, byte[] payload);
-
- /**
- * 格式化响应消息
- *
- * @param response 标准响应
- * @return 格式化后的响应字节数组
- */
- byte[] formatResponse(IotStandardResponse response);
-
- /**
- * 检查是否能够处理指定主题的消息
- *
- * @param topic 主题
- * @return 如果能处理返回 true,否则返回 false
- */
- boolean canHandle(String topic);
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/message/IotMqttMessage.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/message/IotMqttMessage.java
deleted file mode 100644
index 36cc1a7f06..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/message/IotMqttMessage.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.message;
-
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.json.JSONObject;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.Map;
-
-/**
- * IoT MQTT 消息模型
- *
- * 基于 MQTT 协议规范实现的标准消息格式,支持设备属性、事件、服务调用等标准功能
- *
- * @author haohao
- * @see MQTT 协议官方规范
- */
-@Data
-@Builder
-public class IotMqttMessage {
-
- /**
- * 消息 ID
- */
- private String id;
-
- /**
- * 协议版本
- */
- @Builder.Default
- private String version = "1.0";
-
- /**
- * 消息方法
- */
- private String method;
-
- /**
- * 消息参数
- */
- private Map
- * 用于统一 MQTT 和 HTTP 的响应格式
- *
- * @author haohao
- */
-@Data
-@Accessors(chain = true)
-public class IotStandardResponse {
-
- /**
- * 消息 ID
- */
- private String id;
-
- /**
- * 状态码
- */
- private Integer code;
-
- /**
- * 响应数据
- */
- private Object data;
-
- /**
- * 响应消息
- */
- private String message;
-
- /**
- * 方法名
- */
- private String method;
-
- /**
- * 协议版本
- */
- private String version;
-
- /**
- * 创建成功响应
- *
- * @param id 消息 ID
- * @param method 方法名
- * @return 成功响应
- */
- public static IotStandardResponse success(String id, String method) {
- return success(id, method, null);
- }
-
- /**
- * 创建成功响应
- *
- * @param id 消息 ID
- * @param method 方法名
- * @param data 响应数据
- * @return 成功响应
- */
- public static IotStandardResponse success(String id, String method, Object data) {
- return new IotStandardResponse()
- .setId(id)
- .setCode(200)
- .setData(data)
- .setMessage("success")
- .setMethod(method)
- .setVersion("1.0");
- }
-
- /**
- * 创建错误响应
- *
- * @param id 消息 ID
- * @param method 方法名
- * @param code 错误码
- * @param message 错误消息
- * @return 错误响应
- */
- public static IotStandardResponse error(String id, String method, Integer code, String message) {
- return new IotStandardResponse()
- .setId(id)
- .setCode(code)
- .setData(null)
- .setMessage(StrUtil.blankToDefault(message, "error"))
- .setMethod(method)
- .setVersion("1.0");
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/message/impl/IotHttpMessageParser.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/message/impl/IotHttpMessageParser.java
deleted file mode 100644
index 2ce4625c34..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/message/impl/IotHttpMessageParser.java
+++ /dev/null
@@ -1,348 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.message.impl;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONObject;
-import cn.hutool.json.JSONUtil;
-import cn.iocoder.yudao.module.iot.protocol.constants.IotHttpConstants;
-import cn.iocoder.yudao.module.iot.protocol.constants.IotLogConstants;
-import cn.iocoder.yudao.module.iot.protocol.constants.IotTopicConstants;
-import cn.iocoder.yudao.module.iot.protocol.message.IotMessageParser;
-import cn.iocoder.yudao.module.iot.protocol.message.IotMqttMessage;
-import cn.iocoder.yudao.module.iot.protocol.message.IotStandardResponse;
-import lombok.extern.slf4j.Slf4j;
-
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * IoT HTTP 协议消息解析器实现
- *
- * 参考阿里云IoT平台HTTPS协议标准,支持设备认证和数据上报两种消息类型:
- *
- * 1. 设备认证消息格式:
- *
- *
- * 2. 数据上报消息格式:
- *
- *
- * 基于 MQTT 协议规范实现的消息解析器,支持设备属性、事件、服务调用等标准功能
- *
- * @author haohao
- */
-@Slf4j
-public class IotMqttMessageParser implements IotMessageParser {
-
- @Override
- public IotMqttMessage parse(String topic, byte[] payload) {
- if (payload == null || payload.length == 0) {
- log.warn("[MQTT] 收到空消息内容, topic={}", topic);
- return null;
- }
-
- try {
- String message = new String(payload, StandardCharsets.UTF_8);
- if (!JSONUtil.isTypeJSON(message)) {
- log.warn("[MQTT] 收到非JSON格式消息, topic={}, message={}", topic, message);
- return null;
- }
-
- JSONObject json = JSONUtil.parseObj(message);
- String id = json.getStr("id");
- String method = json.getStr("method");
-
- if (StrUtil.isBlank(method)) {
- // 尝试从 topic 中解析方法
- method = IotTopicUtils.parseMethodFromTopic(topic);
- if (StrUtil.isBlank(method)) {
- log.warn("[MQTT] 无法确定消息方法, topic={}, message={}", topic, message);
- return null;
- }
- }
-
- @SuppressWarnings("unchecked")
- Map
- * 参考阿里云IoT平台HTTPS协议标准,支持以下路径格式:
- * 1. 设备认证:/auth
- * 2. 数据上报:/topic/${actualTopic}
- *
- * 其中 actualTopic 遵循MQTT主题规范,例如:
- * - /sys/{productKey}/{deviceName}/thing/service/property/set
- * - /{productKey}/{deviceName}/user/get
- *
- * @author haohao
- */
-public class IotHttpTopicUtils {
-
- /**
- * 设备认证路径
- */
- public static final String AUTH_PATH = "/auth";
-
- /**
- * 数据上报路径前缀
- */
- public static final String TOPIC_PATH_PREFIX = "/topic";
-
- /**
- * 系统主题前缀
- */
- public static final String SYS_TOPIC_PREFIX = "/sys";
-
- /**
- * 构建设备认证路径
- *
- * @return 认证路径
- */
- public static String buildAuthPath() {
- return AUTH_PATH;
- }
-
- /**
- * 构建数据上报路径
- *
- * @param actualTopic 实际的MQTT主题
- * @return HTTP数据上报路径
- */
- public static String buildTopicPath(String actualTopic) {
- if (StrUtil.isBlank(actualTopic)) {
- return null;
- }
- return TOPIC_PATH_PREFIX + actualTopic;
- }
-
- /**
- * 构建系统属性设置路径
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return HTTP路径
- */
- public static String buildPropertySetPath(String productKey, String deviceName) {
- if (StrUtil.hasBlank(productKey, deviceName)) {
- return null;
- }
- String actualTopic = SYS_TOPIC_PREFIX + "/" + productKey + "/" + deviceName + "/thing/service/property/set";
- return buildTopicPath(actualTopic);
- }
-
- /**
- * 构建系统属性获取路径
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return HTTP路径
- */
- public static String buildPropertyGetPath(String productKey, String deviceName) {
- if (StrUtil.hasBlank(productKey, deviceName)) {
- return null;
- }
- String actualTopic = SYS_TOPIC_PREFIX + "/" + productKey + "/" + deviceName + "/thing/service/property/get";
- return buildTopicPath(actualTopic);
- }
-
- /**
- * 构建系统属性上报路径
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return HTTP路径
- */
- public static String buildPropertyPostPath(String productKey, String deviceName) {
- if (StrUtil.hasBlank(productKey, deviceName)) {
- return null;
- }
- String actualTopic = SYS_TOPIC_PREFIX + "/" + productKey + "/" + deviceName + "/thing/event/property/post";
- return buildTopicPath(actualTopic);
- }
-
- /**
- * 构建系统事件上报路径
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @param eventIdentifier 事件标识符
- * @return HTTP路径
- */
- public static String buildEventPostPath(String productKey, String deviceName, String eventIdentifier) {
- if (StrUtil.hasBlank(productKey, deviceName, eventIdentifier)) {
- return null;
- }
- String actualTopic = SYS_TOPIC_PREFIX + "/" + productKey + "/" + deviceName + "/thing/event/" + eventIdentifier
- + "/post";
- return buildTopicPath(actualTopic);
- }
-
- /**
- * 构建系统服务调用路径
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @param serviceIdentifier 服务标识符
- * @return HTTP路径
- */
- public static String buildServiceInvokePath(String productKey, String deviceName, String serviceIdentifier) {
- if (StrUtil.hasBlank(productKey, deviceName, serviceIdentifier)) {
- return null;
- }
- String actualTopic = SYS_TOPIC_PREFIX + "/" + productKey + "/" + deviceName + "/thing/service/"
- + serviceIdentifier;
- return buildTopicPath(actualTopic);
- }
-
- /**
- * 构建自定义主题路径
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @param customPath 自定义路径
- * @return HTTP路径
- */
- public static String buildCustomTopicPath(String productKey, String deviceName, String customPath) {
- if (StrUtil.hasBlank(productKey, deviceName, customPath)) {
- return null;
- }
- String actualTopic = "/" + productKey + "/" + deviceName + "/" + customPath;
- return buildTopicPath(actualTopic);
- }
-
- /**
- * 从HTTP路径中提取实际主题
- *
- * @param httpPath HTTP路径,格式:/topic/${actualTopic}
- * @return 实际主题,如果解析失败返回null
- */
- public static String extractActualTopic(String httpPath) {
- if (StrUtil.isBlank(httpPath) || !httpPath.startsWith(TOPIC_PATH_PREFIX)) {
- return null;
- }
- return httpPath.substring(TOPIC_PATH_PREFIX.length()); // 直接移除/topic前缀
- }
-
- /**
- * 从主题中解析产品Key
- *
- * @param topic 主题,支持系统主题和自定义主题
- * @return 产品Key,如果无法解析则返回null
- */
- public static String parseProductKeyFromTopic(String topic) {
- if (StrUtil.isBlank(topic)) {
- return null;
- }
-
- String[] parts = topic.split("/");
-
- // 系统主题格式:/sys/{productKey}/{deviceName}/...
- if (parts.length >= 4 && "sys".equals(parts[1])) {
- return parts[2];
- }
-
- // 自定义主题格式:/{productKey}/{deviceName}/...
- // 确保不是不完整的系统主题格式
- if (parts.length >= 3 && StrUtil.isNotBlank(parts[1]) && !"sys".equals(parts[1])) {
- return parts[1];
- }
-
- return null;
- }
-
- /**
- * 从主题中解析设备名称
- *
- * @param topic 主题,支持系统主题和自定义主题
- * @return 设备名称,如果无法解析则返回null
- */
- public static String parseDeviceNameFromTopic(String topic) {
- if (StrUtil.isBlank(topic)) {
- return null;
- }
-
- String[] parts = topic.split("/");
-
- // 系统主题格式:/sys/{productKey}/{deviceName}/...
- if (parts.length >= 4 && "sys".equals(parts[1])) {
- return parts[3];
- }
-
- // 自定义主题格式:/{productKey}/{deviceName}/...
- // 确保不是不完整的系统主题格式
- if (parts.length >= 3 && StrUtil.isNotBlank(parts[2]) && !"sys".equals(parts[1])) {
- return parts[2];
- }
-
- return null;
- }
-
- /**
- * 检查是否为认证路径
- *
- * @param path 路径
- * @return 如果是认证路径返回true,否则返回false
- */
- public static boolean isAuthPath(String path) {
- return AUTH_PATH.equals(path);
- }
-
- /**
- * 检查是否为数据上报路径
- *
- * @param path 路径
- * @return 如果是数据上报路径返回true,否则返回false
- */
- public static boolean isTopicPath(String path) {
- return path != null && path.startsWith(TOPIC_PATH_PREFIX);
- }
-
- /**
- * 检查是否为有效的HTTP路径
- *
- * @param path 路径
- * @return 如果是有效的HTTP路径返回true,否则返回false
- */
- public static boolean isValidHttpPath(String path) {
- return isAuthPath(path) || isTopicPath(path);
- }
-
- /**
- * 检查是否为系统主题
- *
- * @param topic 主题
- * @return 如果是系统主题返回true,否则返回false
- */
- public static boolean isSystemTopic(String topic) {
- return topic != null && topic.startsWith(SYS_TOPIC_PREFIX);
- }
-
- /**
- * 构建响应主题路径
- *
- * @param requestPath 请求路径
- * @return 响应路径,如果无法构建返回null
- */
- public static String buildReplyPath(String requestPath) {
- String actualTopic = extractActualTopic(requestPath);
- if (actualTopic == null) {
- return null;
- }
-
- // 为系统主题添加_reply后缀
- if (isSystemTopic(actualTopic)) {
- String replyTopic = actualTopic + "_reply";
- return buildTopicPath(replyTopic);
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/util/IotTopicParser.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/util/IotTopicParser.java
deleted file mode 100644
index 05873d2bdb..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/util/IotTopicParser.java
+++ /dev/null
@@ -1,237 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.util;
-
-import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.module.iot.protocol.constants.IotTopicConstants;
-import cn.iocoder.yudao.module.iot.protocol.enums.IotMessageDirectionEnum;
-import cn.iocoder.yudao.module.iot.protocol.enums.IotMessageTypeEnum;
-import lombok.Data;
-
-/**
- * IoT 主题解析器
- *
- * 用于解析各种格式的 IoT 主题,提取其中的关键信息
- *
- * @author haohao
- */
-public class IotTopicParser {
-
- /**
- * 主题解析结果
- */
- @Data
- public static class TopicInfo {
- /**
- * 产品Key
- */
- private String productKey;
-
- /**
- * 设备名称
- */
- private String deviceName;
-
- /**
- * 消息类型
- */
- private IotMessageTypeEnum messageType;
-
- /**
- * 消息方向
- */
- private IotMessageDirectionEnum direction;
-
- /**
- * 服务标识符(仅服务调用时有效)
- */
- private String serviceIdentifier;
-
- /**
- * 事件标识符(仅事件上报时有效)
- */
- private String eventIdentifier;
-
- /**
- * 是否为响应主题
- */
- private boolean isReply;
-
- /**
- * 原始主题
- */
- private String originalTopic;
- }
-
- /**
- * 解析主题
- *
- * @param topic 主题字符串
- * @return 解析结果,如果解析失败返回 null
- */
- public static TopicInfo parse(String topic) {
- if (StrUtil.isBlank(topic)) {
- return null;
- }
-
- TopicInfo info = new TopicInfo();
- info.setOriginalTopic(topic);
-
- // 检查是否为响应主题
- boolean isReply = topic.endsWith(IotTopicConstants.REPLY_SUFFIX);
- info.setReply(isReply);
-
- // 移除响应后缀,便于后续解析
- String normalizedTopic = isReply ? topic.substring(0, topic.length() - IotTopicConstants.REPLY_SUFFIX.length())
- : topic;
-
- // 解析系统主题
- if (normalizedTopic.startsWith(IotTopicConstants.SYS_TOPIC_PREFIX)) {
- return parseSystemTopic(info, normalizedTopic);
- }
-
- // 解析自定义主题
- return parseCustomTopic(info, normalizedTopic);
- }
-
- /**
- * 解析系统主题
- * 格式:/sys/{productKey}/{deviceName}/thing/service/{identifier}
- * 或:/sys/{productKey}/{deviceName}/thing/event/{identifier}/post
- */
- private static TopicInfo parseSystemTopic(TopicInfo info, String topic) {
- String[] parts = topic.split("/");
- if (parts.length < 6) {
- return null;
- }
-
- // 解析产品Key和设备名称
- info.setProductKey(parts[2]);
- info.setDeviceName(parts[3]);
-
- // 判断消息方向:包含 /post 通常是上行,其他是下行
- info.setDirection(topic.contains("/post") || topic.contains("/reply") ? IotMessageDirectionEnum.UPSTREAM
- : IotMessageDirectionEnum.DOWNSTREAM);
-
- // 解析具体的消息类型
- if (topic.contains("/thing/service/")) {
- return parseServiceTopic(info, topic, parts);
- } else if (topic.contains("/thing/event/")) {
- return parseEventTopic(info, topic, parts);
- }
-
- return null;
- }
-
- /**
- * 解析服务相关主题
- */
- private static TopicInfo parseServiceTopic(TopicInfo info, String topic, String[] parts) {
- // 查找 service 关键字的位置
- int serviceIndex = -1;
- for (int i = 0; i < parts.length; i++) {
- if ("service".equals(parts[i])) {
- serviceIndex = i;
- break;
- }
- }
-
- if (serviceIndex == -1 || serviceIndex + 1 >= parts.length) {
- return null;
- }
-
- String serviceType = parts[serviceIndex + 1];
-
- // 根据服务类型确定消息类型
- switch (serviceType) {
- case "property":
- if (serviceIndex + 2 < parts.length) {
- String operation = parts[serviceIndex + 2];
- if ("set".equals(operation)) {
- info.setMessageType(IotMessageTypeEnum.PROPERTY_SET);
- } else if ("get".equals(operation)) {
- info.setMessageType(IotMessageTypeEnum.PROPERTY_GET);
- }
- }
- break;
- case "config":
- if (serviceIndex + 2 < parts.length && "set".equals(parts[serviceIndex + 2])) {
- info.setMessageType(IotMessageTypeEnum.CONFIG_SET);
- }
- break;
- case "ota":
- if (serviceIndex + 2 < parts.length && "upgrade".equals(parts[serviceIndex + 2])) {
- info.setMessageType(IotMessageTypeEnum.OTA_UPGRADE);
- }
- break;
- default:
- // 自定义服务
- info.setMessageType(IotMessageTypeEnum.SERVICE_INVOKE);
- info.setServiceIdentifier(serviceType);
- break;
- }
-
- return info;
- }
-
- /**
- * 解析事件相关主题
- */
- private static TopicInfo parseEventTopic(TopicInfo info, String topic, String[] parts) {
- // 查找 event 关键字的位置
- int eventIndex = -1;
- for (int i = 0; i < parts.length; i++) {
- if ("event".equals(parts[i])) {
- eventIndex = i;
- break;
- }
- }
-
- if (eventIndex == -1 || eventIndex + 1 >= parts.length) {
- return null;
- }
-
- String eventType = parts[eventIndex + 1];
-
- if ("property".equals(eventType) && eventIndex + 2 < parts.length && "post".equals(parts[eventIndex + 2])) {
- info.setMessageType(IotMessageTypeEnum.PROPERTY_POST);
- } else {
- // 自定义事件
- info.setMessageType(IotMessageTypeEnum.EVENT_POST);
- info.setEventIdentifier(eventType);
- }
-
- return info;
- }
-
- /**
- * 解析自定义主题
- * 这里可以根据实际需求扩展自定义主题的解析逻辑
- */
- private static TopicInfo parseCustomTopic(TopicInfo info, String topic) {
- // TODO: 根据业务需要实现自定义主题解析逻辑
- return info;
- }
-
- /**
- * 检查主题是否为有效的系统主题
- *
- * @param topic 主题
- * @return 如果是有效的系统主题返回 true,否则返回 false
- */
- public static boolean isValidSystemTopic(String topic) {
- TopicInfo info = parse(topic);
- return info != null &&
- StrUtil.isNotBlank(info.getProductKey()) &&
- StrUtil.isNotBlank(info.getDeviceName()) &&
- info.getMessageType() != null;
- }
-
- /**
- * 检查主题是否为响应主题
- *
- * @param topic 主题
- * @return 如果是响应主题返回 true,否则返回 false
- */
- public static boolean isReplyTopic(String topic) {
- return topic != null && topic.endsWith(IotTopicConstants.REPLY_SUFFIX);
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/util/IotTopicUtils.java b/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/util/IotTopicUtils.java
deleted file mode 100644
index 6bd447e5a9..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/java/cn/iocoder/yudao/module/iot/protocol/util/IotTopicUtils.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.util;
-
-import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.module.iot.protocol.constants.IotTopicConstants;
-
-/**
- * IoT 主题工具类
- *
- * 用于构建和解析设备主题
- *
- * @author haohao
- */
-public class IotTopicUtils {
-
- /**
- * 构建设备服务调用主题
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @param serviceIdentifier 服务标识符
- * @return 完整的主题路径
- */
- public static String buildServiceTopic(String productKey, String deviceName, String serviceIdentifier) {
- return buildDeviceBaseTopic(productKey, deviceName) +
- IotTopicConstants.SERVICE_TOPIC_PREFIX + serviceIdentifier;
- }
-
- /**
- * 构建设备属性设置主题
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return 完整的主题路径
- */
- public static String buildPropertySetTopic(String productKey, String deviceName) {
- return buildDeviceBaseTopic(productKey, deviceName) + IotTopicConstants.PROPERTY_SET_TOPIC;
- }
-
- /**
- * 构建设备属性获取主题
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return 完整的主题路径
- */
- public static String buildPropertyGetTopic(String productKey, String deviceName) {
- return buildDeviceBaseTopic(productKey, deviceName) + IotTopicConstants.PROPERTY_GET_TOPIC;
- }
-
- /**
- * 构建设备配置设置主题
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return 完整的主题路径
- */
- public static String buildConfigSetTopic(String productKey, String deviceName) {
- return buildDeviceBaseTopic(productKey, deviceName) + IotTopicConstants.CONFIG_SET_TOPIC;
- }
-
- /**
- * 构建设备 OTA 升级主题
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return 完整的主题路径
- */
- public static String buildOtaUpgradeTopic(String productKey, String deviceName) {
- return buildDeviceBaseTopic(productKey, deviceName) + IotTopicConstants.OTA_UPGRADE_TOPIC;
- }
-
- /**
- * 构建设备属性上报主题
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return 完整的主题路径
- */
- public static String buildPropertyPostTopic(String productKey, String deviceName) {
- return buildDeviceBaseTopic(productKey, deviceName) + IotTopicConstants.PROPERTY_POST_TOPIC;
- }
-
- /**
- * 构建设备事件上报主题
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @param eventIdentifier 事件标识符
- * @return 完整的主题路径
- */
- public static String buildEventPostTopic(String productKey, String deviceName, String eventIdentifier) {
- return buildDeviceBaseTopic(productKey, deviceName) +
- IotTopicConstants.EVENT_POST_TOPIC_PREFIX + eventIdentifier + IotTopicConstants.EVENT_POST_TOPIC_SUFFIX;
- }
-
- /**
- * 获取响应主题
- *
- * @param requestTopic 请求主题
- * @return 响应主题
- */
- public static String getReplyTopic(String requestTopic) {
- return requestTopic + IotTopicConstants.REPLY_SUFFIX;
- }
-
- /**
- * 构建设备基础主题
- * 格式: /sys/${productKey}/${deviceName}
- *
- * @param productKey 产品Key
- * @param deviceName 设备名称
- * @return 设备基础主题
- */
- public static String buildDeviceBaseTopic(String productKey, String deviceName) {
- return IotTopicConstants.SYS_TOPIC_PREFIX + productKey + "/" + deviceName;
- }
-
- /**
- * 从主题中解析产品Key
- * 格式: /sys/${productKey}/${deviceName}/...
- *
- * @param topic 主题
- * @return 产品Key,如果无法解析则返回null
- */
- public static String parseProductKeyFromTopic(String topic) {
- if (StrUtil.isBlank(topic) || !topic.startsWith(IotTopicConstants.SYS_TOPIC_PREFIX)) {
- return null;
- }
-
- String[] parts = topic.split("/");
- if (parts.length < 4) {
- return null;
- }
-
- return parts[2];
- }
-
- /**
- * 从主题中解析设备名称
- * 格式: /sys/${productKey}/${deviceName}/...
- *
- * @param topic 主题
- * @return 设备名称,如果无法解析则返回null
- */
- public static String parseDeviceNameFromTopic(String topic) {
- if (StrUtil.isBlank(topic) || !topic.startsWith(IotTopicConstants.SYS_TOPIC_PREFIX)) {
- return null;
- }
-
- String[] parts = topic.split("/");
- if (parts.length < 4) {
- return null;
- }
-
- return parts[3];
- }
-
- /**
- * 从主题中解析方法名
- * 例如:从 /sys/pk/dn/thing/service/property/set 解析出 property.set
- *
- * @param topic 主题
- * @return 方法名,如果无法解析则返回null
- */
- public static String parseMethodFromTopic(String topic) {
- if (StrUtil.isBlank(topic) || !topic.startsWith(IotTopicConstants.SYS_TOPIC_PREFIX)) {
- return null;
- }
-
- // 服务调用主题
- if (topic.contains("/thing/service/")) {
- String servicePart = topic.substring(topic.indexOf("/thing/service/") + "/thing/service/".length());
- return servicePart.replace("/", ".");
- }
-
- // 事件上报主题
- if (topic.contains("/thing/event/")) {
- String eventPart = topic.substring(topic.indexOf("/thing/event/") + "/thing/event/".length());
- return "event." + eventPart.replace("/", ".");
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-module-iot/yudao-module-iot-protocol/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
deleted file mode 100644
index 2b1cf8d5aa..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ /dev/null
@@ -1 +0,0 @@
-cn.iocoder.yudao.module.iot.protocol.config.IotProtocolAutoConfiguration
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/config/IotProtocolAutoConfigurationTest.java b/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/config/IotProtocolAutoConfigurationTest.java
deleted file mode 100644
index 31b6c63acb..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/config/IotProtocolAutoConfigurationTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.config;
-
-import cn.iocoder.yudao.module.iot.protocol.convert.IotProtocolConverter;
-import cn.iocoder.yudao.module.iot.protocol.enums.IotProtocolTypeEnum;
-import cn.iocoder.yudao.module.iot.protocol.message.IotMessageParser;
-import cn.iocoder.yudao.module.iot.protocol.message.impl.IotHttpMessageParser;
-import cn.iocoder.yudao.module.iot.protocol.message.impl.IotMqttMessageParser;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * {@link IotProtocolAutoConfiguration} 单元测试
- *
- * @author haohao
- */
-class IotProtocolAutoConfigurationTest {
-
- private IotProtocolAutoConfiguration configuration;
-
- @BeforeEach
- void setUp() {
- configuration = new IotProtocolAutoConfiguration();
- }
-
- @Test
- void testIotMqttMessageParser() {
- // 测试 MQTT 协议解析器 Bean 创建
- IotMessageParser parser = configuration.iotMqttMessageParser();
-
- assertNotNull(parser);
- assertInstanceOf(IotMqttMessageParser.class, parser);
- }
-
- @Test
- void testIotHttpMessageParser() {
- // 测试 HTTP 协议解析器 Bean 创建
- IotMessageParser parser = configuration.iotHttpMessageParser();
-
- assertNotNull(parser);
- assertInstanceOf(IotHttpMessageParser.class, parser);
- }
-
- @Test
- void testIotProtocolConverter() {
- // 创建解析器实例
- IotMessageParser mqttParser = configuration.iotMqttMessageParser();
- IotMessageParser httpParser = configuration.iotHttpMessageParser();
-
- // 测试协议转换器 Bean 创建
- IotProtocolConverter converter = configuration.iotProtocolConverter(mqttParser, httpParser);
-
- assertNotNull(converter);
-
- // 验证支持的协议
- assertTrue(converter.supportsProtocol(IotProtocolTypeEnum.MQTT.getCode()));
- assertTrue(converter.supportsProtocol(IotProtocolTypeEnum.HTTP.getCode()));
-
- // 验证支持的协议数量
- String[] supportedProtocols = converter.getSupportedProtocols();
- assertEquals(2, supportedProtocols.length);
- }
-
- @Test
- void testBeanNameConstants() {
- // 测试 Bean 名称常量定义
- assertEquals("iotMqttMessageParser", IotProtocolAutoConfiguration.IOT_MQTT_MESSAGE_PARSER_BEAN_NAME);
- assertEquals("iotHttpMessageParser", IotProtocolAutoConfiguration.IOT_HTTP_MESSAGE_PARSER_BEAN_NAME);
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/example/AliyunHttpProtocolExample.java b/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/example/AliyunHttpProtocolExample.java
deleted file mode 100644
index a1c1dae562..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/example/AliyunHttpProtocolExample.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.example;
-
-import cn.hutool.json.JSONObject;
-import cn.iocoder.yudao.module.iot.protocol.util.IotHttpTopicUtils;
-
-/**
- * 阿里云IoT平台HTTPS协议示例
- *
- * 参考阿里云IoT平台HTTPS连接通信标准,演示设备认证和数据上报的完整流程
- *
- * @author haohao
- */
-public class AliyunHttpProtocolExample {
-
- public static void main(String[] args) {
- System.out.println("=== 阿里云IoT平台HTTPS协议演示 ===\n");
-
- // 演示设备认证
- demonstrateDeviceAuth();
-
- // 演示数据上报
- demonstrateDataUpload();
-
- // 演示路径构建
- demonstratePathBuilding();
- }
-
- /**
- * 演示设备认证流程
- */
- private static void demonstrateDeviceAuth() {
- System.out.println("1. 设备认证流程:");
- System.out.println("认证路径: " + IotHttpTopicUtils.buildAuthPath());
-
- // 构建认证请求消息
- JSONObject authRequest = new JSONObject();
- authRequest.set("productKey", "a1GFjLP****");
- authRequest.set("deviceName", "device123");
- authRequest.set("clientId", "device123_001");
- authRequest.set("timestamp", String.valueOf(System.currentTimeMillis()));
- authRequest.set("sign", "4870141D4067227128CBB4377906C3731CAC221C");
- authRequest.set("signmethod", "hmacsha1");
- authRequest.set("version", "default");
-
- System.out.println("认证请求消息:");
- System.out.println(authRequest.toString());
-
- // 模拟认证响应
- JSONObject authResponse = new JSONObject();
- authResponse.set("code", 0);
- authResponse.set("message", "success");
-
- JSONObject info = new JSONObject();
- info.set("token", "6944e5bfb92e4d4ea3918d1eda39****");
- authResponse.set("info", info);
-
- System.out.println("认证响应:");
- System.out.println(authResponse.toString());
- System.out.println();
- }
-
- /**
- * 演示数据上报流程
- */
- private static void demonstrateDataUpload() {
- System.out.println("2. 数据上报流程:");
-
- String productKey = "a1GFjLP****";
- String deviceName = "device123";
-
- // 属性上报
- String propertyPostPath = IotHttpTopicUtils.buildPropertyPostPath(productKey, deviceName);
- System.out.println("属性上报路径: " + propertyPostPath);
-
- // Alink格式的属性上报消息
- JSONObject propertyMessage = new JSONObject();
- propertyMessage.set("id", "123456");
- propertyMessage.set("version", "1.0");
- propertyMessage.set("method", "thing.event.property.post");
-
- JSONObject propertyParams = new JSONObject();
- JSONObject properties = new JSONObject();
- properties.set("temperature", 25.6);
- properties.set("humidity", 60.3);
- propertyParams.set("properties", properties);
- propertyMessage.set("params", propertyParams);
-
- System.out.println("属性上报消息:");
- System.out.println(propertyMessage.toString());
-
- // 事件上报
- String eventPostPath = IotHttpTopicUtils.buildEventPostPath(productKey, deviceName, "temperatureAlert");
- System.out.println("\n事件上报路径: " + eventPostPath);
-
- JSONObject eventMessage = new JSONObject();
- eventMessage.set("id", "123457");
- eventMessage.set("version", "1.0");
- eventMessage.set("method", "thing.event.temperatureAlert.post");
-
- JSONObject eventParams = new JSONObject();
- eventParams.set("value", new JSONObject().set("alertLevel", "high").set("currentTemp", 45.2));
- eventParams.set("time", System.currentTimeMillis());
- eventMessage.set("params", eventParams);
-
- System.out.println("事件上报消息:");
- System.out.println(eventMessage.toString());
-
- // 模拟数据上报响应
- JSONObject uploadResponse = new JSONObject();
- uploadResponse.set("code", 0);
- uploadResponse.set("message", "success");
-
- JSONObject responseInfo = new JSONObject();
- responseInfo.set("messageId", 892687470447040L);
- uploadResponse.set("info", responseInfo);
-
- System.out.println("\n数据上报响应:");
- System.out.println(uploadResponse.toString());
- System.out.println();
- }
-
- /**
- * 演示路径构建功能
- */
- private static void demonstratePathBuilding() {
- System.out.println("3. 路径构建功能:");
-
- String productKey = "smartProduct";
- String deviceName = "sensor001";
-
- // 系统主题路径
- System.out.println("系统主题路径:");
- System.out.println(" 属性设置: " + IotHttpTopicUtils.buildPropertySetPath(productKey, deviceName));
- System.out.println(" 属性获取: " + IotHttpTopicUtils.buildPropertyGetPath(productKey, deviceName));
- System.out.println(" 属性上报: " + IotHttpTopicUtils.buildPropertyPostPath(productKey, deviceName));
- System.out.println(" 事件上报: " + IotHttpTopicUtils.buildEventPostPath(productKey, deviceName, "alarm"));
- System.out.println(" 服务调用: " + IotHttpTopicUtils.buildServiceInvokePath(productKey, deviceName, "reboot"));
-
- // 自定义主题路径
- System.out.println("\n自定义主题路径:");
- System.out.println(" 用户主题: " + IotHttpTopicUtils.buildCustomTopicPath(productKey, deviceName, "user/get"));
-
- // 响应路径
- String requestPath = IotHttpTopicUtils.buildPropertySetPath(productKey, deviceName);
- String replyPath = IotHttpTopicUtils.buildReplyPath(requestPath);
- System.out.println("\n响应路径:");
- System.out.println(" 请求路径: " + requestPath);
- System.out.println(" 响应路径: " + replyPath);
-
- // 路径解析
- System.out.println("\n路径解析:");
- String testPath = "/topic/sys/smartProduct/sensor001/thing/service/property/set";
- String actualTopic = IotHttpTopicUtils.extractActualTopic(testPath);
- System.out.println(" HTTP路径: " + testPath);
- System.out.println(" 实际主题: " + actualTopic);
- System.out.println(" 产品Key: " + IotHttpTopicUtils.parseProductKeyFromTopic(actualTopic));
- System.out.println(" 设备名称: " + IotHttpTopicUtils.parseDeviceNameFromTopic(actualTopic));
- System.out.println(" 是否为系统主题: " + IotHttpTopicUtils.isSystemTopic(actualTopic));
-
- // 路径类型检查
- System.out.println("\n路径类型检查:");
- System.out.println(" 认证路径检查: " + IotHttpTopicUtils.isAuthPath("/auth"));
- System.out.println(" 数据路径检查: " + IotHttpTopicUtils.isTopicPath("/topic/test"));
- System.out.println(" 有效路径检查: " + IotHttpTopicUtils.isValidHttpPath("/topic/sys/test/device/property"));
- }
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/message/impl/IotHttpMessageParserTest.java b/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/message/impl/IotHttpMessageParserTest.java
deleted file mode 100644
index 5fb6f5ed3b..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/src/test/java/cn/iocoder/yudao/module/iot/protocol/message/impl/IotHttpMessageParserTest.java
+++ /dev/null
@@ -1,259 +0,0 @@
-package cn.iocoder.yudao.module.iot.protocol.message.impl;
-
-import cn.hutool.json.JSONObject;
-import cn.iocoder.yudao.module.iot.protocol.message.IotMqttMessage;
-import cn.iocoder.yudao.module.iot.protocol.message.IotStandardResponse;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * {@link IotHttpMessageParser} 单元测试
- *
- * 测试阿里云IoT平台HTTPS协议标准的消息解析功能
- *
- * @author haohao
- */
-class IotHttpMessageParserTest {
-
- private IotHttpMessageParser parser;
-
- @BeforeEach
- void setUp() {
- parser = new IotHttpMessageParser();
- }
-
- @Test
- void testCanHandle() {
- // 测试能处理的路径
- assertTrue(parser.canHandle("/auth"));
- assertTrue(parser.canHandle("/topic/sys/test/device1/thing/service/property/set"));
- assertTrue(parser.canHandle("/topic/test/device1/user/get"));
-
- // 测试不能处理的路径
- assertFalse(parser.canHandle("/sys/test/device1/thing/service/property/set"));
- assertFalse(parser.canHandle("/unknown/path"));
- assertFalse(parser.canHandle(null));
- assertFalse(parser.canHandle(""));
- }
-
- @Test
- void testParseAuthMessage() {
- // 构建认证消息
- JSONObject authMessage = new JSONObject();
- authMessage.set("productKey", "a1GFjLP****");
- authMessage.set("deviceName", "device123");
- authMessage.set("clientId", "device123_001");
- authMessage.set("timestamp", "1501668289957");
- authMessage.set("sign", "4870141D4067227128CBB4377906C3731CAC221C");
- authMessage.set("signmethod", "hmacsha1");
- authMessage.set("version", "default");
-
- String topic = "/auth";
- byte[] payload = authMessage.toString().getBytes(StandardCharsets.UTF_8);
-
- // 解析消息
- IotMqttMessage result = parser.parse(topic, payload);
-
- // 验证结果
- assertNotNull(result);
- assertNotNull(result.getId());
- assertEquals("device.auth", result.getMethod());
- assertEquals("default", result.getVersion());
- assertNotNull(result.getParams());
-
- Map
`/mqtt/{productKey}/{deviceName}/...`
`/device/{productKey}/{deviceName}/...` | 实时性要求高的设备(推荐) |
-| HTTP | HTTP | JSON | `/topic/sys/{productKey}/{deviceName}/...`
`/topic/{productKey}/{deviceName}/...` | 间歇性通信的设备 |
-| MQTT_RAW | MQTT | 原始 | 自定义格式 | 特殊协议设备 |
-
-## 模块依赖
-
-本模块是一个基础模块,依赖项最小化:
-
-- `yudao-common`: 基础工具类
-- `hutool-all`: 工具库
-- `lombok`: 简化代码
-- `spring-boot-starter`: Spring Boot 基础支持
-
-## 扩展点
-
-### 1. 自定义消息解析器
-
-实现 `IotMessageParser` 接口,支持新的协议格式。
-
-### 2. 自定义协议转换器
-
-实现 `IotProtocolConverter` 接口,提供更复杂的转换逻辑。
-
-### 3. 自定义主题格式
-
-扩展 `IotTopicParser` 的 `parseCustomTopic` 方法,支持自定义主题格式。
-
-## 注意事项
-
-1. 本模块设计为无状态的工具模块,避免引入有状态的组件
-2. 所有的工具类都采用静态方法,便于直接调用
-3. 异常处理采用返回 null 的方式,调用方需要做好空值检查
-4. 日志级别建议设置为 INFO 或 WARN,避免过多的 DEBUG 日志
-5. HTTP 协议解析器使用设备标识 `deviceKey`(格式:`productKey/deviceName`)来标识设备
-
-## 版本更新
-
-- v1.0.0: 基础功能实现,支持 MQTT 协议和 HTTP 协议支持
-- 后续版本将支持更多协议类型和高级功能
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-protocol/pom.xml b/yudao-module-iot/yudao-module-iot-protocol/pom.xml
deleted file mode 100644
index 0a4e4552dd..0000000000
--- a/yudao-module-iot/yudao-module-iot-protocol/pom.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
- * POST /auth HTTP/1.1
- * Content-Type: application/json
- * {
- * "productKey": "a1AbC***",
- * "deviceName": "device01",
- * "clientId": "device01_001",
- * "timestamp": "1501668289957",
- * "sign": "xxxxx",
- * "signmethod": "hmacsha1",
- * "version": "default"
- * }
- *
- *
- * POST /topic/${topic} HTTP/1.1
- * password: ${token}
- * Content-Type: application/octet-stream
- * ${payload}
- *
- *
- * @author haohao
- */
-@Slf4j
-public class IotHttpMessageParser implements IotMessageParser {
-
- /**
- * 认证路径
- */
- public static final String AUTH_PATH = IotHttpConstants.Path.AUTH;
-
- /**
- * 主题路径前缀
- */
- public static final String TOPIC_PATH_PREFIX = IotHttpConstants.Path.TOPIC_PREFIX;
-
- @Override
- public IotMqttMessage parse(String topic, byte[] payload) {
- if (payload == null || payload.length == 0) {
- log.warn(IotLogConstants.Http.RECEIVED_EMPTY_MESSAGE, topic);
- return null;
- }
-
- try {
- String message = new String(payload, StandardCharsets.UTF_8);
-
- // 判断是认证请求还是数据上报
- if (AUTH_PATH.equals(topic)) {
- return parseAuthMessage(message);
- } else if (topic.startsWith(TOPIC_PATH_PREFIX)) {
- return parseDataMessage(topic, message);
- } else {
- log.warn(IotLogConstants.Http.UNSUPPORTED_PATH_FORMAT, topic);
- return null;
- }
-
- } catch (Exception e) {
- log.error(IotLogConstants.Http.PARSE_MESSAGE_FAILED, topic, e);
- return null;
- }
- }
-
- /**
- * 解析设备认证消息
- *
- * @param message 认证消息JSON
- * @return 标准消息格式
- */
- private IotMqttMessage parseAuthMessage(String message) {
- if (!JSONUtil.isTypeJSON(message)) {
- log.warn(IotLogConstants.Http.AUTH_MESSAGE_NOT_JSON, message);
- return null;
- }
-
- JSONObject json = JSONUtil.parseObj(message);
-
- // 验证必需字段
- String productKey = json.getStr(IotHttpConstants.AuthField.PRODUCT_KEY);
- String deviceName = json.getStr(IotHttpConstants.AuthField.DEVICE_NAME);
- String clientId = json.getStr(IotHttpConstants.AuthField.CLIENT_ID);
- String sign = json.getStr(IotHttpConstants.AuthField.SIGN);
-
- if (StrUtil.hasBlank(productKey, deviceName, clientId, sign)) {
- log.warn(IotLogConstants.Http.AUTH_MESSAGE_MISSING_REQUIRED_FIELDS, message);
- return null;
- }
-
- // 构建认证消息
- Map