From c3485a3f3daa2dbcdb03c6c0484afefb8ae655ee Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 1 Jun 2025 07:48:30 +0800 Subject: [PATCH] reactor:【IoT 物联网】将 http component 合并到 gateway 里 --- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java | 1 + yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java | 4 +++- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageBusSubscriber.java | 49 ------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageSubscriber.java | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java | 6 +----- yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBus.java | 2 +- yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBusSubscriber.java | 29 ----------------------------- yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageSubscriber.java | 29 +++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBus.java | 12 ++++++------ yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBus.java | 4 ++-- yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java | 4 ++-- yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotCoreUtils.java | 29 +++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBusIntegrationTest.java | 10 +++++----- yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBusTest.java | 12 ++++++------ yudao-module-iot/yudao-module-iot-gateway/pom.xml | 42 ++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/IotGatewayServerApplication.java | 13 +++++++++++++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/package-info.java | 3 +++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java | 39 +++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/enums/IotDeviceTopicEnum.java | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/package-info.java | 1 - yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpDownstreamSubscriber.java | 44 ++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/package-info.java | 1 - yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/package-info.java | 2 +- yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-net-components/README.md | 137 ----------------------------------------------------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-net-components/pom.xml | 3 +-- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonAutoConfiguration.java | 2 -- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonProperties.java | 24 ------------------------ yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/constants/IotDeviceTopicEnum.java | 179 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/pojo/IotStandardResponse.java | 2 -- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/util/IotNetComponentCommonUtils.java | 38 +------------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/pom.xml | 47 ----------------------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpAutoConfiguration.java | 90 ------------------------------------------------------------------------------------------ yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpProperties.java | 33 --------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/downstream/IotDeviceDownstreamHandlerImpl.java | 44 -------------------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/IotDeviceUpstreamServer.java | 73 ------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/auth/IotDeviceAuthProvider.java | 50 -------------------------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/router/IotDeviceUpstreamVertxHandler.java | 330 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 1 - yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/application.yml | 10 ---------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/pom.xml | 46 +--------------------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/NetComponentServerApplication.java | 18 ------------------ yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerConfiguration.java | 25 ------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerProperties.java | 16 ---------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/controller/HealthController.java | 33 --------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/upstream/IotComponentUpstreamClient.java | 50 ++++++-------------------------------------------- yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/resources/application.yml | 70 ---------------------------------------------------------------------- 50 files changed, 1023 insertions(+), 1421 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageBusSubscriber.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageSubscriber.java delete mode 100644 yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBusSubscriber.java create mode 100644 yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageSubscriber.java create mode 100644 yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotCoreUtils.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/IotGatewayServerApplication.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/enums/IotDeviceTopicEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpDownstreamSubscriber.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java delete mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/README.md delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonProperties.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/constants/IotDeviceTopicEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpAutoConfiguration.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpProperties.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/downstream/IotDeviceDownstreamHandlerImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/IotDeviceUpstreamServer.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/auth/IotDeviceAuthProvider.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/router/IotDeviceUpstreamVertxHandler.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/application.yml delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/NetComponentServerApplication.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/controller/HealthController.java delete mode 100644 yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/resources/application.yml diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index 9633d2f..714775c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -33,6 +33,7 @@ public class IotDeviceDO extends TenantBaseDO { */ @TableId private Long id; + // TODO @芋艿:看看怎么弱化 deviceKey /** * 设备唯一标识符,全局唯一,用于识别设备 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index 0c26751..d31096b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; */ public interface RedisKeyConstants { + // TODO @芋艿:弱化 deviceKey;使用 product_key + device_name 替代 /** * 设备属性的数据缓存,采用 HASH 结构 *

@@ -18,6 +19,7 @@ public interface RedisKeyConstants { */ String DEVICE_PROPERTY = "iot:device_property:%s"; + // TODO @芋艿:弱化 deviceKey;使用 product_key + device_name 替代 /** * 设备的最后上报时间,采用 ZSET 结构 * @@ -29,7 +31,7 @@ public interface RedisKeyConstants { /** * 设备信息的数据缓存,使用 Spring Cache 操作(忽略租户) * - * KEY 格式:device_${productKey}_${deviceKey} + * KEY 格式:device_${productKey}_${deviceName} * VALUE 数据类型:String(JSON) */ String DEVICE = "iot:device"; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageBusSubscriber.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageBusSubscriber.java deleted file mode 100644 index 4b42781..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageBusSubscriber.java +++ /dev/null @@ -1,49 +0,0 @@ -package cn.iocoder.yudao.module.iot.mq.consumer.device; - -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -/** - * 针对 {@link IotDeviceMessage} 的消费者,记录设备日志 - * - * @author 芋道源码 - */ -@Component -@Slf4j -public class IotDeviceLogMessageBusSubscriber implements IotMessageBusSubscriber { - - @Resource - private IotMessageBus messageBus; - - @Resource - private IotDeviceLogService deviceLogService; - - @PostConstruct - public void init() { - messageBus.register(this); - } - - @Override - public String getTopic() { - return IotDeviceMessage.MESSAGE_BUS_DEVICE_MESSAGE_TOPIC; - } - - @Override - public String getGroup() { - return "iot_device_log_consumer"; - } - - // TODO @芋艿:后续再对接这个细节逻辑; - @Override - public void onMessage(IotDeviceMessage message) { - log.info("[onMessage][消息内容({})]", message); -// deviceLogService.createDeviceLog(message); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageSubscriber.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageSubscriber.java new file mode 100644 index 0000000..279e422 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageSubscriber.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.device; + +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 针对 {@link IotDeviceMessage} 的消费者,记录设备日志 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class IotDeviceLogMessageSubscriber implements IotMessageSubscriber { + + @Resource + private IotMessageBus messageBus; + + @Resource + private IotDeviceLogService deviceLogService; + + @PostConstruct + public void init() { + messageBus.register(this); + } + + @Override + public String getTopic() { + return IotDeviceMessage.MESSAGE_BUS_DEVICE_MESSAGE_TOPIC; + } + + @Override + public String getGroup() { + return "iot_device_log_consumer"; + } + + // TODO @芋艿:后续再对接这个细节逻辑; + @Override + public void onMessage(IotDeviceMessage message) { + log.info("[onMessage][消息内容({})]", message); +// deviceLogService.createDeviceLog(message); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java index d568d7a..511585a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java @@ -20,7 +20,6 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import org.springframework.web.client.RestTemplate; import java.time.LocalDateTime; import java.util.List; @@ -45,9 +44,6 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic private IotDeviceService deviceService; @Resource - private RestTemplate restTemplate; - - @Resource private IotDeviceProducer deviceProducer; @Resource private IotDeviceMessageProducer deviceMessageProducer; @@ -156,7 +152,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage message = cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage .of(getProductKey(device, parentDevice), getDeviceName(device, parentDevice), deviceName, null, tenantId); - String serverId = "yy"; + String serverId = "192_168_64_1_8092"; deviceMessageProducer.sendGatewayDeviceMessage(serverId, message); // TODO @芋艿:后续可以清理掉 return null; diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBus.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBus.java index b032298..c621467 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBus.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBus.java @@ -22,6 +22,6 @@ public interface IotMessageBus { * * @param subscriber 订阅者 */ - void register(IotMessageBusSubscriber subscriber); + void register(IotMessageSubscriber subscriber); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBusSubscriber.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBusSubscriber.java deleted file mode 100644 index 631fa88..0000000 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBusSubscriber.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.iot.core.messagebus.core; - -/** - * IoT 消息总线订阅者接口 - * - * 用于处理从消息总线接收到的消息 - * - * @author 芋道源码 - */ -public interface IotMessageBusSubscriber { - - /** - * @return 主题 - */ - String getTopic(); - - /** - * @return 分组 - */ - String getGroup(); - - /** - * 处理接收到的消息 - * - * @param message 消息内容 - */ - void onMessage(T message); - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageSubscriber.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageSubscriber.java new file mode 100644 index 0000000..23a0553 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageSubscriber.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.core.messagebus.core; + +/** + * IoT 消息总线订阅者接口 + * + * 用于处理从消息总线接收到的消息 + * + * @author 芋道源码 + */ +public interface IotMessageSubscriber { + + /** + * @return 主题 + */ + String getTopic(); + + /** + * @return 分组 + */ + String getGroup(); + + /** + * 处理接收到的消息 + * + * @param message 消息内容 + */ + void onMessage(T message); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBus.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBus.java index af73547..76bd6a4 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBus.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBus.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core.local; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; @@ -30,7 +30,7 @@ public class LocalIotMessageBus implements IotMessageBus { * 订阅者映射表 * Key: topic */ - private final Map>> subscribers = new HashMap<>(); + private final Map>> subscribers = new HashMap<>(); @Override public void post(String topic, Object message) { @@ -38,9 +38,9 @@ public class LocalIotMessageBus implements IotMessageBus { } @Override - public void register(IotMessageBusSubscriber subscriber) { + public void register(IotMessageSubscriber subscriber) { String topic = subscriber.getTopic(); - List> topicSubscribers = subscribers.computeIfAbsent(topic, k -> new ArrayList<>()); + List> topicSubscribers = subscribers.computeIfAbsent(topic, k -> new ArrayList<>()); topicSubscribers.add(subscriber); log.info("[register][topic({}/{}) 注册消费者({})成功]", topic, subscriber.getGroup(), subscriber.getClass().getName()); @@ -50,11 +50,11 @@ public class LocalIotMessageBus implements IotMessageBus { @SuppressWarnings({"unchecked", "rawtypes"}) public void onMessage(LocalIotMessage message) { String topic = message.getTopic(); - List> topicSubscribers = subscribers.get(topic); + List> topicSubscribers = subscribers.get(topic); if (CollUtil.isEmpty(topicSubscribers)) { return; } - for (IotMessageBusSubscriber subscriber : topicSubscribers) { + for (IotMessageSubscriber subscriber : topicSubscribers) { try { subscriber.onMessage(message.getMessage()); } catch (Exception ex) { diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBus.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBus.java index a304ef4..68d2ce9 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBus.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBus.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq; import cn.hutool.core.util.TypeUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -47,7 +47,7 @@ public class RocketMQIotMessageBus implements IotMessageBus { @Override @SneakyThrows - public void register(IotMessageBusSubscriber subscriber) { + public void register(IotMessageSubscriber subscriber) { Type type = TypeUtil.getTypeArgument(subscriber.getClass(), 0); if (type == null) { throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName())); diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java index da829b1..3d9cc2d 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.core.mq.message; -import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageIdentifierEnum; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageTypeEnum; +import cn.iocoder.yudao.module.iot.core.util.IotCoreUtils; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -119,7 +119,7 @@ public class IotDeviceMessage { String requestId, LocalDateTime reportTime, String serverId, Long tenantId) { if (requestId == null) { - requestId = IdUtil.fastSimpleUUID(); + requestId = IotCoreUtils.generateRequestId(); } if (reportTime == null) { reportTime = LocalDateTime.now(); diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotCoreUtils.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotCoreUtils.java new file mode 100644 index 0000000..10d9769 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotCoreUtils.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.core.util; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.system.SystemUtil; + +/** + * IoT 核心模块的工具类 + * + * @author 芋道源码 + */ +public class IotCoreUtils { + + /** + * 生成服务器编号 + * + * @param serverPort 服务器端口 + * @return 服务器编号 + */ + public static String generateServerId(Integer serverPort) { + String serverId = String.format("%s.%d", SystemUtil.getHostInfo().getAddress(), serverPort); + // 避免一些场景无法使用 . 符号,例如说 RocketMQ Topic + return serverId.replaceAll("\\.", "_"); + } + + public static String generateRequestId() { + return IdUtil.fastSimpleUUID(); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBusIntegrationTest.java b/yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBusIntegrationTest.java index de757dd..341ad89 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBusIntegrationTest.java +++ b/yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBusIntegrationTest.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core.local; import cn.iocoder.yudao.module.iot.core.messagebus.config.IotMessageBusAutoConfiguration; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -47,7 +47,7 @@ public class LocalIotMessageBusIntegrationTest { AtomicInteger subscriber2Count = new AtomicInteger(0); // 创建第一个订阅者 - IotMessageBusSubscriber subscriber1 = new IotMessageBusSubscriber<>() { + IotMessageSubscriber subscriber1 = new IotMessageSubscriber<>() { @Override public String getTopic() { @@ -69,7 +69,7 @@ public class LocalIotMessageBusIntegrationTest { }; // 创建第二个订阅者 - IotMessageBusSubscriber subscriber2 = new IotMessageBusSubscriber<>() { + IotMessageSubscriber subscriber2 = new IotMessageSubscriber<>() { @Override public String getTopic() { @@ -120,7 +120,7 @@ public class LocalIotMessageBusIntegrationTest { CountDownLatch latch = new CountDownLatch(2); // 创建订阅者 1 - 只订阅设备状态 - IotMessageBusSubscriber statusSubscriber = new IotMessageBusSubscriber<>() { + IotMessageSubscriber statusSubscriber = new IotMessageSubscriber<>() { @Override public String getTopic() { @@ -141,7 +141,7 @@ public class LocalIotMessageBusIntegrationTest { }; // 创建订阅者 2 - 只订阅设备数据 - IotMessageBusSubscriber dataSubscriber = new IotMessageBusSubscriber<>() { + IotMessageSubscriber dataSubscriber = new IotMessageSubscriber<>() { @Override public String getTopic() { diff --git a/yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBusTest.java b/yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBusTest.java index babd3b2..01b97ce 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBusTest.java +++ b/yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBusTest.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq; import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.module.iot.core.messagebus.config.IotMessageBusAutoConfiguration; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; import cn.iocoder.yudao.module.iot.core.messagebus.core.TestMessage; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -59,7 +59,7 @@ public class RocketMQIotMessageBusTest { messageBus.post(topic, testMessage); // 创建订阅者 - IotMessageBusSubscriber subscriber1 = new IotMessageBusSubscriber<>() { + IotMessageSubscriber subscriber1 = new IotMessageSubscriber<>() { @Override public String getTopic() { @@ -117,7 +117,7 @@ public class RocketMQIotMessageBusTest { messageBus.post(topic, testMessage); // 创建第一个订阅者 - IotMessageBusSubscriber subscriber1 = new IotMessageBusSubscriber<>() { + IotMessageSubscriber subscriber1 = new IotMessageSubscriber<>() { @Override public String getTopic() { @@ -141,7 +141,7 @@ public class RocketMQIotMessageBusTest { }; // 创建第二个订阅者 - IotMessageBusSubscriber subscriber2 = new IotMessageBusSubscriber<>() { + IotMessageSubscriber subscriber2 = new IotMessageSubscriber<>() { @Override public String getTopic() { @@ -204,7 +204,7 @@ public class RocketMQIotMessageBusTest { messageBus.post(topic2, message2); // 创建订阅者 1 - 只订阅设备状态 - IotMessageBusSubscriber statusSubscriber = new IotMessageBusSubscriber<>() { + IotMessageSubscriber statusSubscriber = new IotMessageSubscriber<>() { @Override public String getTopic() { @@ -227,7 +227,7 @@ public class RocketMQIotMessageBusTest { }; // 创建订阅者 2 - 只订阅设备数据 - IotMessageBusSubscriber dataSubscriber = new IotMessageBusSubscriber<>() { + IotMessageSubscriber dataSubscriber = new IotMessageSubscriber<>() { @Override public String getTopic() { diff --git a/yudao-module-iot/yudao-module-iot-gateway/pom.xml b/yudao-module-iot/yudao-module-iot-gateway/pom.xml index 1355f51..83eae1f 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/pom.xml +++ b/yudao-module-iot/yudao-module-iot-gateway/pom.xml @@ -16,4 +16,46 @@ ② 功能二:接收来自消息网关的消息(由 iot-biz 发送),并进行编码(encode)后,发送给设备 + + + cn.iocoder.boot + yudao-module-iot-core + ${revision} + + + + + org.apache.rocketmq + rocketmq-spring-boot-starter + + + + + + + io.vertx + vertx-web + + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/IotGatewayServerApplication.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/IotGatewayServerApplication.java new file mode 100644 index 0000000..e9c4578 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/IotGatewayServerApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class IotGatewayServerApplication { + + public static void main(String[] args) { + SpringApplication.run(IotGatewayServerApplication.class, args); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/package-info.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/package-info.java index b922a07..e1dae77 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/package-info.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/package-info.java @@ -1 +1,4 @@ +/** + * 提供设备接入的各种数据(请求、响应)的编解码 + */ package cn.iocoder.yudao.module.iot.gateway.codec; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java new file mode 100644 index 0000000..cd0e6ac --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.iot.gateway.config; + +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; +import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; +import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpDownstreamSubscriber; +import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableConfigurationProperties(IotGatewayProperties.class) +@Slf4j +public class IotGatewayConfiguration { + + /** + * IoT 网关 HTTP 协议配置类 + */ + @Configuration + @ConditionalOnProperty(prefix = "yudao.iot.gateway.protocol.http", name = "enabled", havingValue = "true") + @Slf4j + public static class HttpProtocolConfiguration { + + @Bean + public IotHttpUpstreamProtocol iotHttpUpstreamProtocol(IotGatewayProperties gatewayProperties, + IotDeviceMessageProducer deviceMessageProducer) { + return new IotHttpUpstreamProtocol(gatewayProperties.getProtocol().getHttp(), deviceMessageProducer); + } + + @Bean + public IotHttpDownstreamSubscriber iotHttpDownstreamSubscriber(IotHttpUpstreamProtocol httpUpstreamProtocol, + IotMessageBus messageBus) { + return new IotHttpDownstreamSubscriber(httpUpstreamProtocol,messageBus); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java new file mode 100644 index 0000000..9e83a36 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.iot.gateway.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +@ConfigurationProperties(prefix = "yudao.iot.gateway") +@Validated +@Data +public class IotGatewayProperties { + + /** + * 设备 RPC 服务配置 + */ + private RpcProperties rpc; + + /** + * 协议配置 + */ + private ProtocolProperties protocol; + + @Data + public static class RpcProperties { + + /** + * 主程序 API 地址 + */ + private String url; + /** + * 连接超时时间 + */ + private String connectTimeout; + /** + * 读取超时时间 + */ + private String readTimeout; + + } + + @Data + public static class ProtocolProperties { + + /** + * HTTP 组件配置 + */ + private HttpProperties http; + + /** + * EMQX 组件配置 + */ + private EmqxProperties emqx; + + } + + @Data + public static class HttpProperties { + + /** + * 是否开启 + */ + private Boolean enabled; + /** + * 服务端口 + */ + private Integer serverPort; + + } + + @Data + public static class EmqxProperties { + + /** + * 是否开启 + */ + private Boolean enabled; + /** + * MQTT 服务器地址 + */ + private String mqttHost; + /** + * MQTT 服务器端口 + */ + private Integer mqttPort; + /** + * MQTT 用户名 + */ + private String mqttUsername; + /** + * MQTT 密码 + */ + private String mqttPassword; + /** + * MQTT 是否开启 SSL + */ + private Boolean mqttSsl; + /** + * MQTT 主题 + */ + private List mqttTopics; + /** + * 认证端口 + */ + private Integer authPort; + + } + +} diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/enums/IotDeviceTopicEnum.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/enums/IotDeviceTopicEnum.java new file mode 100644 index 0000000..543b307 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/enums/IotDeviceTopicEnum.java @@ -0,0 +1,174 @@ +package cn.iocoder.yudao.module.iot.gateway.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * IoT 设备主题枚举 + *

+ * 用于统一管理 MQTT 协议中的主题常量,基于 Alink 协议规范 + * + * @author haohao + */ +@RequiredArgsConstructor +@Getter +public enum IotDeviceTopicEnum { + + // TODO @haohao:SYS_TOPIC_PREFIX、SERVICE_TOPIC_PREFIX、REPLY_SUFFIX 类似这种,要不搞成这个里面的静态变量?不是枚举值 + /** + * 系统主题前缀 + */ + SYS_TOPIC_PREFIX("/sys/", "系统主题前缀"), + + /** + * 服务调用主题前缀 + */ + SERVICE_TOPIC_PREFIX("/thing/service/", "服务调用主题前缀"), + + // TODO @haohao:注释时,中英文之间,有个空格; + /** + * 设备属性设置主题 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/service/property/set + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply + */ + PROPERTY_SET_TOPIC("/thing/service/property/set", "设备属性设置主题"), + + /** + * 设备属性获取主题 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/service/property/get + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/service/property/get_reply + */ + PROPERTY_GET_TOPIC("/thing/service/property/get", "设备属性获取主题"), + + /** + * 设备配置设置主题 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/service/config/set + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/service/config/set_reply + */ + 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 + */ + OTA_UPGRADE_TOPIC("/thing/service/ota/upgrade", "设备OTA升级主题"), + + /** + * 设备属性上报主题 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply + */ + PROPERTY_POST_TOPIC("/thing/event/property/post", "设备属性上报主题"), + + /** + * 设备事件上报主题前缀 + */ + EVENT_POST_TOPIC_PREFIX("/thing/event/", "设备事件上报主题前缀"), + + /** + * 设备事件上报主题后缀 + */ + EVENT_POST_TOPIC_SUFFIX("/post", "设备事件上报主题后缀"), + + /** + * 响应主题后缀 + */ + REPLY_SUFFIX("_reply", "响应主题后缀"); + + private final String topic; + private final String description; + + /** + * 构建设备服务调用主题 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @param serviceIdentifier 服务标识符 + * @return 完整的主题路径 + */ + public static String buildServiceTopic(String productKey, String deviceName, String serviceIdentifier) { + // TODO @haohao:貌似 SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName 是统一的; + return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + + SERVICE_TOPIC_PREFIX.getTopic() + serviceIdentifier; + } + + /** + * 构建设备属性设置主题 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildPropertySetTopic(String productKey, String deviceName) { + return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + PROPERTY_SET_TOPIC.getTopic(); + } + + /** + * 构建设备属性获取主题 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildPropertyGetTopic(String productKey, String deviceName) { + return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + PROPERTY_GET_TOPIC.getTopic(); + } + + /** + * 构建设备配置设置主题 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildConfigSetTopic(String productKey, String deviceName) { + return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + CONFIG_SET_TOPIC.getTopic(); + } + + /** + * 构建设备 OTA 升级主题 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildOtaUpgradeTopic(String productKey, String deviceName) { + return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + OTA_UPGRADE_TOPIC.getTopic(); + } + + /** + * 构建设备属性上报主题 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildPropertyPostTopic(String productKey, String deviceName) { + return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + PROPERTY_POST_TOPIC.getTopic(); + } + + /** + * 构建设备事件上报主题 + * + * @param productKey 产品Key + * @param deviceName 设备名称 + * @param eventIdentifier 事件标识符 + * @return 完整的主题路径 + */ + public static String buildEventPostTopic(String productKey, String deviceName, String eventIdentifier) { + return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + + EVENT_POST_TOPIC_PREFIX.getTopic() + eventIdentifier + EVENT_POST_TOPIC_SUFFIX.getTopic(); + } + + /** + * 获取响应主题 + * + * @param requestTopic 请求主题 + * @return 响应主题 + */ + public static String getReplyTopic(String requestTopic) { + return requestTopic + REPLY_SUFFIX.getTopic(); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/package-info.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/package-info.java deleted file mode 100644 index 7de19cf..0000000 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.iot.gateway; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpDownstreamSubscriber.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpDownstreamSubscriber.java new file mode 100644 index 0000000..046095e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpDownstreamSubscriber.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.iot.gateway.protocol.http; + +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * IoT 网关 HTTP 订阅者:接收下行给设备的消息 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Slf4j +public class IotHttpDownstreamSubscriber implements IotMessageSubscriber { + + private final IotHttpUpstreamProtocol protocol; + + private final IotMessageBus messageBus; + + @PostConstruct + public void init() { + messageBus.register(this); + } + + @Override + public String getTopic() { + return IotDeviceMessage.buildMessageBusGatewayDeviceMessageTopic(protocol.getServerId()); + } + + @Override + public String getGroup() { + // 保证点对点消费,需要保证独立的 Group,所以使用 Topic 作为 Group + return getTopic(); + } + + @Override + public void onMessage(IotDeviceMessage message) { + log.error("[onMessage][IoT 网关 HTTP 协议不支持下行消息,忽略消息:{}]", message); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java new file mode 100644 index 0000000..4ddc79f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.iot.gateway.protocol.http; + +import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; +import cn.iocoder.yudao.module.iot.core.util.IotCoreUtils; +import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties; +import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpUpstreamHandler; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServer; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.BodyHandler; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * IoT 网关 HTTP 协议:接收设备上行消息 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Slf4j +public class IotHttpUpstreamProtocol extends AbstractVerticle { + + private final IotGatewayProperties.HttpProperties httpProperties; + + private final IotDeviceMessageProducer deviceMessageProducer; + + private HttpServer httpServer; + + @Override + @PostConstruct + public void start() { + // 创建路由 + Vertx vertx = Vertx.vertx(); + Router router = Router.router(vertx); + router.route().handler(BodyHandler.create()); + + // 创建处理器,添加路由处理器 + IotHttpUpstreamHandler upstreamHandler = new IotHttpUpstreamHandler( + this, deviceMessageProducer); + router.post(IotHttpUpstreamHandler.PROPERTY_PATH).handler(upstreamHandler); + router.post(IotHttpUpstreamHandler.EVENT_PATH).handler(upstreamHandler); + + // 启动 HTTP 服务器 + try { + httpServer = vertx.createHttpServer() + .requestHandler(router) + .listen(httpProperties.getServerPort()) + .result(); + log.info("[start][IoT 网关 HTTP 协议启动成功,端口:{}]", httpProperties.getServerPort()); + } catch (Exception e) { + log.error("[start][IoT 网关 HTTP 协议启动失败]", e); + throw e; + } + } + + @Override + @PreDestroy + public void stop() { + if (httpServer != null) { + try { + httpServer.close().result(); + log.info("[stop][IoT 网关 HTTP 协议已停止]"); + } catch (Exception e) { + log.error("[stop][IoT 网关 HTTP 协议停止失败]", e); + } + } + } + + public String getServerId() { + return IotCoreUtils.generateServerId(httpProperties.getServerPort()); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/package-info.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/package-info.java deleted file mode 100644 index ed889b8..0000000 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.iot.gateway.protocol.http; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java new file mode 100644 index 0000000..2c626d6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java @@ -0,0 +1,322 @@ +package cn.iocoder.yudao.module.iot.gateway.protocol.http.router; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; +import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum; +import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; + +/** + * IoT 网关 HTTP 协议的处理器 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Slf4j +public class IotHttpUpstreamHandler implements Handler { + + // TODO @haohao:你说,咱要不要把 "/sys/:productKey/:deviceName" + // + IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic(),也抽到 IotDeviceTopicEnum 的 build 这种?尽量都收敛掉? + /** + * 属性上报路径 + */ + public static final String PROPERTY_PATH = "/sys/:productKey/:deviceName" + + IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic(); + + /** + * 事件上报路径 + */ + public static final String EVENT_PATH = "/sys/:productKey/:deviceName" + + IotDeviceTopicEnum.EVENT_POST_TOPIC_PREFIX.getTopic() + ":identifier" + + IotDeviceTopicEnum.EVENT_POST_TOPIC_SUFFIX.getTopic(); + + /** + * 事件上报方法前缀 + */ + private static final String EVENT_METHOD_PREFIX = "thing.event."; + + /** + * 事件上报方法后缀 + */ + private static final String EVENT_METHOD_SUFFIX = ".post"; + + private final IotHttpUpstreamProtocol protocol; +// /** +// * 设备上行 API +// */ +// private final IotDeviceUpstreamApi deviceUpstreamApi; + /** + * 设备消息生产者 + */ + private final IotDeviceMessageProducer deviceMessageProducer; + + @Override + public void handle(RoutingContext routingContext) { + String path = routingContext.request().path(); + String requestId = IdUtil.fastSimpleUUID(); + + try { + // 1. 解析通用参数 + Map params = parseCommonParams(routingContext, requestId); + String productKey = params.get("productKey"); + String deviceName = params.get("deviceName"); + JsonObject body = routingContext.body().asJsonObject(); + requestId = params.get("requestId"); + + // 2. 根据路径模式处理不同类型的请求 + if (isPropertyPostPath(path)) { + // 处理属性上报 + handlePropertyPost(routingContext, productKey, deviceName, requestId, body); + return; + } + + if (isEventPostPath(path)) { + // 处理事件上报 + String identifier = routingContext.pathParam("identifier"); + handleEventPost(routingContext, productKey, deviceName, identifier, requestId, body); + return; + } + + // 不支持的请求路径 + sendErrorResponse(routingContext, requestId, "unknown", BAD_REQUEST.getCode(), "不支持的请求路径"); + } catch (Exception e) { + log.error("[handle][处理上行请求异常] path={}", path, e); + String method = determineMethodFromPath(path, routingContext); + sendErrorResponse(routingContext, requestId, method, INTERNAL_SERVER_ERROR.getCode(), + INTERNAL_SERVER_ERROR.getMsg()); + } + } + + /** + * 解析通用参数 + * + * @param routingContext 路由上下文 + * @param defaultRequestId 默认请求 ID + * @return 参数映射 + */ + private Map parseCommonParams(RoutingContext routingContext, String defaultRequestId) { + Map params = MapUtil.newHashMap(); + params.put("productKey", routingContext.pathParam("productKey")); + params.put("deviceName", routingContext.pathParam("deviceName")); + + JsonObject body = routingContext.body().asJsonObject(); + String requestId = ObjUtil.defaultIfNull(body.getString("id"), defaultRequestId); + params.put("requestId", requestId); + + return params; + } + + /** + * 判断是否是属性上报路径 + * + * @param path 路径 + * @return 是否是属性上报路径 + */ + private boolean isPropertyPostPath(String path) { + return StrUtil.endWith(path, IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic()); + } + + /** + * 判断是否是事件上报路径 + * + * @param path 路径 + * @return 是否是事件上报路径 + */ + private boolean isEventPostPath(String path) { + return StrUtil.contains(path, IotDeviceTopicEnum.EVENT_POST_TOPIC_PREFIX.getTopic()) + && StrUtil.endWith(path, IotDeviceTopicEnum.EVENT_POST_TOPIC_SUFFIX.getTopic()); + } + + /** + * 处理属性上报请求 + * + * @param routingContext 路由上下文 + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @param requestId 请求 ID + * @param body 请求体 + */ + private void handlePropertyPost(RoutingContext routingContext, String productKey, String deviceName, + String requestId, JsonObject body) { + // 1.1 构建设备消息 + String deviceKey = "xxx"; // TODO @芋艿:待支持 + Long tenantId = 1L; // TODO @芋艿:待支持 + IotDeviceMessage message = IotDeviceMessage.of(productKey, deviceName, deviceKey, + requestId, LocalDateTime.now(), + protocol.getServerId(), tenantId) + .ofPropertyReport(parsePropertiesFromBody(body)); + // 1.2 发送消息 + deviceMessageProducer.sendDeviceMessage(message); + + // 2. 返回响应 + sendResponse(routingContext, requestId, null, null); + } + + /** + * 处理事件上报请求 + * + * @param routingContext 路由上下文 + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @param identifier 事件标识符 + * @param requestId 请求 ID + * @param body 请求体 + */ + private void handleEventPost(RoutingContext routingContext, String productKey, String deviceName, + String identifier, String requestId, JsonObject body) { +// // 处理事件上报 +// IotDeviceEventReportReqDTO reportReqDTO = parseEventReportRequest(productKey, deviceName, identifier, +// requestId, body); +// +// // 事件上报 +// CommonResult result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO); +// String method = EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX; +// +// // 返回响应 +// sendResponse(routingContext, requestId, method, result); + } + + /** + * 发送响应 + * + * @param routingContext 路由上下文 + * @param requestId 请求 ID + * @param method 方法名 + * @param result 结果 + */ + private void sendResponse(RoutingContext routingContext, String requestId, String method, + CommonResult result) { +// // TODO @芋艿:后续再优化 +// IotStandardResponse response; +// if (result == null ) { +// response = IotStandardResponse.success(requestId, method, null); +// } else if (result.isSuccess()) { +// response = IotStandardResponse.success(requestId, method, result.getData()); +// } else { +// response = IotStandardResponse.error(requestId, method, result.getCode(), result.getMsg()); +// } +// IotNetComponentCommonUtils.writeJsonResponse(routingContext, response); + } + + /** + * 发送错误响应 + * + * @param routingContext 路由上下文 + * @param requestId 请求 ID + * @param method 方法名 + * @param code 错误代码 + * @param message 错误消息 + */ + private void sendErrorResponse(RoutingContext routingContext, String requestId, String method, Integer code, + String message) { +// IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, code, message); +// IotNetComponentCommonUtils.writeJsonResponse(routingContext, errorResponse); + } + + /** + * 从路径确定方法名 + * + * @param path 路径 + * @param routingContext 路由上下文 + * @return 方法名 + */ + private String determineMethodFromPath(String path, RoutingContext routingContext) { + if (StrUtil.contains(path, "/property/")) { + return null; + } + + return EVENT_METHOD_PREFIX + + (routingContext.pathParams().containsKey("identifier") + ? routingContext.pathParam("identifier") + : "unknown") + + + EVENT_METHOD_SUFFIX; + } + + // TODO @芋艿:这块在看看 + /** + * 从请求体解析属性 + * + * @param body 请求体 + * @return 属性映射 + */ + private Map parsePropertiesFromBody(JsonObject body) { + Map properties = MapUtil.newHashMap(); + JsonObject params = body.getJsonObject("params"); + if (CollUtil.isEmpty(params)) { + return properties; + } + + // 将标准格式的 params 转换为平台需要的 properties 格式 + for (String key : params.fieldNames()) { + Object valueObj = params.getValue(key); + // 如果是复杂结构(包含 value 和 time) + if (valueObj instanceof JsonObject) { + JsonObject valueJson = (JsonObject) valueObj; + properties.put(key, valueJson.containsKey("value") ? valueJson.getValue("value") : valueObj); + } else { + properties.put(key, valueObj); + } + } + return properties; + } + +// /** +// * 解析事件上报请求 +// * +// * @param productKey 产品 Key +// * @param deviceName 设备名称 +// * @param identifier 事件标识符 +// * @param requestId 请求 ID +// * @param body 请求体 +// * @return 事件上报请求 DTO +// */ +// private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, +// String requestId, JsonObject body) { +// // 解析参数 +// Map params = parseParamsFromBody(body); +// +// // 构建事件上报请求 DTO +// return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO() +// .setRequestId(requestId) +// .setProcessId(IotNetComponentCommonUtils.getProcessId()) +// .setReportTime(LocalDateTime.now()) +// .setProductKey(productKey) +// .setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); +// } + + /** + * 从请求体解析参数 + * + * @param body 请求体 + * @return 参数映射 + */ + private Map parseParamsFromBody(JsonObject body) { + Map params = MapUtil.newHashMap(); + JsonObject paramsJson = body.getJsonObject("params"); + if (CollUtil.isEmpty(paramsJson)) { + return params; + } + + for (String key : paramsJson.fieldNames()) { + params.put(key, paramsJson.getValue(key)); + } + return params; + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/package-info.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/package-info.java index 4920c11..6eb414e 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/package-info.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/package-info.java @@ -1,4 +1,4 @@ /** - * TODO 占位 + * 提供设备接入的各种协议的实现 */ package cn.iocoder.yudao.module.iot.gateway.protocol; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml b/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml new file mode 100644 index 0000000..9cc4387 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml @@ -0,0 +1,57 @@ +spring: + application: + name: iot-gateway-server + +--- #################### 消息队列相关 #################### + +# rocketmq 配置项,对应 RocketMQProperties 配置类 +rocketmq: + name-server: 127.0.0.1:9876 # RocketMQ Namesrv + # Producer 配置项 + producer: + group: ${spring.application.name}_PRODUCER # 生产者分组 + +--- #################### 芋道相关配置 #################### + +yudao: + iot: + # 网关配置 + gateway: + # 设备 RPC 配置 + rpc: + url: http://127.0.0.1:48080 # 主程序 API 地址 + connect-timeout: 30s + read-timeout: 30s + + # 协议配置 + protocol: + # ==================================== + # 针对引入的 HTTP 组件的配置 + # ==================================== + http: + enabled: true + server-port: 8092 + # ==================================== + # 针对引入的 EMQX 组件的配置 + # ==================================== + emqx: + enabled: true + mqtt-host: 127.0.0.1 + mqtt-port: 1883 + mqtt-username: admin + mqtt-password: admin123 + mqtt-ssl: false + mqtt-topics: + - "/sys/#" + auth-port: 8101 + + # 消息总线配置 + message-bus: + type: rocketmq # 消息总线的类型 + +# 日志配置 +# TODO 芋艿:是不是可以删除 +logging: + level: + cn.iocoder.yudao: INFO + root: INFO diff --git a/yudao-module-iot/yudao-module-iot-net-components/README.md b/yudao-module-iot/yudao-module-iot-net-components/README.md deleted file mode 100644 index d60c0dd..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/README.md +++ /dev/null @@ -1,137 +0,0 @@ -# IOT 组件使用说明 - -## 组件介绍 - -该模块包含多个 IoT 设备连接组件,提供不同的通信协议支持: - -- `yudao-module-iot-net-component-core`: 核心接口和通用类 -- `yudao-module-iot-net-component-http`: 基于 HTTP 协议的设备通信组件 -- `yudao-module-iot-net-component-emqx`: 基于 MQTT/EMQX 的设备通信组件 - -## 组件架构 - -### 架构设计 - -各组件采用统一的架构设计和命名规范: - -- 配置类: `IotComponentXxxAutoConfiguration` - 提供Bean定义和组件初始化逻辑 -- 属性类: `IotComponentXxxProperties` - 定义组件的配置属性 -- 下行接口: `*DownstreamHandler` - 处理从平台到设备的下行通信 -- 上行接口: `*UpstreamServer` - 处理从设备到平台的上行通信 - -### Bean 命名规范 - -为避免 Bean 冲突,各个组件中的 Bean 已添加特定前缀: - -- HTTP 组件: `httpDeviceUpstreamServer`, `httpDeviceDownstreamHandler` -- EMQX 组件: `emqxDeviceUpstreamServer`, `emqxDeviceDownstreamHandler` - -### 组件启用规则 - -现在系统支持同时使用多个组件,但有以下规则: - -1. 当`yudao.iot.component.emqx.enabled=true`时,核心模块将优先使用EMQX组件 -2. 如果同时启用了多个组件,需要在业务代码中使用`@Qualifier`指定要使用的具体实现 - -> **重要提示:** -> 1. 组件库内部的默认配置文件**不会**被自动加载。必须将上述配置添加到主应用的配置文件中。 -> 2. 所有配置项现在都已增加空值处理,配置缺失时将使用合理的默认值 -> 3. `mqtt-host` 是唯一必须配置的参数,其他参数均有默认值 -> 4. `mqtt-ssl` 和 `auth-port` 缺失时的默认值分别为 `false` 和 `8080` -> 5. `mqtt-topics` 缺失时将使用默认主题 `/device/#` - -### 如何引用特定的 Bean - -在其他组件中引用这些 Bean 时,需要使用 `@Qualifier` 注解指定 Bean 名称: - -```java -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import cn.iocoder.yudao.module.iot.component.core.downstream.IotDeviceDownstreamHandler; - -@Service -public class YourServiceClass { - - // 注入 HTTP 组件的下行处理器 - @Autowired - @Qualifier("httpDeviceDownstreamHandler") - private IotDeviceDownstreamHandler httpDeviceDownstreamHandler; - - // 注入 EMQX 组件的下行处理器 - @Autowired - @Qualifier("emqxDeviceDownstreamHandler") - private IotDeviceDownstreamHandler emqxDeviceDownstreamHandler; - - // 使用示例 - public void example() { - // 使用 HTTP 组件 - httpDeviceDownstreamHandler.invokeDeviceService(...); - - // 使用 EMQX 组件 - emqxDeviceDownstreamHandler.invokeDeviceService(...); - } -} -``` - -### 组件选择指南 - -- **HTTP 组件**:适用于简单场景,设备通过 HTTP 接口与平台通信 -- **EMQX 组件**:适用于实时性要求高的场景,基于 MQTT 协议,支持发布/订阅模式 - -## 常见问题 - -### 1. 配置未加载问题 - -如果遇到以下日志: - -``` -MQTT配置: host=null, port=null, username=null, ssl=null -[connectMqtt][MQTT Host为null,无法连接] -``` - -这表明配置没有被正确加载。请确保: - -1. 在主应用的配置文件中(如 `application.yml` 或 `application-dev.yml`)添加了必要的 EMQX 配置 -2. 配置前缀正确:`yudao.iot.component.emqx` -3. 配置了必要的 `mqtt-host` 属性 - -### 2. mqttSsl 空指针异常 - -如果遇到以下错误: - -``` -Cannot invoke "java.lang.Boolean.booleanValue()" because the return value of "cn.iocoder.yudao.module.iot.component.emqx.config.IotEmqxComponentProperties.getMqttSsl()" is null -``` - -此问题已通过代码修复,现在会自动使用默认值 `false`。同样适用于其他配置项的空值问题。 - -### 3. authPort 空指针异常 - -如果遇到以下错误: - -``` -Cannot invoke "java.lang.Integer.intValue()" because the return value of "cn.iocoder.yudao.module.iot.component.emqx.config.IotEmqxComponentProperties.getAuthPort()" is null -``` - -此问题已通过代码修复,现在会自动使用默认值 `8080`。 - -### 4. Bean注入问题 - -如果遇到以下错误: - -``` -Parameter 1 of method deviceDownstreamServer in IotPluginCommonAutoConfiguration required a single bean, but 2 were found -``` - -此问题已通过修改核心配置类来解决。现在系统会根据组件的启用状态自动选择合适的实现: - -1. 优先使用EMQX组件(当`yudao.iot.component.emqx.enabled=true`时) -2. 如果EMQX未启用,则使用HTTP组件(当`yudao.iot.component.http.enabled=true`时) - -如果需要同时使用两个组件,业务代码中必须使用`@Qualifier`明确指定要使用的Bean。 - -### 5. 使用默认配置 - -组件现已加入完善的默认配置和空值处理机制,使配置更加灵活。但需要注意的是,这些默认配置值必须通过在主应用配置文件中设置相应的属性才能生效。 - -// TODO 芋艿:后续继续完善 README.md \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/pom.xml b/yudao-module-iot/yudao-module-iot-net-components/pom.xml index 6147006..d90f4a5 100644 --- a/yudao-module-iot/yudao-module-iot-net-components/pom.xml +++ b/yudao-module-iot/yudao-module-iot-net-components/pom.xml @@ -18,9 +18,8 @@ yudao-module-iot-net-component-core - yudao-module-iot-net-component-http yudao-module-iot-net-component-emqx yudao-module-iot-net-component-server - \ No newline at end of file + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonAutoConfiguration.java index 714b39e..7c28ee6 100644 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonAutoConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonAutoConfiguration.java @@ -11,9 +11,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; * * @author haohao */ -@AutoConfiguration @EnableConfigurationProperties(IotNetComponentCommonProperties.class) -@EnableScheduling // 开启定时任务,因为 IotNetComponentInstanceHeartbeatJob 是一个定时任务 public class IotNetComponentCommonAutoConfiguration { /** diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonProperties.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonProperties.java deleted file mode 100644 index 9931299..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonProperties.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.core.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.validation.annotation.Validated; - -/** - * IoT 网络组件通用配置属性 - * - * @author haohao - */ -@ConfigurationProperties(prefix = "yudao.iot.component") -@Validated -@Data -public class IotNetComponentCommonProperties { - - /** - * 组件的唯一标识 - *

- * 注意:该值将在运行时由各组件设置,不再从配置读取 - */ - private String pluginKey; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/constants/IotDeviceTopicEnum.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/constants/IotDeviceTopicEnum.java deleted file mode 100644 index 9429133..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/constants/IotDeviceTopicEnum.java +++ /dev/null @@ -1,179 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.core.constants; - -import lombok.Getter; - -// TODO @haohao:要不放到 enums 包下; -/** - * IoT 设备主题枚举 - *

- * 用于统一管理 MQTT 协议中的主题常量,基于 Alink 协议规范 - * - * @author haohao - */ -@Getter -public enum IotDeviceTopicEnum { - - // TODO @haohao:SYS_TOPIC_PREFIX、SERVICE_TOPIC_PREFIX、REPLY_SUFFIX 类似这种,要不搞成这个里面的静态变量?不是枚举值 - /** - * 系统主题前缀 - */ - SYS_TOPIC_PREFIX("/sys/", "系统主题前缀"), - - /** - * 服务调用主题前缀 - */ - SERVICE_TOPIC_PREFIX("/thing/service/", "服务调用主题前缀"), - - // TODO @haohao:注释时,中英文之间,有个空格; - /** - * 设备属性设置主题 - * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/set - * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply - */ - PROPERTY_SET_TOPIC("/thing/service/property/set", "设备属性设置主题"), - - /** - * 设备属性获取主题 - * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/get - * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/get_reply - */ - PROPERTY_GET_TOPIC("/thing/service/property/get", "设备属性获取主题"), - - /** - * 设备配置设置主题 - * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/config/set - * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/config/set_reply - */ - 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 - */ - OTA_UPGRADE_TOPIC("/thing/service/ota/upgrade", "设备OTA升级主题"), - - /** - * 设备属性上报主题 - * 请求Topic:/sys/${productKey}/${deviceName}/thing/event/property/post - * 响应Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply - */ - PROPERTY_POST_TOPIC("/thing/event/property/post", "设备属性上报主题"), - - /** - * 设备事件上报主题前缀 - */ - EVENT_POST_TOPIC_PREFIX("/thing/event/", "设备事件上报主题前缀"), - - /** - * 设备事件上报主题后缀 - */ - EVENT_POST_TOPIC_SUFFIX("/post", "设备事件上报主题后缀"), - - /** - * 响应主题后缀 - */ - REPLY_SUFFIX("_reply", "响应主题后缀"); - - private final String topic; - private final String description; - - // TODO @haohao:使用 lombok 去除 - IotDeviceTopicEnum(String topic, String description) { - this.topic = topic; - this.description = description; - } - - /** - * 构建设备服务调用主题 - * - * @param productKey 产品Key - * @param deviceName 设备名称 - * @param serviceIdentifier 服务标识符 - * @return 完整的主题路径 - */ - public static String buildServiceTopic(String productKey, String deviceName, String serviceIdentifier) { - // TODO @haohao:貌似 SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName 是统一的; - return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + - SERVICE_TOPIC_PREFIX.getTopic() + serviceIdentifier; - } - - /** - * 构建设备属性设置主题 - * - * @param productKey 产品Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildPropertySetTopic(String productKey, String deviceName) { - return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + PROPERTY_SET_TOPIC.getTopic(); - } - - /** - * 构建设备属性获取主题 - * - * @param productKey 产品Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildPropertyGetTopic(String productKey, String deviceName) { - return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + PROPERTY_GET_TOPIC.getTopic(); - } - - /** - * 构建设备配置设置主题 - * - * @param productKey 产品Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildConfigSetTopic(String productKey, String deviceName) { - return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + CONFIG_SET_TOPIC.getTopic(); - } - - /** - * 构建设备 OTA 升级主题 - * - * @param productKey 产品Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildOtaUpgradeTopic(String productKey, String deviceName) { - return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + OTA_UPGRADE_TOPIC.getTopic(); - } - - /** - * 构建设备属性上报主题 - * - * @param productKey 产品Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildPropertyPostTopic(String productKey, String deviceName) { - return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + PROPERTY_POST_TOPIC.getTopic(); - } - - /** - * 构建设备事件上报主题 - * - * @param productKey 产品Key - * @param deviceName 设备名称 - * @param eventIdentifier 事件标识符 - * @return 完整的主题路径 - */ - public static String buildEventPostTopic(String productKey, String deviceName, String eventIdentifier) { - return SYS_TOPIC_PREFIX.getTopic() + productKey + "/" + deviceName + - EVENT_POST_TOPIC_PREFIX.getTopic() + eventIdentifier + EVENT_POST_TOPIC_SUFFIX.getTopic(); - } - - /** - * 获取响应主题 - * - * @param requestTopic 请求主题 - * @return 响应主题 - */ - public static String getReplyTopic(String requestTopic) { - return requestTopic + REPLY_SUFFIX.getTopic(); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/pojo/IotStandardResponse.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/pojo/IotStandardResponse.java index 5959072..ce5adc3 100644 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/pojo/IotStandardResponse.java +++ b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/pojo/IotStandardResponse.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.net.component.core.pojo; import cn.hutool.core.util.StrUtil; import lombok.Data; -import lombok.experimental.Accessors; /** * IoT 标准协议响应实体类 @@ -12,7 +11,6 @@ import lombok.experimental.Accessors; * @author haohao */ @Data -@Accessors(chain = true) // TODO @haohao:貌似不用写 @Accessors(chain = true),我全局加啦,可见 lombok.config public class IotStandardResponse { /** diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/util/IotNetComponentCommonUtils.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/util/IotNetComponentCommonUtils.java index 9e432af..5598c29 100644 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/util/IotNetComponentCommonUtils.java +++ b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/util/IotNetComponentCommonUtils.java @@ -1,8 +1,5 @@ package cn.iocoder.yudao.module.iot.net.component.core.util; -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.system.SystemUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.net.component.core.pojo.IotStandardResponse; import io.vertx.core.http.HttpHeaders; @@ -17,40 +14,6 @@ import org.springframework.http.MediaType; public class IotNetComponentCommonUtils { /** - * 流程实例的进程编号 - */ - private static String processId; - - /** - * 获取进程ID - * - * @return 进程ID - */ - public static String getProcessId() { - if (StrUtil.isEmpty(processId)) { - initProcessId(); - } - return processId; - } - - /** - * 初始化进程ID - */ - private synchronized static void initProcessId() { - processId = String.format("%s@%d@%s", // IP@PID@${uuid} - SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID(), IdUtil.fastSimpleUUID()); - } - - /** - * 生成请求ID - * - * @return 生成的唯一请求ID - */ - public static String generateRequestId() { - return IdUtil.fastSimpleUUID(); - } - - /** * 将对象转换为JSON字符串后写入HTTP响应 * * @param routingContext 路由上下文 @@ -89,4 +52,5 @@ public class IotNetComponentCommonUtils { .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) .end(JsonUtils.toJsonString(response)); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/pom.xml b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/pom.xml deleted file mode 100644 index cb71977..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - yudao-module-iot-net-components - cn.iocoder.boot - ${revision} - - 4.0.0 - yudao-module-iot-net-component-http - jar - - ${project.artifactId} - - 物联网网络组件 HTTP 模块 - - - - - cn.iocoder.boot - yudao-module-iot-net-component-core - ${revision} - - - - - - - - - - - - io.vertx - vertx-web - - - - - org.springframework.boot - spring-boot-starter-validation - true - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpAutoConfiguration.java deleted file mode 100644 index d65a502..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpAutoConfiguration.java +++ /dev/null @@ -1,90 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.http.config; - -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; -import cn.iocoder.yudao.module.iot.net.component.http.upstream.IotDeviceUpstreamServer; -import io.vertx.core.Vertx; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.event.ApplicationStartedEvent; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Lazy; -import org.springframework.context.event.EventListener; - -/** - * IoT 网络组件 HTTP 的自动配置类 - * - * @author haohao - */ -@Slf4j -@AutoConfiguration -@EnableConfigurationProperties(IotNetComponentHttpProperties.class) -@ConditionalOnProperty(prefix = "yudao.iot.component.http", name = "enabled", havingValue = "true", matchIfMissing = false) -@ComponentScan(basePackages = { - "cn.iocoder.yudao.module.iot.net.component.http" // 只扫描 HTTP 组件包 -}) -public class IotNetComponentHttpAutoConfiguration { - - /** - * 初始化 HTTP 组件 - * - * @param event 应用启动事件 - */ - @EventListener(ApplicationStartedEvent.class) - public void initialize(ApplicationStartedEvent event) { - log.info("[IotNetComponentHttpAutoConfiguration][开始初始化]"); - - // TODO @芋艿:临时处理 - IotMessageBus messageBus = event.getApplicationContext() - .getBean(IotMessageBus.class); - messageBus.register(new IotMessageBusSubscriber() { - - @Override - public String getTopic() { - return IotDeviceMessage.buildMessageBusGatewayDeviceMessageTopic("yy"); - } - - @Override - public String getGroup() { - return "test"; - } - - @Override - public void onMessage(IotDeviceMessage message) { - System.out.println(message); - } - - }); - } - - // TODO @芋艿:貌似这里不用注册 bean? - /** - * 创建 Vert.x 实例 - * - * @return Vert.x 实例 - */ - @Bean(name = "httpVertx") - public Vertx vertx() { - return Vertx.vertx(); - } - - /** - * 创建设备上行服务器 - */ - @Bean(name = "httpDeviceUpstreamServer", initMethod = "start", destroyMethod = "stop") - public IotDeviceUpstreamServer deviceUpstreamServer( - @Lazy @Qualifier("httpVertx") Vertx vertx, - IotDeviceUpstreamApi deviceUpstreamApi, - IotNetComponentHttpProperties properties, - IotDeviceMessageProducer deviceMessageProducer) { - return new IotDeviceUpstreamServer(vertx, properties, deviceUpstreamApi, deviceMessageProducer); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpProperties.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpProperties.java deleted file mode 100644 index 02bbca2..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpProperties.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.http.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.validation.annotation.Validated; - -/** - * IoT HTTP 网络组件配置属性 - * - * @author haohao - */ -@ConfigurationProperties(prefix = "yudao.iot.component.http") -@Validated -@Data -public class IotNetComponentHttpProperties { - - /** - * 是否启用 HTTP 组件 - */ - private Boolean enabled; - - /** - * HTTP 服务端口 - */ - private Integer serverPort; - - /** - * 连接超时时间(毫秒) - *

- * 默认值: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-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/downstream/IotDeviceDownstreamHandlerImpl.java deleted file mode 100644 index f099403..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/downstream/IotDeviceDownstreamHandlerImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.http.downstream; - -// TODO @芋艿:实现下; -///** -// * HTTP 网络组件的 {@link IotDeviceDownstreamHandler} 实现类 -// *

-// * 但是:由于设备通过 HTTP 短链接接入,导致其实无法下行指导给 device 设备,所以基本都是直接返回失败!!! -// * 类似 MQTT、WebSocket、TCP 网络组件,是可以实现下行指令的。 -// * -// * @author 芋道源码 -// */ -//@Slf4j -//public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler { -// -// /** -// * 不支持的错误消息 -// */ -// private static final String NOT_SUPPORTED_MSG = "HTTP 不支持设备下行通信"; -// -// @Override -// public CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) { -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG); -// } -// -// @Override -// public CommonResult getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO) { -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG); -// } -// -// @Override -// public CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) { -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG); -// } -// -// @Override -// public CommonResult setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO) { -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG); -// } -// -// @Override -// public CommonResult upgradeDeviceOta(IotDeviceOtaUpgradeReqDTO upgradeReqDTO) { -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG); -// } -//} diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/IotDeviceUpstreamServer.java deleted file mode 100644 index e9e40f7..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/IotDeviceUpstreamServer.java +++ /dev/null @@ -1,73 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.http.upstream; - -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; -import cn.iocoder.yudao.module.iot.net.component.http.config.IotNetComponentHttpProperties; -import cn.iocoder.yudao.module.iot.net.component.http.upstream.router.IotDeviceUpstreamVertxHandler; -import io.vertx.core.AbstractVerticle; -import io.vertx.core.Promise; -import io.vertx.core.Vertx; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.handler.BodyHandler; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -/** - * IoT 设备上行服务器 - *

- * 处理设备通过 HTTP 方式接入的上行消息 - * - * @author 芋道源码 - */ -@RequiredArgsConstructor -@Slf4j -public class IotDeviceUpstreamServer extends AbstractVerticle { - - private final Vertx vertx; - - private final IotNetComponentHttpProperties httpProperties; - - private final IotDeviceUpstreamApi deviceUpstreamApi; - - private final IotDeviceMessageProducer deviceMessageProducer; - - @Override - public void start() { - start(Promise.promise()); - } - - // TODO @haohao:这样貌似初始化不到;我临时拷贝上去了 - @Override - public void start(Promise startPromise) { - // 创建路由 - Router router = Router.router(vertx); - router.route().handler(BodyHandler.create()); - - // 创建处理器 - IotDeviceUpstreamVertxHandler upstreamHandler = new IotDeviceUpstreamVertxHandler( - deviceUpstreamApi, deviceMessageProducer); - - // 添加路由处理器 - router.post(IotDeviceUpstreamVertxHandler.PROPERTY_PATH).handler(upstreamHandler::handle); - router.post(IotDeviceUpstreamVertxHandler.EVENT_PATH).handler(upstreamHandler::handle); - - // 启动 HTTP 服务器 - vertx.createHttpServer() - .requestHandler(router) - .listen(httpProperties.getServerPort(), result -> { - if (result.succeeded()) { - log.info("[start][IoT 设备上行服务器启动成功,端口:{}]", httpProperties.getServerPort()); - startPromise.complete(); - } else { - log.error("[start][IoT 设备上行服务器启动失败]", result.cause()); - startPromise.fail(result.cause()); - } - }); - } - - @Override - public void stop(Promise stopPromise) { - log.info("[stop][IoT 设备上行服务器已停止]"); - stopPromise.complete(); - } -} diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/auth/IotDeviceAuthProvider.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/auth/IotDeviceAuthProvider.java deleted file mode 100644 index 10b00cd..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/auth/IotDeviceAuthProvider.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.http.upstream.auth; - -import io.vertx.core.Future; -import io.vertx.ext.web.RoutingContext; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.ApplicationContext; - -// TODO @haohao:待实现,或者不需要? -/** - * IoT 设备认证提供者 - *

- * 用于 HTTP 设备接入时的身份认证 - * - * @author haohao - */ -@Slf4j -public class IotDeviceAuthProvider { - - private final ApplicationContext applicationContext; - - /** - * 构造函数 - * - * @param applicationContext Spring 应用上下文 - */ - public IotDeviceAuthProvider(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - /** - * 认证设备 - * - * @param context 路由上下文 - * @param clientId 设备唯一标识 - * @return 认证结果 Future 对象 - */ - public Future authenticate(RoutingContext context, String clientId) { - if (clientId == null || clientId.isEmpty()) { - return Future.failedFuture("clientId 不能为空"); - } - - try { - log.info("[authenticate][设备认证成功,clientId={}]", clientId); - return Future.succeededFuture(); - } catch (Exception e) { - log.error("[authenticate][设备认证异常,clientId={}]", clientId, e); - return Future.failedFuture(e); - } - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/router/IotDeviceUpstreamVertxHandler.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/router/IotDeviceUpstreamVertxHandler.java deleted file mode 100644 index 47e90e0..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/router/IotDeviceUpstreamVertxHandler.java +++ /dev/null @@ -1,330 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.http.upstream.router; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; -import cn.iocoder.yudao.module.iot.net.component.core.constants.IotDeviceTopicEnum; -import cn.iocoder.yudao.module.iot.net.component.core.pojo.IotStandardResponse; -import cn.iocoder.yudao.module.iot.net.component.core.util.IotNetComponentCommonUtils; -import io.vertx.core.Handler; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.web.RoutingContext; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; - -/** - * IoT 设备上行统一处理的 Vert.x Handler - *

- * 统一处理设备属性上报和事件上报的请求。 - * - * @author 芋道源码 - */ -@RequiredArgsConstructor -@Slf4j -public class IotDeviceUpstreamVertxHandler implements Handler { - - // TODO @haohao:你说,咱要不要把 "/sys/:productKey/:deviceName" - // + IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic(),也抽到 IotDeviceTopicEnum 的 build 这种?尽量都收敛掉? - /** - * 属性上报路径 - */ - public static final String PROPERTY_PATH = "/sys/:productKey/:deviceName" - + IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic(); - - /** - * 事件上报路径 - */ - public static final String EVENT_PATH = "/sys/:productKey/:deviceName" - + IotDeviceTopicEnum.EVENT_POST_TOPIC_PREFIX.getTopic() + ":identifier" - + IotDeviceTopicEnum.EVENT_POST_TOPIC_SUFFIX.getTopic(); - - /** - * 属性上报方法标识 - */ - 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"; - - /** - * 设备上行 API - */ - private final IotDeviceUpstreamApi deviceUpstreamApi; - /** - * 设备消息生产者 - */ - private final IotDeviceMessageProducer deviceMessageProducer; - - @Override - public void handle(RoutingContext routingContext) { - String path = routingContext.request().path(); - String requestId = IdUtil.fastSimpleUUID(); - - try { - // 1. 解析通用参数 - Map params = parseCommonParams(routingContext, requestId); - String productKey = params.get("productKey"); - String deviceName = params.get("deviceName"); - JsonObject body = routingContext.body().asJsonObject(); - requestId = params.get("requestId"); - - // 2. 根据路径模式处理不同类型的请求 - if (isPropertyPostPath(path)) { - // 处理属性上报 - handlePropertyPost(routingContext, productKey, deviceName, requestId, body); - return; - } - - if (isEventPostPath(path)) { - // 处理事件上报 - String identifier = routingContext.pathParam("identifier"); - handleEventPost(routingContext, productKey, deviceName, identifier, requestId, body); - return; - } - - // 不支持的请求路径 - sendErrorResponse(routingContext, requestId, "unknown", BAD_REQUEST.getCode(), "不支持的请求路径"); - } catch (Exception e) { - log.error("[handle][处理上行请求异常] path={}", path, e); - String method = determineMethodFromPath(path, routingContext); - sendErrorResponse(routingContext, requestId, method, INTERNAL_SERVER_ERROR.getCode(), - INTERNAL_SERVER_ERROR.getMsg()); - } - } - - /** - * 解析通用参数 - * - * @param routingContext 路由上下文 - * @param defaultRequestId 默认请求 ID - * @return 参数映射 - */ - private Map parseCommonParams(RoutingContext routingContext, String defaultRequestId) { - Map params = MapUtil.newHashMap(); - params.put("productKey", routingContext.pathParam("productKey")); - params.put("deviceName", routingContext.pathParam("deviceName")); - - JsonObject body = routingContext.body().asJsonObject(); - String requestId = ObjUtil.defaultIfNull(body.getString("id"), defaultRequestId); - params.put("requestId", requestId); - - return params; - } - - /** - * 判断是否是属性上报路径 - * - * @param path 路径 - * @return 是否是属性上报路径 - */ - private boolean isPropertyPostPath(String path) { - return StrUtil.endWith(path, IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic()); - } - - /** - * 判断是否是事件上报路径 - * - * @param path 路径 - * @return 是否是事件上报路径 - */ - private boolean isEventPostPath(String path) { - return StrUtil.contains(path, IotDeviceTopicEnum.EVENT_POST_TOPIC_PREFIX.getTopic()) - && StrUtil.endWith(path, IotDeviceTopicEnum.EVENT_POST_TOPIC_SUFFIX.getTopic()); - } - - /** - * 处理属性上报请求 - * - * @param routingContext 路由上下文 - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @param requestId 请求 ID - * @param body 请求体 - */ - private void handlePropertyPost(RoutingContext routingContext, String productKey, String deviceName, - String requestId, JsonObject body) { - // 1.1 构建设备消息 - String deviceKey = "xxx"; // TODO @芋艿:待支持 - Long tenantId = 1L; // TODO @芋艿:待支持 - IotDeviceMessage message = IotDeviceMessage.of(productKey, deviceName, deviceKey, - requestId, LocalDateTime.now(), IotNetComponentCommonUtils.getProcessId(), tenantId) - .ofPropertyReport(parsePropertiesFromBody(body)); - // 1.2 发送消息 - deviceMessageProducer.sendDeviceMessage(message); - - // 2. 返回响应 - sendResponse(routingContext, requestId, PROPERTY_METHOD, null); - } - - /** - * 处理事件上报请求 - * - * @param routingContext 路由上下文 - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @param identifier 事件标识符 - * @param requestId 请求 ID - * @param body 请求体 - */ - private void handleEventPost(RoutingContext routingContext, String productKey, String deviceName, - String identifier, String requestId, JsonObject body) { - // 处理事件上报 - IotDeviceEventReportReqDTO reportReqDTO = parseEventReportRequest(productKey, deviceName, identifier, - requestId, body); - - // 事件上报 - CommonResult result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO); - String method = EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX; - - // 返回响应 - sendResponse(routingContext, requestId, method, result); - } - - /** - * 发送响应 - * - * @param routingContext 路由上下文 - * @param requestId 请求 ID - * @param method 方法名 - * @param result 结果 - */ - private void sendResponse(RoutingContext routingContext, String requestId, String method, - CommonResult result) { - // TODO @芋艿:后续再优化 - IotStandardResponse response; - if (result == null ) { - response = IotStandardResponse.success(requestId, method, null); - } else if (result.isSuccess()) { - response = IotStandardResponse.success(requestId, method, result.getData()); - } else { - response = IotStandardResponse.error(requestId, method, result.getCode(), result.getMsg()); - } - IotNetComponentCommonUtils.writeJsonResponse(routingContext, response); - } - - /** - * 发送错误响应 - * - * @param routingContext 路由上下文 - * @param requestId 请求 ID - * @param method 方法名 - * @param code 错误代码 - * @param message 错误消息 - */ - private void sendErrorResponse(RoutingContext routingContext, String requestId, String method, Integer code, - String message) { - IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, code, message); - IotNetComponentCommonUtils.writeJsonResponse(routingContext, errorResponse); - } - - /** - * 从路径确定方法名 - * - * @param path 路径 - * @param routingContext 路由上下文 - * @return 方法名 - */ - private String determineMethodFromPath(String path, RoutingContext routingContext) { - if (StrUtil.contains(path, "/property/")) { - return PROPERTY_METHOD; - } - - return EVENT_METHOD_PREFIX - + (routingContext.pathParams().containsKey("identifier") - ? routingContext.pathParam("identifier") - : "unknown") - + - EVENT_METHOD_SUFFIX; - } - - // TODO @芋艿:这块在看看 - /** - * 从请求体解析属性 - * - * @param body 请求体 - * @return 属性映射 - */ - private Map parsePropertiesFromBody(JsonObject body) { - Map properties = MapUtil.newHashMap(); - JsonObject params = body.getJsonObject("params"); - if (CollUtil.isEmpty(params)) { - return properties; - } - - // 将标准格式的 params 转换为平台需要的 properties 格式 - for (String key : params.fieldNames()) { - Object valueObj = params.getValue(key); - // 如果是复杂结构(包含 value 和 time) - if (valueObj instanceof JsonObject) { - JsonObject valueJson = (JsonObject) valueObj; - properties.put(key, valueJson.containsKey("value") ? valueJson.getValue("value") : valueObj); - } else { - properties.put(key, valueObj); - } - } - return properties; - } - - /** - * 解析事件上报请求 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @param identifier 事件标识符 - * @param requestId 请求 ID - * @param body 请求体 - * @return 事件上报请求 DTO - */ - private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, - String requestId, JsonObject body) { - // 解析参数 - Map params = parseParamsFromBody(body); - - // 构建事件上报请求 DTO - return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO() - .setRequestId(requestId) - .setProcessId(IotNetComponentCommonUtils.getProcessId()) - .setReportTime(LocalDateTime.now()) - .setProductKey(productKey) - .setDeviceName(deviceName)).setIdentifier(identifier).setParams(params); - } - - /** - * 从请求体解析参数 - * - * @param body 请求体 - * @return 参数映射 - */ - private Map parseParamsFromBody(JsonObject body) { - Map params = MapUtil.newHashMap(); - JsonObject paramsJson = body.getJsonObject("params"); - if (CollUtil.isEmpty(paramsJson)) { - return params; - } - - for (String key : paramsJson.fieldNames()) { - params.put(key, paramsJson.getValue(key)); - } - return params; - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 9d3b405..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1 +0,0 @@ -cn.iocoder.yudao.module.iot.net.component.http.config.IotNetComponentHttpAutoConfiguration \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/application.yml deleted file mode 100644 index bdb6b74..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/application.yml +++ /dev/null @@ -1,10 +0,0 @@ -# HTTP组件默认配置 -yudao: - iot: - component: - core: - plugin-key: http # 插件的唯一标识 -# http: -# enabled: true # 是否启用HTTP组件,默认启用 -# server-port: 8092 - diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/pom.xml b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/pom.xml index eaf000e..457feee 100644 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/pom.xml +++ b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/pom.xml @@ -17,32 +17,12 @@ - - - org.springframework.boot - spring-boot-starter - - org.springframework.boot spring-boot-starter-web - - - cn.iocoder.boot - yudao-module-iot-net-component-core - ${revision} - - - - - cn.iocoder.boot - yudao-module-iot-net-component-http - ${revision} - - cn.iocoder.boot @@ -50,32 +30,8 @@ ${revision} - - - org.apache.rocketmq - rocketmq-spring-boot-starter - - - - - ${project.artifactId} - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring.boot.version} - - - - repackage - - - - - - + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/NetComponentServerApplication.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/NetComponentServerApplication.java deleted file mode 100644 index 0d40edb..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/NetComponentServerApplication.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.server; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * IoT 网络组件聚合启动服务 - * - * @author haohao - */ -@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}.module.iot.net.component"}) -public class NetComponentServerApplication { - - public static void main(String[] args) { - SpringApplication.run(NetComponentServerApplication.class, args); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerConfiguration.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerConfiguration.java index 33fd957..7d646c5 100644 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerConfiguration.java @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.net.component.server.config; import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; import cn.iocoder.yudao.module.iot.net.component.server.upstream.IotComponentUpstreamClient; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; @@ -50,28 +49,4 @@ public class IotNetComponentServerConfiguration { return new IotComponentUpstreamClient(properties, restTemplate); } - /** - * 配置默认的设备上行客户端,避免在独立运行模式下的循环依赖问题 - * - * @return 设备上行客户端 - */ - @Bean - @ConditionalOnMissingBean(name = "serverDeviceUpstreamClient") - public Object serverDeviceUpstreamClient() { - // 返回一个空对象,避免找不到类的问题 - return new Object(); - } - - // TODO @haohao:这个是不是木有用呀? - /** - * 配置默认的组件实例注册客户端 - * - * @return 插件实例注册客户端 - */ - @Bean - @ConditionalOnMissingBean(name = "serverPluginInstanceRegistryClient") - public Object serverPluginInstanceRegistryClient() { - // 返回一个空对象,避免找不到类的问题 - return new Object(); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerProperties.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerProperties.java index bb5a973..bc0a65a 100644 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerProperties.java +++ b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerProperties.java @@ -18,8 +18,6 @@ public class IotNetComponentServerProperties { /** * 上行 URL,用于向主应用程序上报数据 - *

- * 默认:http://127.0.0.1:48080 */ private String upstreamUrl = "http://127.0.0.1:48080"; @@ -33,18 +31,4 @@ public class IotNetComponentServerProperties { */ private Duration upstreamReadTimeout = Duration.ofSeconds(30); - /** - * 下行服务端口,用于接收主应用程序的请求 - *

- * 默认:18888 - */ - private Integer downstreamPort = 18888; - - /** - * 组件服务器唯一标识 - *

- * 默认:yudao-module-iot-net-component-server - */ - private String serverKey = "yudao-module-iot-net-component-server"; - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/controller/HealthController.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/controller/HealthController.java deleted file mode 100644 index 4f652da..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/controller/HealthController.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.iot.net.component.server.controller; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.HashMap; -import java.util.Map; - -// TODO @haohao:这个是必须的哇?可以考虑基于 spring boot actuator; -/** - * 健康检查接口 - * - * @author haohao - */ -@RestController -@RequestMapping("/health") -public class HealthController { - - /** - * 健康检查接口 - * - * @return 返回服务状态信息 - */ - @GetMapping("/status") - public Map status() { - Map result = new HashMap<>(); - result.put("status", "UP"); - result.put("message", "IoT 网络组件服务运行正常"); - result.put("timestamp", System.currentTimeMillis()); - return result; - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/upstream/IotComponentUpstreamClient.java b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/upstream/IotComponentUpstreamClient.java index 53ea8f1..7959c5b 100644 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/upstream/IotComponentUpstreamClient.java +++ b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/upstream/IotComponentUpstreamClient.java @@ -1,8 +1,6 @@ package cn.iocoder.yudao.module.iot.net.component.server.upstream; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*; import cn.iocoder.yudao.module.iot.net.component.server.config.IotNetComponentServerProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -19,7 +17,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC */ @RequiredArgsConstructor @Slf4j -public class IotComponentUpstreamClient implements IotDeviceUpstreamApi { +public class IotComponentUpstreamClient { public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; @@ -27,47 +25,11 @@ public class IotComponentUpstreamClient implements IotDeviceUpstreamApi { private final RestTemplate restTemplate; - @Override - public CommonResult updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) { - String url = properties.getUpstreamUrl() + URL_PREFIX + "/update-state"; - return doPost(url, updateReqDTO); - } - - @Override - public CommonResult reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { - String url = properties.getUpstreamUrl() + URL_PREFIX + "/report-event"; - return doPost(url, reportReqDTO); - } - - @Override - public CommonResult registerDevice(IotDeviceRegisterReqDTO registerReqDTO) { - String url = properties.getUpstreamUrl() + URL_PREFIX + "/register-device"; - return doPost(url, registerReqDTO); - } - - @Override - public CommonResult registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) { - String url = properties.getUpstreamUrl() + URL_PREFIX + "/register-sub-device"; - return doPost(url, registerReqDTO); - } - - @Override - public CommonResult addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) { - String url = properties.getUpstreamUrl() + URL_PREFIX + "/add-device-topology"; - return doPost(url, addReqDTO); - } - - @Override - public CommonResult authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) { - String url = properties.getUpstreamUrl() + URL_PREFIX + "/authenticate-emqx-connection"; - return doPost(url, authReqDTO); - } - - @Override - public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { - String url = properties.getUpstreamUrl() + URL_PREFIX + "/report-property"; - return doPost(url, reportReqDTO); - } +// @Override +// public CommonResult updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) { +// String url = properties.getUpstreamUrl() + URL_PREFIX + "/update-state"; +// return doPost(url, updateReqDTO); +// } @SuppressWarnings("unchecked") private CommonResult doPost(String url, T requestBody) { diff --git a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/resources/application.yml deleted file mode 100644 index f1b104b..0000000 --- a/yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/resources/application.yml +++ /dev/null @@ -1,70 +0,0 @@ -# 服务器配置 -server: - port: 18080 # 修改端口,避免与主应用的8080端口冲突 - -# Spring 配置 -spring: - application: - name: iot-component-server - # 允许循环引用 - main: - allow-circular-references: true - allow-bean-definition-overriding: true - -# Yudao 配置 -yudao: - info: - base-package: cn.iocoder.yudao # 主项目包路径,确保正确 - iot: - component: - - # 网络组件服务器专用配置 - server: - # 上行通信配置,用于向主程序上报数据 - upstream-url: http://127.0.0.1:48080 # 主程序 API 地址 - upstream-connect-timeout: 30s # 连接超时 - upstream-read-timeout: 30s # 读取超时 - - # 下行通信配置,用于接收主程序的控制指令 - downstream-port: 18888 # 下行服务器端口 - - # 组件服务唯一标识 - server-key: yudao-module-iot-net-component-server - - # ==================================== - # 针对引入的 HTTP 组件的配置 - # ==================================== - http: - enabled: true # 启用HTTP组件 - server-port: 8092 # HTTP组件服务端口 - - # ==================================== - # 针对引入的 EMQX 组件的配置 - # ==================================== - emqx: - enabled: true # 启用EMQX组件 - mqtt-host: 127.0.0.1 # MQTT服务器主机地址 - mqtt-port: 1883 # MQTT服务器端口 - mqtt-username: admin # MQTT服务器用户名 - mqtt-password: admin123 # MQTT服务器密码 - mqtt-ssl: false # 是否启用SSL - mqtt-topics: # 订阅的主题列表 - - "/sys/#" - auth-port: 8101 # 认证端口 - message-bus: - type: rocketmq # 消息总线的类型 - -# 日志配置 -logging: - level: - cn.iocoder.yudao: INFO - root: INFO - ---- #################### 消息队列相关 #################### - -# rocketmq 配置项,对应 RocketMQProperties 配置类 -rocketmq: - name-server: 127.0.0.1:9876 # RocketMQ Namesrv - # Producer 配置项 - producer: - group: ${spring.application.name}_PRODUCER # 生产者分组 -- libgit2 0.21.4