From 4a251b19c48c5f8f2568acc222b06601a6e26c9c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 30 Jan 2025 18:44:50 +0800 Subject: [PATCH] 【代码新增】IoT:优化 plugins 相关的代码,包拆成分 upstream、downstream、config 三个,职责更明确 --- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java | 59 ----------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamHandler.java | 23 ----------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamServer.java | 71 ----------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/router/IotDeviceServiceInvokeVertxHandler.java | 23 ----------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/upstream/IotDeviceUpstreamClient.java | 71 ----------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java | 23 +++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java | 23 +++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 2 +- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties | 2 +- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml | 2 +- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java | 6 +++--- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java | 81 --------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java | 81 --------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java | 27 +++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java | 52 ---------------------------------------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java | 34 ++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/downstream/IotDeviceDownstreamHandlerImpl.java | 34 ---------------------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/package-info.java | 1 - yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/upstream/HttpVertxHandler.java | 93 --------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 25 files changed, 579 insertions(+), 595 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamHandler.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamServer.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/router/IotDeviceServiceInvokeVertxHandler.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/upstream/IotDeviceUpstreamClient.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/downstream/IotDeviceDownstreamHandlerImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/package-info.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/upstream/HttpVertxHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java create mode 100644 yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java new file mode 100644 index 0000000..9a76355 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/IotPluginCommonAutoConfiguration.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.iot.plugin.common.config; + +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamServer; +import cn.iocoder.yudao.module.iot.plugin.common.upstream.IotDeviceUpstreamClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +import java.time.Duration; + +/** + * IoT 插件的通用自动配置类 + * + * @author haohao + */ +@AutoConfiguration +public class IotPluginCommonAutoConfiguration { + + // TODO @haohao:这个要不搞个配置类哈 + @Value("${iot.device-data.url}") + private String deviceDataUrl; + + /** + * 创建 RestTemplate 实例 + * + * @return RestTemplate 实例 + */ + @Bean + public RestTemplate restTemplate() { + // 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 + return new RestTemplateBuilder() + .connectTimeout(Duration.ofMillis(5000)) // 设置连接超时时间 + .readTimeout(Duration.ofMillis(5000)) // 设置读取超时时间 + .build(); + } + + /** + * 创建 DeviceDataApi 实例 + * + * @param restTemplate RestTemplate 实例 + * @return DeviceDataApi 实例 + */ + @Bean + public IotDeviceUpstreamApi deviceDataApi(RestTemplate restTemplate) { + return new IotDeviceUpstreamClient(restTemplate, deviceDataUrl); + } + + @Bean(initMethod = "start", destroyMethod = "stop") + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public IotDeviceDownstreamServer deviceDownstreamServer(IotDeviceDownstreamHandler deviceDownstreamHandler) { + return new IotDeviceDownstreamServer(deviceDownstreamHandler); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java deleted file mode 100644 index 605a903..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/config/YudaoDeviceDataApiAutoConfiguration.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.common.config; - -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.plugin.common.core.downstream.IotDeviceDownstreamHandler; -import cn.iocoder.yudao.module.iot.plugin.common.core.downstream.IotDeviceDownstreamServer; -import cn.iocoder.yudao.module.iot.plugin.common.core.upstream.IotDeviceUpstreamClient; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.web.client.RestTemplate; - -import java.time.Duration; - -// TODO @芋艿:配置类的名字 -/** - * 设备数据 API 初始化器 - * - * @author haohao - */ -@AutoConfiguration -public class YudaoDeviceDataApiAutoConfiguration { - - // TODO @haohao:这个要不搞个配置类哈 - @Value("${iot.device-data.url}") - private String deviceDataUrl; - - /** - * 创建 RestTemplate 实例 - * - * @return RestTemplate 实例 - */ - @Bean - public RestTemplate restTemplate() { - // 如果你有更多的自定义需求,比如连接池、超时时间等,可以在这里设置 - return new RestTemplateBuilder() - .connectTimeout(Duration.ofMillis(5000)) // 设置连接超时时间 - .readTimeout(Duration.ofMillis(5000)) // 设置读取超时时间 - .build(); - } - - /** - * 创建 DeviceDataApi 实例 - * - * @param restTemplate RestTemplate 实例 - * @return DeviceDataApi 实例 - */ - @Bean - public IotDeviceUpstreamApi deviceDataApi(RestTemplate restTemplate) { - return new IotDeviceUpstreamClient(restTemplate, deviceDataUrl); - } - - @Bean(initMethod = "start", destroyMethod = "stop") - @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") - public IotDeviceDownstreamServer deviceDownstreamServer(IotDeviceDownstreamHandler deviceDownstreamHandler) { - return new IotDeviceDownstreamServer(deviceDownstreamHandler); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamHandler.java deleted file mode 100644 index c140c32..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamHandler.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.common.core.downstream; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; - -/** - * IoT 设备下行处理器 - * - * 目的:每个 plugin 需要实现,用于处理 server 下行的指令(请求),从而实现从 server => plugin => device 的下行流程 - * - * @author 芋道源码 - */ -public interface IotDeviceDownstreamHandler { - - CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO); - - CommonResult getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO); - - CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO); - -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamServer.java deleted file mode 100644 index 310415f..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/IotDeviceDownstreamServer.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.common.core.downstream; - -import cn.iocoder.yudao.module.iot.plugin.common.core.downstream.router.IotDeviceServiceInvokeVertxHandler; -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 lombok.extern.slf4j.Slf4j; - -@Slf4j -public class IotDeviceDownstreamServer { - - private final Vertx vertx; - private final HttpServer server; - - public IotDeviceDownstreamServer(IotDeviceDownstreamHandler deviceDownstreamHandler) { - // 创建 Vertx 实例 - this.vertx = Vertx.vertx(); - // 创建 Router 实例 - Router router = Router.router(vertx); - router.route().handler(BodyHandler.create()); // 处理 Body - router.post(IotDeviceServiceInvokeVertxHandler.PATH).handler( - new IotDeviceServiceInvokeVertxHandler(deviceDownstreamHandler)); // 处理 Service Invoke - // 创建 HttpServer 实例 - this.server = vertx.createHttpServer().requestHandler(router); - } - - public void start() { - log.info("[start][开始启动]"); - server.listen(0) // 通过 0 自动选择端口 - .toCompletionStage() - .toCompletableFuture() - .join(); - log.info("[start][启动完成,端口({})]", this.server.actualPort()); - } - - public void stop() { - log.info("[stop][开始关闭]"); - try { - // 关闭 HTTP 服务器 - if (server != null) { - server.close() - .toCompletionStage() - .toCompletableFuture() - .join(); - } - - // 关闭 Vertx 实例 - if (vertx != null) { - vertx.close() - .toCompletionStage() - .toCompletableFuture() - .join(); - } - log.info("[stop][关闭完成]"); - } catch (Exception e) { - log.error("[stop][关闭异常]", e); - throw new RuntimeException(e); - } - } - - /** - * 获得端口 - * - * @return 端口 - */ - public int getPort() { - return this.server.actualPort(); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/router/IotDeviceServiceInvokeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/router/IotDeviceServiceInvokeVertxHandler.java deleted file mode 100644 index 2f53b62..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/downstream/router/IotDeviceServiceInvokeVertxHandler.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.common.core.downstream.router; - -import cn.iocoder.yudao.module.iot.plugin.common.core.downstream.IotDeviceDownstreamHandler; -import io.vertx.core.Handler; -import io.vertx.ext.web.RoutingContext; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@RequiredArgsConstructor -public class IotDeviceServiceInvokeVertxHandler implements Handler { - - public static final String PATH = "/sys/:productKey/:deviceName/thing/service/:identifier"; - - private final IotDeviceDownstreamHandler deviceDownstreamHandler; - - @Override - public void handle(RoutingContext routingContext) { - // TODO 芋艿:这里没实现 - deviceDownstreamHandler.invokeDeviceService(null); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/upstream/IotDeviceUpstreamClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/upstream/IotDeviceUpstreamClient.java deleted file mode 100644 index 5a729c0..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/core/upstream/IotDeviceUpstreamClient.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.common.core.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.IotDeviceEventReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.client.RestTemplate; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -/** - * 设备数据 Upstream 上行客户端 - * - * 通过 HTTP 调用远程的 IotDeviceUpstreamApi 接口 - * - * @author haohao - */ -@Slf4j -public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi { - - public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; - - private final RestTemplate restTemplate; - private final String deviceDataUrl; - - // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 - // TODO @haohao:可以用 lombok 简化 - public IotDeviceUpstreamClient(RestTemplate restTemplate, String deviceDataUrl) { - this.restTemplate = restTemplate; - this.deviceDataUrl = deviceDataUrl; - } - - // TODO @haohao:返回结果,不用 CommonResult 哈。 - @Override - public CommonResult updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) { - String url = deviceDataUrl + URL_PREFIX + "/update-state"; - return doPost(url, updateReqDTO, "updateDeviceState"); - } - - @Override - public CommonResult reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { - String url = deviceDataUrl + URL_PREFIX + "/report-event"; - return doPost(url, reportReqDTO, "reportDeviceEventData"); - } - - @Override - public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { - String url = deviceDataUrl + URL_PREFIX + "/report-property"; - return doPost(url, reportReqDTO, "reportDevicePropertyData"); - } - - // TODO @haohao:未来可能有 get 类型哈 - /** - * 将与远程服务交互的通用逻辑抽取成一个私有方法 - */ - private CommonResult doPost(String url, T requestBody, String actionName) { - log.info("[{}] Sending request to URL: {}", actionName, url); - try { - // 这里指定返回类型为 CommonResult,根据后台服务返回的实际结构做调整 - restTemplate.postForObject(url, requestBody, CommonResult.class); - // TODO @haohao:check 结果,是否成功 - return success(true); - } catch (Exception e) { - log.error("[{}] Error sending request to URL: {}", actionName, url, e); - return CommonResult.error(400, "Request error: " + e.getMessage()); - } - } - -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java new file mode 100644 index 0000000..3c6fee7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.iot.plugin.common.downstream; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; + +/** + * IoT 设备下行处理器 + * + * 目的:每个 plugin 需要实现,用于处理 server 下行的指令(请求),从而实现从 server => plugin => device 的下行流程 + * + * @author 芋道源码 + */ +public interface IotDeviceDownstreamHandler { + + CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO); + + CommonResult getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO); + + CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO); + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java new file mode 100644 index 0000000..b87a2fc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.iot.plugin.common.downstream; + +import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceServiceInvokeVertxHandler; +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 lombok.extern.slf4j.Slf4j; + +/** + * IoT 设备下行服务端,接收来自 server 服务器的请求,转发给 device 设备 + * + * @author 芋道源码 + */ +@Slf4j +public class IotDeviceDownstreamServer { + + private final Vertx vertx; + private final HttpServer server; + + public IotDeviceDownstreamServer(IotDeviceDownstreamHandler deviceDownstreamHandler) { + // 创建 Vertx 实例 + this.vertx = Vertx.vertx(); + // 创建 Router 实例 + Router router = Router.router(vertx); + router.route().handler(BodyHandler.create()); // 处理 Body + router.post(IotDeviceServiceInvokeVertxHandler.PATH).handler( + new IotDeviceServiceInvokeVertxHandler(deviceDownstreamHandler)); // 处理 Service Invoke + // 创建 HttpServer 实例 + this.server = vertx.createHttpServer().requestHandler(router); + } + + /** + * 启动 HTTP 服务器 + */ + public void start() { + log.info("[start][开始启动]"); + server.listen(0) // 通过 0 自动选择端口 + .toCompletionStage() + .toCompletableFuture() + .join(); + log.info("[start][启动完成,端口({})]", this.server.actualPort()); + } + + /** + * 停止所有 + */ + public void stop() { + log.info("[stop][开始关闭]"); + try { + // 关闭 HTTP 服务器 + if (server != null) { + server.close() + .toCompletionStage() + .toCompletableFuture() + .join(); + } + + // 关闭 Vertx 实例 + if (vertx != null) { + vertx.close() + .toCompletionStage() + .toCompletableFuture() + .join(); + } + log.info("[stop][关闭完成]"); + } catch (Exception e) { + log.error("[stop][关闭异常]", e); + throw new RuntimeException(e); + } + } + + /** + * 获得端口 + * + * @return 端口 + */ + public int getPort() { + return this.server.actualPort(); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java new file mode 100644 index 0000000..27e1ff8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.iot.plugin.common.downstream.router; + +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +public class IotDeviceServiceInvokeVertxHandler implements Handler { + + public static final String PATH = "/sys/:productKey/:deviceName/thing/service/:identifier"; + + private final IotDeviceDownstreamHandler deviceDownstreamHandler; + + @Override + public void handle(RoutingContext routingContext) { + // TODO 芋艿:这里没实现 + deviceDownstreamHandler.invokeDeviceService(null); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java new file mode 100644 index 0000000..a42fdae --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/upstream/IotDeviceUpstreamClient.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.plugin.common.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.IotDeviceEventReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.client.RestTemplate; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +/** + * 设备数据 Upstream 上行客户端 + * + * 通过 HTTP 调用远程的 IotDeviceUpstreamApi 接口 + * + * @author haohao + */ +@Slf4j +public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi { + + public static final String URL_PREFIX = "/rpc-api/iot/device/upstream"; + + private final RestTemplate restTemplate; + private final String deviceDataUrl; + + // 可以通过构造器把 RestTemplate 和 baseUrl 注入进来 + // TODO @haohao:可以用 lombok 简化 + public IotDeviceUpstreamClient(RestTemplate restTemplate, String deviceDataUrl) { + this.restTemplate = restTemplate; + this.deviceDataUrl = deviceDataUrl; + } + + // TODO @haohao:返回结果,不用 CommonResult 哈。 + @Override + public CommonResult updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) { + String url = deviceDataUrl + URL_PREFIX + "/update-state"; + return doPost(url, updateReqDTO, "updateDeviceState"); + } + + @Override + public CommonResult reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) { + String url = deviceDataUrl + URL_PREFIX + "/report-event"; + return doPost(url, reportReqDTO, "reportDeviceEventData"); + } + + @Override + public CommonResult reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) { + String url = deviceDataUrl + URL_PREFIX + "/report-property"; + return doPost(url, reportReqDTO, "reportDevicePropertyData"); + } + + // TODO @haohao:未来可能有 get 类型哈 + /** + * 将与远程服务交互的通用逻辑抽取成一个私有方法 + */ + private CommonResult doPost(String url, T requestBody, String actionName) { + log.info("[{}] Sending request to URL: {}", actionName, url); + try { + // 这里指定返回类型为 CommonResult,根据后台服务返回的实际结构做调整 + restTemplate.postForObject(url, requestBody, CommonResult.class); + // TODO @haohao:check 结果,是否成功 + return success(true); + } catch (Exception e) { + log.error("[{}] Error sending request to URL: {}", actionName, url, e); + return CommonResult.error(400, "Request error: " + e.getMessage()); + } + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 65bd7ad..eae9ad8 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1 +1 @@ -cn.iocoder.yudao.module.iot.plugin.common.config.YudaoDeviceDataApiAutoConfiguration \ No newline at end of file +cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonAutoConfiguration \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties index bcdce07..647d551 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/plugin.properties @@ -1,5 +1,5 @@ plugin.id=yudao-module-iot-plugin-http -plugin.class=cn.iocoder.yudao.module.iot.plugin.http.config.HttpVertxPlugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.http.config.IotHttpVertxPlugin plugin.version=1.0.0 plugin.provider=yudao plugin.dependencies= diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml index 0bfa107..b939428 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml @@ -22,7 +22,7 @@ ${project.artifactId} - cn.iocoder.yudao.module.iot.plugin.http.config.HttpVertxPlugin + cn.iocoder.yudao.module.iot.plugin.http.config.IotHttpVertxPlugin ${project.version} yudao ${project.artifactId}-${project.version} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java index bd64c8b..f2dbbde 100644 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.plugin.http; -import cn.iocoder.yudao.module.iot.plugin.http.config.VertxService; +import cn.iocoder.yudao.module.iot.plugin.http.upstream.IotDeviceUpstreamServer; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; @@ -21,8 +21,8 @@ public class HttpPluginSpringbootApplication { // 手动获取 VertxService 并启动 // TODO @haohao:可以放在 bean 的 init 里么?回复:会和插件模式冲突 @芋艿,测试下 - VertxService vertxService = context.getBean(VertxService.class); - vertxService.startServer(); + IotDeviceUpstreamServer vertxService = context.getBean(IotDeviceUpstreamServer.class); + vertxService.start(); log.info("[HttpPluginSpringbootApplication] 独立模式启动完成"); } diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java deleted file mode 100644 index 2c26367..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPlugin.java +++ /dev/null @@ -1,81 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.http.config; - -import cn.hutool.core.lang.Assert; -import cn.hutool.extra.spring.SpringUtil; -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import lombok.extern.slf4j.Slf4j; -import org.pf4j.PluginWrapper; -import org.pf4j.spring.SpringPlugin; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -/** - * 负责插件的启动和停止,与 Vert.x 的生命周期管理 - */ -@Slf4j -public class HttpVertxPlugin extends SpringPlugin { - - public HttpVertxPlugin(PluginWrapper wrapper) { - super(wrapper); - } - - @Override - public void start() { - log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动开始...]"); - try { - // 1. 获取插件上下文 - ApplicationContext pluginContext = getApplicationContext(); - Assert.notNull(pluginContext, "pluginContext 不能为空"); - - // 2. 启动 Vert.x - VertxService vertxService = pluginContext.getBean(VertxService.class); - vertxService.startServer(); - - log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动成功...]"); - } catch (Exception e) { - log.error("[HttpVertxPlugin][HttpVertxPlugin 插件开启动异常...]", e); - } - } - - @Override - public void stop() { - log.info("[HttpVertxPlugin][HttpVertxPlugin 插件停止开始...]"); - try { - // 停止服务器 - ApplicationContext pluginContext = getApplicationContext(); - if (pluginContext != null) { - VertxService vertxService = pluginContext.getBean(VertxService.class); - vertxService.stopServer(); - } - - log.info("[HttpVertxPlugin][HttpVertxPlugin 插件停止成功...]"); - } catch (Exception e) { - log.error("[HttpVertxPlugin][HttpVertxPlugin 插件停止异常...]", e); - } - } - - @Override - protected ApplicationContext createApplicationContext() { - // TODO @haohao:这个加 deviceDataApi 的目的是啥呀? - AnnotationConfigApplicationContext pluginContext = new AnnotationConfigApplicationContext() { - - @Override - protected void prepareRefresh() { - // 在刷新容器前注册主程序中的 Bean - ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); - IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class); - beanFactory.registerSingleton("deviceDataApi", deviceDataApi); - super.prepareRefresh(); - } - - }; - - pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); - // TODO @芋艿:枚举 - pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.http.config"); - pluginContext.refresh(); - return pluginContext; - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java deleted file mode 100644 index 88d3765..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/HttpVertxPluginConfiguration.java +++ /dev/null @@ -1,81 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.http.config; - -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.plugin.http.framework.upstream.HttpVertxHandler; -import io.vertx.core.Vertx; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.handler.BodyHandler; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * 插件与独立运行都可复用的配置类 - */ -@Slf4j -@Configuration -public class HttpVertxPluginConfiguration { - - // TODO @haohao:这个要不要搞个配置类,更容易维护; - /** - * 可在 application.yml 中配置,默认端口 8092 - */ - @Value("${plugin.http.server.port:8092}") - private Integer port; - - /** - * 创建 Vert.x 实例 - */ - @Bean - public Vertx vertx() { - return Vertx.vertx(); - } - - /** - * 创建路由 - * - * @param vertx Vertx 实例 - * @param httpVertxHandler HttpVertxHandler 实例 - * @return Router 实例 - */ - @Bean - public Router router(Vertx vertx, HttpVertxHandler httpVertxHandler) { - Router router = Router.router(vertx); - - // 处理 Body - router.route().handler(BodyHandler.create()); - - // 设置路由 - // TODO @haohao:这个后续,我们是多个 Handler ,还是一个哈? - router.post("/sys/:productKey/:deviceName/thing/event/property/post") - .handler(httpVertxHandler); - - return router; - } - - /** - * 创建 HttpVertxHandler 实例 - * - * @param deviceDataApi DeviceDataApi 实例 - * @return HttpVertxHandler 实例 - */ - @Bean - public HttpVertxHandler httpVertxHandler(IotDeviceUpstreamApi deviceDataApi) { - return new HttpVertxHandler(deviceDataApi); - } - - /** - * 定义一个 VertxService 来管理服务器启动逻辑 - * 无论是独立运行还是插件方式,都可以共用此类 - * - * @param vertx Vertx 实例 - * @param router Router 实例 - * @return VertxService 实例 - */ - @Bean - public VertxService vertxService(Vertx vertx, Router router) { - return new VertxService(port, vertx, router); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java new file mode 100644 index 0000000..0da7241 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotHttpVertxPlugin.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.iot.plugin.http.config; + +import cn.hutool.core.lang.Assert; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.http.upstream.IotDeviceUpstreamServer; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginWrapper; +import org.pf4j.spring.SpringPlugin; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * 负责插件的启动和停止,与 Vert.x 的生命周期管理 + */ +@Slf4j +public class IotHttpVertxPlugin extends SpringPlugin { + + public IotHttpVertxPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动开始...]"); + try { + // 1. 获取插件上下文 + ApplicationContext pluginContext = getApplicationContext(); + Assert.notNull(pluginContext, "pluginContext 不能为空"); + + // 2. 启动 Vert.x + IotDeviceUpstreamServer vertxService = pluginContext.getBean(IotDeviceUpstreamServer.class); + vertxService.start(); + + log.info("[HttpVertxPlugin][HttpVertxPlugin 插件启动成功...]"); + } catch (Exception e) { + log.error("[HttpVertxPlugin][HttpVertxPlugin 插件开启动异常...]", e); + } + } + + @Override + public void stop() { + log.info("[HttpVertxPlugin][HttpVertxPlugin 插件停止开始...]"); + try { + // 停止服务器 + ApplicationContext pluginContext = getApplicationContext(); + if (pluginContext != null) { + IotDeviceUpstreamServer vertxService = pluginContext.getBean(IotDeviceUpstreamServer.class); + vertxService.stopServer(); + } + + log.info("[HttpVertxPlugin][HttpVertxPlugin 插件停止成功...]"); + } catch (Exception e) { + log.error("[HttpVertxPlugin][HttpVertxPlugin 插件停止异常...]", e); + } + } + + @Override + protected ApplicationContext createApplicationContext() { + // TODO @haohao:这个加 deviceDataApi 的目的是啥呀? + AnnotationConfigApplicationContext pluginContext = new AnnotationConfigApplicationContext() { + + @Override + protected void prepareRefresh() { + // 在刷新容器前注册主程序中的 Bean + ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); + IotDeviceUpstreamApi deviceDataApi = SpringUtil.getBean(IotDeviceUpstreamApi.class); + beanFactory.registerSingleton("deviceDataApi", deviceDataApi); + super.prepareRefresh(); + } + + }; + + pluginContext.setClassLoader(getWrapper().getPluginClassLoader()); + // TODO @芋艿:枚举 + pluginContext.scan("cn.iocoder.yudao.module.iot.plugin.http.config"); + pluginContext.refresh(); + return pluginContext; + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java new file mode 100644 index 0000000..3ecc2dc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.iot.plugin.http.config; + +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.http.upstream.IotDeviceUpstreamServer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 插件与独立运行都可复用的配置类 + */ +@Configuration +public class IotPluginHttpAutoConfiguration { + + // TODO @haohao:这个要不要搞个配置类,更容易维护; + /** + * 可在 application.yml 中配置,默认端口 8092 + */ + @Value("${plugin.http.server.port:8092}") + private Integer port; + + @Bean + public IotDeviceUpstreamServer vertxService(IotDeviceUpstreamApi deviceUpstreamApi) { + return new IotDeviceUpstreamServer(port, deviceUpstreamApi); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java deleted file mode 100644 index 5a57be8..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/VertxService.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.http.config; - -import io.vertx.core.Vertx; -import io.vertx.ext.web.Router; -import lombok.extern.slf4j.Slf4j; - -/** - * 封装 Vert.x HTTP 服务的启动/关闭逻辑 - */ -@Slf4j -public class VertxService { - - private final Integer port; - private final Vertx vertx; - private final Router router; - - public VertxService(Integer port, Vertx vertx, Router router) { - this.port = port; - this.vertx = vertx; - this.router = router; - } - - /** - * 启动 HTTP 服务器 - */ - public void startServer() { - vertx.createHttpServer() - .requestHandler(router) - .listen(port, http -> { - if (http.succeeded()) { - log.info("[VertxService] HTTP 服务器启动成功, 端口: {}", port); - } else { - log.error("[VertxService] HTTP 服务器启动失败", http.cause()); - } - }); - } - - /** - * 关闭 HTTP 服务器 - */ - public void stopServer() { - if (vertx != null) { - vertx.close(ar -> { - if (ar.succeeded()) { - log.info("[VertxService] Vert.x 关闭成功"); - } else { - log.error("[VertxService] Vert.x 关闭失败", ar.cause()); - } - }); - } - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java new file mode 100644 index 0000000..91604c6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.plugin.http.downstream; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler; +import org.springframework.stereotype.Component; + +@Component // TODO @芋艿:后续统一处理 +public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler { + + @Override + public CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) { + // TODO @芋艿:待实现 + System.out.println(); + return null; + } + + @Override + public CommonResult getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO) { + // TODO @芋艿:待实现 + System.out.println(); + return null; + } + + @Override + public CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) { + // TODO @芋艿:待实现 + System.out.println(); + return null; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/downstream/IotDeviceDownstreamHandlerImpl.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/downstream/IotDeviceDownstreamHandlerImpl.java deleted file mode 100644 index f01a1cb..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/downstream/IotDeviceDownstreamHandlerImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.http.framework.downstream; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; -import cn.iocoder.yudao.module.iot.plugin.common.core.downstream.IotDeviceDownstreamHandler; -import org.springframework.stereotype.Component; - -@Component // TODO @芋艿:后续统一处理 -public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler { - - @Override - public CommonResult invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) { - // TODO @芋艿:待实现 - System.out.println(); - return null; - } - - @Override - public CommonResult getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO) { - // TODO @芋艿:待实现 - System.out.println(); - return null; - } - - @Override - public CommonResult setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) { - // TODO @芋艿:待实现 - System.out.println(); - return null; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/package-info.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/package-info.java deleted file mode 100644 index 9f84cda..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.http.framework; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/upstream/HttpVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/upstream/HttpVertxHandler.java deleted file mode 100644 index ec5976d..0000000 --- a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/framework/upstream/HttpVertxHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.iocoder.yudao.module.iot.plugin.http.framework.upstream; - -import cn.hutool.core.util.IdUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; -import io.vertx.core.Handler; -import io.vertx.ext.web.RequestBody; -import io.vertx.ext.web.RoutingContext; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; -import java.util.Map; - -@Slf4j -public class HttpVertxHandler implements Handler { - - private final IotDeviceUpstreamApi deviceDataApi; - - public HttpVertxHandler(IotDeviceUpstreamApi deviceDataApi) { - this.deviceDataApi = deviceDataApi; - } - - @Override - public void handle(RoutingContext ctx) { - String productKey = ctx.pathParam("productKey"); - String deviceName = ctx.pathParam("deviceName"); - - // TODO @haohao:requestBody.asJsonObject() 貌似天然就是 json 对象哈? - RequestBody requestBody = ctx.body(); - JSONObject jsonData; - try { - jsonData = JSONUtil.parseObj(requestBody.asJsonObject()); - } catch (Exception e) { - log.error("[HttpVertxHandler] 请求数据解析失败", e); - ctx.response().setStatusCode(400) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(createResponseJson(400, null, null, - "请求数据不是合法的 JSON 格式: " + e.getMessage(), - "thing.event.property.post", "1.0").toString()); - return; - } - - String id = jsonData.getStr("id"); - - try { - // TODO @haohao:pluginKey 需要设置 - // 设备上线 - deviceDataApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) - new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) - .setPluginKey("http") - .setReportTime(LocalDateTime.now()) - .setProductKey(productKey).setDeviceName(deviceName)) - .setState(IotDeviceStateEnum.ONLINE.getState())); - - // 属性上报 - deviceDataApi.reportDeviceProperty(((IotDevicePropertyReportReqDTO) - new IotDevicePropertyReportReqDTO().setRequestId(IdUtil.fastSimpleUUID()) - .setPluginKey("http").setReportTime(LocalDateTime.now()) - .setProductKey(productKey).setDeviceName(deviceName)) - .setProperties((Map) requestBody.asJsonObject().getMap().get("properties"))); - - ctx.response() - .setStatusCode(200) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(createResponseJson(200, new JSONObject(), id, "success", - "thing.event.property.post", "1.0").toString()); - } catch (Exception e) { - log.error("[HttpVertxHandler] 上报属性数据失败", e); - ctx.response() - .setStatusCode(500) - .putHeader("Content-Type", "application/json; charset=UTF-8") - .end(createResponseJson(500, new JSONObject(), id, - "The format of result is error!", - "thing.event.property.post", "1.0").toString()); - } - } - - private JSONObject createResponseJson(int code, JSONObject data, String id, - String message, String method, String version) { - JSONObject res = new JSONObject(); - res.set("code", code); - res.set("data", data != null ? data : new JSONObject()); - res.set("id", id); - res.set("message", message); - res.set("method", method); - res.set("version", version); - return res; - } -} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java new file mode 100644 index 0000000..113c54e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/IotDeviceUpstreamServer.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.iot.plugin.http.upstream; + +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.plugin.http.upstream.router.IotDevicePropertyReportVertxHandler; +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 lombok.extern.slf4j.Slf4j; + +/** + * IoT 设备下行服务端,接收来自 device 设备的请求,转发给 server 服务器 + * + * 协议:HTTP + * + * @author haohao + */ +@Slf4j +public class IotDeviceUpstreamServer { + + private final Vertx vertx; + private final HttpServer server; + private final Integer port; + + public IotDeviceUpstreamServer(Integer port, + IotDeviceUpstreamApi deviceUpstreamApi) { + this.port = port; + // 创建 Vertx 实例 + this.vertx = Vertx.vertx(); + // 创建 Router 实例 + Router router = Router.router(vertx); + router.route().handler(BodyHandler.create()); // 处理 Body + router.post(IotDevicePropertyReportVertxHandler.PATH) + .handler(new IotDevicePropertyReportVertxHandler(deviceUpstreamApi)); // 处理设备属性上报 + // 创建 HttpServer 实例 + this.server = vertx.createHttpServer().requestHandler(router); + } + + /** + * 启动 HTTP 服务器 + */ + public void start() { + log.info("[start][开始启动]"); + server.listen(port) + .toCompletionStage() + .toCompletableFuture() + .join(); + log.info("[start][启动完成,端口({})]", this.server.actualPort()); + } + + /** + * 停止所有 + */ + public void stopServer() { + log.info("[stop][开始关闭]"); + try { + // 关闭 HTTP 服务器 + if (server != null) { + server.close() + .toCompletionStage() + .toCompletableFuture() + .join(); + } + + // 关闭 Vertx 实例 + if (vertx != null) { + vertx.close() + .toCompletionStage() + .toCompletableFuture() + .join(); + } + log.info("[stop][关闭完成]"); + } catch (Exception e) { + log.error("[stop][关闭异常]", e); + throw new RuntimeException(e); + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java new file mode 100644 index 0000000..91700f4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.iot.plugin.http.upstream.router; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; +import io.vertx.core.Handler; +import io.vertx.ext.web.RequestBody; +import io.vertx.ext.web.RoutingContext; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.Map; + +@Slf4j +public class IotDevicePropertyReportVertxHandler implements Handler { + + public static final String PATH = "/sys/:productKey/:deviceName/thing/event/property/post"; + + private final IotDeviceUpstreamApi deviceDataApi; + + public IotDevicePropertyReportVertxHandler(IotDeviceUpstreamApi deviceDataApi) { + this.deviceDataApi = deviceDataApi; + } + + @Override + public void handle(RoutingContext ctx) { + String productKey = ctx.pathParam("productKey"); + String deviceName = ctx.pathParam("deviceName"); + + // TODO @haohao:requestBody.asJsonObject() 貌似天然就是 json 对象哈? + RequestBody requestBody = ctx.body(); + JSONObject jsonData; + try { + jsonData = JSONUtil.parseObj(requestBody.asJsonObject()); + } catch (Exception e) { + log.error("[HttpVertxHandler] 请求数据解析失败", e); + ctx.response().setStatusCode(400) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(createResponseJson(400, null, null, + "请求数据不是合法的 JSON 格式: " + e.getMessage(), + "thing.event.property.post", "1.0").toString()); + return; + } + + String id = jsonData.getStr("id"); + + try { + // TODO @haohao:pluginKey 需要设置 + // 设备上线 + deviceDataApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) + new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) + .setPluginKey("http") + .setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)) + .setState(IotDeviceStateEnum.ONLINE.getState())); + + // 属性上报 + deviceDataApi.reportDeviceProperty(((IotDevicePropertyReportReqDTO) + new IotDevicePropertyReportReqDTO().setRequestId(IdUtil.fastSimpleUUID()) + .setPluginKey("http").setReportTime(LocalDateTime.now()) + .setProductKey(productKey).setDeviceName(deviceName)) + .setProperties((Map) requestBody.asJsonObject().getMap().get("properties"))); + + ctx.response() + .setStatusCode(200) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(createResponseJson(200, new JSONObject(), id, "success", + "thing.event.property.post", "1.0").toString()); + } catch (Exception e) { + log.error("[HttpVertxHandler] 上报属性数据失败", e); + ctx.response() + .setStatusCode(500) + .putHeader("Content-Type", "application/json; charset=UTF-8") + .end(createResponseJson(500, new JSONObject(), id, + "The format of result is error!", + "thing.event.property.post", "1.0").toString()); + } + } + + private JSONObject createResponseJson(int code, JSONObject data, String id, + String message, String method, String version) { + JSONObject res = new JSONObject(); + res.set("code", code); + res.set("data", data != null ? data : new JSONObject()); + res.set("id", id); + res.set("message", message); + res.set("method", method); + res.set("version", version); + return res; + } +} -- libgit2 0.21.4