From 890d304340f1d20c52cf5288d47956eaed5814ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 15 Jan 2025 22:37:07 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=9B=B4=E6=96=B0=20Vert.x=20?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E8=87=B3=204.5.1=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20EMQX=20=E6=8F=92=E4=BB=B6=E5=8F=8A=E5=85=B6=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=85=8D=E7=BD=AE=EF=BC=8C=E9=87=8D=E6=9E=84=20MQTT?= =?UTF-8?q?=20=E6=8F=92=E4=BB=B6=E4=BB=A5=E6=94=AF=E6=8C=81=20Vert.x=20MQT?= =?UTF-8?q?T=20=E6=9C=8D=E5=8A=A1=E5=99=A8=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=90=AF=E5=8A=A8=E5=92=8C=E5=81=9C=E6=AD=A2?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E6=9B=B4=E6=96=B0=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E4=BF=A1=E6=81=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 6 + .../plugin.properties | 6 + .../yudao-module-iot-emqx-plugin/pom.xml | 164 +++++++++++++ .../src/main/assembly/assembly.xml | 31 +++ .../yudao/module/iot/plugin/EmqxPlugin.java | 45 ++++ .../yudao-module-iot-http-plugin/pom.xml | 13 +- .../plugin.properties | 7 +- .../yudao-module-iot-mqtt-plugin/pom.xml | 7 +- .../yudao/module/iot/plugin/MqttPlugin.java | 39 ++- .../iot/plugin/MqttServerExtension.java | 231 ++++++++++++++++++ 10 files changed, 508 insertions(+), 41 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index fb3cf8562d..0a9d0bf454 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -626,6 +626,12 @@ vertx-web ${vertx.version} + + + io.vertx + vertx-mqtt + ${vertx.version} + diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties new file mode 100644 index 0000000000..a23bafcf79 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties @@ -0,0 +1,6 @@ +plugin.id=emqx-plugin +plugin.class=cn.iocoder.yudao.module.iot.plugin.EmqxPlugin +plugin.version=0.0.1 +plugin.provider=ahh +plugin.dependencies= +plugin.description=emqx-plugin-0.0.1 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml new file mode 100644 index 0000000000..43d67f5207 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml @@ -0,0 +1,164 @@ + + + + yudao-module-iot-plugin + cn.iocoder.boot + ${revision} + + 4.0.0 + jar + + yudao-module-iot-emqx-plugin + + ${project.artifactId} + + 物联网 插件模块 - emqx 插件 + + + + + emqx-plugin + cn.iocoder.yudao.module.iot.plugin.EmqxPlugin + 0.0.1 + ahh + emqx-plugin-0.0.1 + + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + + + unzip jar file + package + + + + + + + run + + + + + + + maven-assembly-plugin + 2.3 + + + + src/main/assembly/assembly.xml + + + false + + + + make-assembly + package + + attached + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + ${plugin.description} + ${plugin.dependencies} + + + + + + + maven-deploy-plugin + + true + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.pf4j + pf4j-spring + provided + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + io.vertx + vertx-core + + + + io.vertx + vertx-web + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml new file mode 100644 index 0000000000..daec9e4315 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml @@ -0,0 +1,31 @@ + + plugin + + zip + + false + + + false + runtime + lib + + *:jar:* + + + + + + + target/plugin-classes + classes + + + diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java new file mode 100644 index 0000000000..e64695b06d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; + +import javax.annotation.Resource; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Slf4j +public class EmqxPlugin extends Plugin { + + private ExecutorService executorService; + @Resource + private DeviceDataApi deviceDataApi; + + public EmqxPlugin(PluginWrapper wrapper) { + super(wrapper); + this.executorService = Executors.newSingleThreadExecutor(); + } + + @Override + public void start() { + log.info("EmqxPlugin.start()"); + + if (executorService.isShutdown() || executorService.isTerminated()) { + executorService = Executors.newSingleThreadExecutor(); + } + + deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); + if (deviceDataApi == null) { + log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); + return; + } + + } + + @Override + public void stop() { + log.info("EmqxPlugin.stop()"); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 29c0200f1c..22cb439681 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -147,20 +147,11 @@ ${lombok.version} provided - - - io.vertx - vertx-core - - + io.vertx vertx-web - - - - org.eclipse.paho - org.eclipse.paho.client.mqttv3 + 4.5.11 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties index 31050c5bac..939e0f6929 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/plugin.properties @@ -1,6 +1,7 @@ plugin.id=mqtt-plugin +plugin.description=Vert.x MQTT plugin plugin.class=cn.iocoder.yudao.module.iot.plugin.MqttPlugin -plugin.version=0.0.1 +plugin.version=1.0.0 +plugin.requires= plugin.provider=ahh -plugin.dependencies= -plugin.description=mqtt-plugin-0.0.1 +plugin.license=Apache-2.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml index 9607e0f93c..462fbd0901 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/pom.xml @@ -145,10 +145,11 @@ ${lombok.version} provided - + - org.eclipse.paho - org.eclipse.paho.client.mqttv3 + io.vertx + vertx-mqtt + 4.5.11 \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java index b3749e4025..54ff31f36b 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttPlugin.java @@ -1,45 +1,36 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.ServiceRegistry; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import lombok.extern.slf4j.Slf4j; import org.pf4j.Plugin; import org.pf4j.PluginWrapper; -import javax.annotation.Resource; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - @Slf4j public class MqttPlugin extends Plugin { - private ExecutorService executorService; - @Resource - private DeviceDataApi deviceDataApi; + private MqttServerExtension mqttServerExtension; public MqttPlugin(PluginWrapper wrapper) { super(wrapper); - this.executorService = Executors.newSingleThreadExecutor(); } @Override public void start() { - log.info("MqttPlugin.start()"); - - if (executorService.isShutdown() || executorService.isTerminated()) { - executorService = Executors.newSingleThreadExecutor(); - } - - deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); - if (deviceDataApi == null) { - log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); - return; - } - + log.info("MQTT Plugin started."); + mqttServerExtension = new MqttServerExtension(); + mqttServerExtension.startMqttServer(); } @Override public void stop() { - log.info("MqttPlugin.stop()"); + log.info("MQTT Plugin stopped."); + if (mqttServerExtension != null) { + mqttServerExtension.stopMqttServer().onComplete(ar -> { + if (ar.succeeded()) { + log.info("Stopped MQTT Server successfully"); + } else { + log.error("Failed to stop MQTT Server: {}", ar.cause().getMessage()); + } + }); + } } -} \ No newline at end of file +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java new file mode 100644 index 0000000000..868d238ee9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-mqtt-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/MqttServerExtension.java @@ -0,0 +1,231 @@ +package cn.iocoder.yudao.module.iot.plugin; + +import io.netty.handler.codec.mqtt.MqttProperties; +import io.netty.handler.codec.mqtt.MqttQoS; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.mqtt.MqttEndpoint; +import io.vertx.mqtt.MqttServer; +import io.vertx.mqtt.MqttServerOptions; +import io.vertx.mqtt.MqttTopicSubscription; +import io.vertx.mqtt.messages.MqttDisconnectMessage; +import io.vertx.mqtt.messages.MqttPublishMessage; +import io.vertx.mqtt.messages.MqttSubscribeMessage; +import io.vertx.mqtt.messages.MqttUnsubscribeMessage; +import io.vertx.mqtt.messages.codes.MqttSubAckReasonCode; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.Extension; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * 根据官方示例,整合常见 MQTT 功能到 PF4J 的 Extension 类中 + */ +@Slf4j +@Extension +public class MqttServerExtension { + + private Vertx vertx; + private MqttServer mqttServer; + + /** + * 启动 MQTT 服务端 + * 可根据需要决定是否启用 SSL/TLS、WebSocket、多实例部署等 + */ + public void startMqttServer() { + // 初始化 Vert.x + vertx = Vertx.vertx(); + + // ========== 如果需要 SSL/TLS,请参考下面注释,启用注释并替换端口、证书路径等 ========== + // MqttServerOptions options = new MqttServerOptions() + // .setPort(8883) + // .setKeyCertOptions(new PemKeyCertOptions() + // .setKeyPath("./src/test/resources/tls/server-key.pem") + // .setCertPath("./src/test/resources/tls/server-cert.pem")) + // .setSsl(true); + + // ========== 如果需要 WebSocket,请设置 setUseWebSocket(true) ========== + // options.setUseWebSocket(true); + + // ========== 默认不启用 SSL 的示例 ========== + MqttServerOptions options = new MqttServerOptions() + .setPort(1883) + .setHost("0.0.0.0") + .setUseWebSocket(false); // 如果需要 WebSocket,请改为 true + + mqttServer = MqttServer.create(vertx, options); + + // 指定 endpointHandler,处理客户端连接等 + mqttServer.endpointHandler(endpoint -> { + handleClientConnect(endpoint); + handleDisconnect(endpoint); + handleSubscribe(endpoint); + handleUnsubscribe(endpoint); + handlePublish(endpoint); + handlePing(endpoint); + }); + + // 启动监听 + mqttServer.listen(ar -> { + if (ar.succeeded()) { + log.info("MQTT server is listening on port {}", mqttServer.actualPort()); + } else { + log.error("Error on starting the server", ar.cause()); + } + }); + } + + /** + * 优雅关闭 MQTT 服务端 + */ + public Future stopMqttServer() { + if (mqttServer != null) { + return mqttServer.close().onComplete(ar -> { + if (ar.succeeded()) { + log.info("MQTT server closed."); + if (vertx != null) { + vertx.close(); + log.info("Vert.x instance closed."); + } + } else { + log.error("Failed to close MQTT server: {}", ar.cause().getMessage()); + } + }); + } + return Future.succeededFuture(); + } + + // ==================== 以下为官方示例中常见事件的处理封装 ==================== + + /** + * 处理客户端连接 (CONNECT) + */ + private void handleClientConnect(MqttEndpoint endpoint) { + // 打印 CONNECT 的主要信息 + log.info("MQTT client [{}] request to connect, clean session = {}", + endpoint.clientIdentifier(), endpoint.isCleanSession()); + + if (endpoint.auth() != null) { + log.info("[username = {}, password = {}]", endpoint.auth().getUsername(), endpoint.auth().getPassword()); + } + log.info("[properties = {}]", endpoint.connectProperties()); + + if (endpoint.will() != null) { + log.info("[will topic = {}, msg = {}, QoS = {}, isRetain = {}]", + endpoint.will().getWillTopic(), + new String(endpoint.will().getWillMessageBytes()), + endpoint.will().getWillQos(), + endpoint.will().isWillRetain()); + } + + log.info("[keep alive timeout = {}]", endpoint.keepAliveTimeSeconds()); + + // 接受远程客户端的连接 + endpoint.accept(false); + } + + /** + * 处理客户端主动断开 (DISCONNECT) + */ + private void handleDisconnect(MqttEndpoint endpoint) { + endpoint.disconnectMessageHandler((MqttDisconnectMessage disconnectMessage) -> { + log.info("Received disconnect from client [{}], reason code = {}", + endpoint.clientIdentifier(), disconnectMessage.code()); + }); + } + + /** + * 处理客户端订阅 (SUBSCRIBE) + */ + private void handleSubscribe(MqttEndpoint endpoint) { + endpoint.subscribeHandler((MqttSubscribeMessage subscribe) -> { + List reasonCodes = new ArrayList<>(); + for (MqttTopicSubscription s : subscribe.topicSubscriptions()) { + log.info("Subscription for {} with QoS {}", s.topicName(), s.qualityOfService()); + // 将客户端请求的 QoS 转换为返回给客户端的 reason code(可能是错误码或实际 granted QoS) + reasonCodes.add(MqttSubAckReasonCode.qosGranted(s.qualityOfService())); + } + // 回复 SUBACK,MQTT 5.0 时可指定 reasonCodes、properties + endpoint.subscribeAcknowledge(subscribe.messageId(), reasonCodes, MqttProperties.NO_PROPERTIES); + }); + } + + /** + * 处理客户端取消订阅 (UNSUBSCRIBE) + */ + private void handleUnsubscribe(MqttEndpoint endpoint) { + endpoint.unsubscribeHandler((MqttUnsubscribeMessage unsubscribe) -> { + for (String topic : unsubscribe.topics()) { + log.info("Unsubscription for {}", topic); + } + // 回复 UNSUBACK,MQTT 5.0 时可指定 reasonCodes、properties + endpoint.unsubscribeAcknowledge(unsubscribe.messageId()); + }); + } + + /** + * 处理客户端发布的消息 (PUBLISH) + */ + private void handlePublish(MqttEndpoint endpoint) { + // 接收 PUBLISH 消息 + endpoint.publishHandler((MqttPublishMessage message) -> { + String payload = message.payload().toString(Charset.defaultCharset()); + log.info("Received message [{}] on topic [{}] with QoS [{}]", + payload, message.topicName(), message.qosLevel()); + + // 根据不同 QoS,回复客户端 + if (message.qosLevel() == MqttQoS.AT_LEAST_ONCE) { + endpoint.publishAcknowledge(message.messageId()); + } else if (message.qosLevel() == MqttQoS.EXACTLY_ONCE) { + endpoint.publishReceived(message.messageId()); + } + }); + + // 如果 QoS = 2,需要处理 PUBREL + endpoint.publishReleaseHandler(messageId -> { + endpoint.publishComplete(messageId); + }); + } + + /** + * 处理客户端 PINGREQ + */ + private void handlePing(MqttEndpoint endpoint) { + endpoint.pingHandler(v -> { + // 这里仅做日志, PINGRESP 已自动发送 + log.info("Ping received from client [{}]", endpoint.clientIdentifier()); + }); + } + + // ==================== 如果需要服务端向客户端发布消息,可用以下示例 ==================== + + /** + * 服务端主动向已连接的某个 endpoint 发布消息的示例 + * 如果使用 MQTT 5.0,可以传递更多消息属性 + */ + public void publishToClient(MqttEndpoint endpoint, String topic, String content) { + endpoint.publish(topic, + Buffer.buffer(content), + MqttQoS.AT_LEAST_ONCE, // QoS 自行选择 + false, + false); + + // 处理 QoS 1 和 QoS 2 的 ACK + endpoint.publishAcknowledgeHandler(messageId -> { + log.info("Received PUBACK from client [{}] for messageId = {}", endpoint.clientIdentifier(), messageId); + }).publishReceivedHandler(messageId -> { + endpoint.publishRelease(messageId); + }).publishCompletionHandler(messageId -> { + log.info("Received PUBCOMP from client [{}] for messageId = {}", endpoint.clientIdentifier(), messageId); + }); + } + + // ==================== 如果需要多实例部署,用于多核扩展,可参考以下思路 ==================== + // 例如,在宿主应用或插件中循环启动多个 MqttServerExtension 实例,或使用 Vert.x 的 deployVerticle: + // DeploymentOptions options = new DeploymentOptions().setInstances(10); + // vertx.deployVerticle(() -> new MyMqttVerticle(), options); + +} From 552432455415142c5b57f403b52bba7eacc008e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 19 Jan 2025 09:53:57 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E5=88=A0=E9=99=A4=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=20MQTT=20RPC=20=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=92=8C=E5=AE=9E=E7=8E=B0=EF=BC=8C=E5=8C=85?= =?UTF-8?q?=E6=8B=AC=20MqttConfig=E3=80=81RpcServer=E3=80=81RpcClient=20?= =?UTF-8?q?=E5=92=8C=20RpcController=20=E7=B1=BB=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=E4=BB=A5=E6=B8=85?= =?UTF-8?q?=E7=90=86=E6=9C=AA=E4=BD=BF=E7=94=A8=E7=9A=84=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/mqttrpc/config/MqttConfig.java | 40 ------- .../module/iot/mqttrpc/server/RpcServer.java | 100 ------------------ .../module/iot/controller/RpcController.java | 38 ------- .../module/iot/mqttrpc/client/RpcClient.java | 93 ---------------- .../module/iot/mqttrpc/config/MqttConfig.java | 41 ------- 5 files changed, 312 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java delete mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java deleted file mode 100644 index c7a0500030..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "mqtt") -public class MqttConfig { - /** - * MQTT 代理地址 - */ - private String broker; - - /** - * MQTT 用户名 - */ - private String username; - - /** - * MQTT 密码 - */ - private String password; - - /** - * MQTT 客户端 ID - */ - private String clientId; - - /** - * MQTT 请求主题 - */ - private String requestTopic; - - /** - * MQTT 响应主题前缀 - */ - private String responseTopicPrefix; -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java deleted file mode 100644 index 90ce2a3875..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java +++ /dev/null @@ -1,100 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.server; - -import cn.hutool.core.lang.UUID; -import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; -import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; -import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; -import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.*; -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import java.util.HashMap; -import java.util.Map; - -// TODO @芋艿:server 逻辑,再瞅瞅; -// TODO @haohao:如果只写在 iot biz 里,那么后续 server => client 貌似不方便?微信再讨论下~; -@Service -@Slf4j -public class RpcServer { - - private final MqttConfig mqttConfig; - private final MqttClient mqttClient; - private final Map methodRegistry = new HashMap<>(); - - public RpcServer(MqttConfig mqttConfig) throws MqttException { - this.mqttConfig = mqttConfig; - this.mqttClient = new MqttClient(mqttConfig.getBroker(), "rpc-server-" + UUID.randomUUID(), new MemoryPersistence()); - MqttConnectOptions options = new MqttConnectOptions(); - options.setAutomaticReconnect(true); - options.setCleanSession(true); - options.setUserName(mqttConfig.getUsername()); - options.setPassword(mqttConfig.getPassword().toCharArray()); - this.mqttClient.connect(options); - } - - @PostConstruct - public void init() throws MqttException { - mqttClient.subscribe(mqttConfig.getRequestTopic(), this::handleRequest); - log.info("RPC Server subscribed to topic: {}", mqttConfig.getRequestTopic()); - } - - private void handleRequest(String topic, MqttMessage message) { - RpcRequest request = SerializationUtils.deserialize(new String(message.getPayload()), RpcRequest.class); - RpcResponse response = new RpcResponse(); - response.setCorrelationId(request.getCorrelationId()); - - try { - MethodInvoker invoker = methodRegistry.get(request.getMethod()); - if (invoker == null) { - throw new NoSuchMethodException("Unknown method: " + request.getMethod()); - } - Object result = invoker.invoke(request.getParams()); - response.setResult(result); - } catch (Exception e) { - response.setError(e.getMessage()); - log.error("Error processing RPC request: {}", e.getMessage(), e); - } - - String replyPayload = SerializationUtils.serialize(response); - MqttMessage replyMessage = new MqttMessage(replyPayload.getBytes()); - replyMessage.setQos(1); - try { - mqttClient.publish(request.getReplyTo(), replyMessage); - log.info("Published response to {}", request.getReplyTo()); - } catch (MqttException e) { - log.error("Failed to publish response: {}", e.getMessage(), e); - } - } - - /** - * 注册可调用的方法 - * - * @param methodName 方法名称 - * @param invoker 方法调用器 - */ - public void registerMethod(String methodName, MethodInvoker invoker) { - methodRegistry.put(methodName, invoker); - log.info("Registered method: {}", methodName); - } - - @PreDestroy - public void cleanup() throws MqttException { - mqttClient.disconnect(); - log.info("RPC Server disconnected"); - } - - /** - * 方法调用器接口 - */ - @FunctionalInterface - public interface MethodInvoker { - - Object invoke(Object[] params) throws Exception; - - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java deleted file mode 100644 index 4615dcf96f..0000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java +++ /dev/null @@ -1,38 +0,0 @@ - -package cn.iocoder.yudao.module.iot.controller; - -import cn.iocoder.yudao.module.iot.mqttrpc.client.RpcClient; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import java.util.concurrent.CompletableFuture; - -// TODO 芋艿:后续 review 下 -/** - * 插件实例 RPC 接口 - * - * @author 芋道源码 - */ -@RestController -@RequestMapping("/rpc") -@RequiredArgsConstructor -public class RpcController { - - @Resource - private RpcClient rpcClient; - - @PostMapping("/add") - public CompletableFuture add(@RequestParam int a, @RequestParam int b) throws Exception { - return rpcClient.call("add", new Object[]{a, b}, 10); - } - - @PostMapping("/concat") - public CompletableFuture concat(@RequestParam String str1, @RequestParam String str2) throws Exception { - return rpcClient.call("concat", new Object[]{str1, str2}, 10); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java deleted file mode 100644 index b73f88c537..0000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/client/RpcClient.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.client; - -import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest; -import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse; -import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils; -import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.client.mqttv3.MqttClient; -import org.eclipse.paho.client.mqttv3.MqttConnectOptions; -import org.eclipse.paho.client.mqttv3.MqttException; -import org.eclipse.paho.client.mqttv3.MqttMessage; -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import java.util.UUID; -import java.util.concurrent.*; - -// TODO @芋艿:需要考虑,怎么公用! -@Service -@Slf4j -public class RpcClient { - - private final MqttConfig mqttConfig; - private final MqttClient mqttClient; - private final ConcurrentMap> pendingRequests = new ConcurrentHashMap<>(); - private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - public RpcClient(MqttConfig mqttConfig) throws MqttException { - this.mqttConfig = mqttConfig; - this.mqttClient = new MqttClient(mqttConfig.getBroker(), mqttConfig.getClientId(), new MemoryPersistence()); - MqttConnectOptions options = new MqttConnectOptions(); - options.setAutomaticReconnect(true); - options.setCleanSession(true); - options.setUserName(mqttConfig.getUsername()); - options.setPassword(mqttConfig.getPassword().toCharArray()); - this.mqttClient.connect(options); - } - - @PostConstruct - public void init() throws MqttException { - mqttClient.subscribe(mqttConfig.getResponseTopicPrefix() + "#", this::handleResponse); - log.info("RPC Client subscribed to topics: {}", mqttConfig.getResponseTopicPrefix() + "#"); - } - - private void handleResponse(String topic, MqttMessage message) { - String correlationId = topic.substring(mqttConfig.getResponseTopicPrefix().length()); - RpcResponse response = SerializationUtils.deserialize(new String(message.getPayload()), RpcResponse.class); - CompletableFuture future = pendingRequests.remove(correlationId); - if (future != null) { - if (response.getError() != null) { - future.completeExceptionally(new RuntimeException(response.getError())); - } else { - future.complete(response); - } - } else { - log.warn("Received response for unknown correlationId: {}", correlationId); - } - } - - public CompletableFuture call(String method, Object[] params, int timeoutSeconds) throws MqttException { - String correlationId = UUID.randomUUID().toString(); - String replyTo = mqttConfig.getResponseTopicPrefix() + correlationId; - - RpcRequest request = new RpcRequest(method, params, correlationId, replyTo); - String payload = SerializationUtils.serialize(request); - MqttMessage message = new MqttMessage(payload.getBytes()); - message.setQos(1); - mqttClient.publish(mqttConfig.getRequestTopic(), message); - - CompletableFuture futureResponse = new CompletableFuture<>(); - pendingRequests.put(correlationId, futureResponse); - - // 设置超时 - scheduler.schedule(() -> { - CompletableFuture removed = pendingRequests.remove(correlationId); - if (removed != null) { - removed.completeExceptionally(new TimeoutException("RPC call timed out")); - } - }, timeoutSeconds, TimeUnit.SECONDS); - - // 返回最终的结果 - return futureResponse.thenApply(RpcResponse::getResult); - } - - @PreDestroy - public void cleanup() throws MqttException { - mqttClient.disconnect(); - scheduler.shutdown(); - log.info("RPC Client disconnected"); - } -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java deleted file mode 100644 index 89569b0c3d..0000000000 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "mqtt") -public class MqttConfig { - - /** - * MQTT 代理地址 - */ - private String broker; - - /** - * MQTT 用户名 - */ - private String username; - - /** - * MQTT 密码 - */ - private String password; - - /** - * MQTT 客户端 ID - */ - private String clientId; - - /** - * MQTT 请求主题 - */ - private String requestTopic; - - /** - * MQTT 响应主题前缀 - */ - private String responseTopicPrefix; -} From a85890d958417e90564fe4ab075fdf6216cd1c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 20 Jan 2025 17:03:27 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E3=80=91IoT:=20=E6=B7=BB=E5=8A=A0=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E9=85=8D=E7=BD=AE=EF=BC=8C=E9=87=8D=E6=9E=84?= =?UTF-8?q?=20SpringPluginManager=20=E5=AE=9E=E4=BE=8B=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91=EF=BC=8C=E5=88=A0=E9=99=A4=E4=B8=8D=E5=86=8D=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=9A=84=20ExampleService=20=E7=B1=BB=E4=BB=A5?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/UnifiedConfiguration.java | 6 ++- .../iot/service/plugin/ExampleService.java | 43 ------------------- 2 files changed, 5 insertions(+), 44 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index 374e3856a1..e02ec9be05 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -5,11 +5,13 @@ import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.framework.plugin.listener.CustomPluginStateListener; import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import javax.annotation.Resource; +import java.nio.file.Paths; @Slf4j @Configuration @@ -19,6 +21,8 @@ public class UnifiedConfiguration { @Resource private DeviceDataApi deviceDataApi; + @Value("${pf4j.pluginsDir:pluginsDir}") + private String pluginsDir; @Bean(SERVICE_REGISTRY_INITIALIZED_MARKER) public Object serviceRegistryInitializedMarker() { @@ -31,7 +35,7 @@ public class UnifiedConfiguration { @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) public SpringPluginManager pluginManager() { log.info("[init][实例化 SpringPluginManager]"); - SpringPluginManager springPluginManager = new SpringPluginManager() { + SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { @Override public void startPlugins() { // 禁用插件启动,避免插件启动时,启动所有插件 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java deleted file mode 100644 index 22ebe8b4f2..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/ExampleService.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.plugin; - -import cn.iocoder.yudao.module.iot.mqttrpc.server.RpcServer; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; - -@Service -@RequiredArgsConstructor -public class ExampleService { - - private final RpcServer rpcServer; - - @PostConstruct - public void registerMethods() { - rpcServer.registerMethod("add", params -> { - if (params.length != 2) { - throw new IllegalArgumentException("add方法需要两个参数"); - } - int a = ((Number) params[0]).intValue(); - int b = ((Number) params[1]).intValue(); - return add(a, b); - }); - - rpcServer.registerMethod("concat", params -> { - if (params.length != 2) { - throw new IllegalArgumentException("concat方法需要两个参数"); - } - String str1 = params[0].toString(); - String str2 = params[1].toString(); - return concat(str1, str2); - }); - } - - private int add(int a, int b) { - return a + b; - } - - private String concat(String a, String b) { - return a + b; - } -} \ No newline at end of file From 3647fd36860035eda823fa8207b5bc6a312037b3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 20 Jan 2025 19:28:03 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IoT=EF=BC=9A=E7=A7=BB=E9=99=A4=20ServiceRegis?= =?UTF-8?q?try=EF=BC=8C=E4=BD=BF=E7=94=A8=20SpringUtils=20=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 15105 -> 8535 bytes .../yudao/module/iot/api/ServiceRegistry.java | 37 ----------------- .../module/iot/mqttrpc/common/RpcRequest.java | 39 ------------------ .../iot/mqttrpc/common/RpcResponse.java | 33 --------------- .../mqttrpc/common/SerializationUtils.java | 19 --------- .../iot/framework/plugin/PluginStart.java | 20 ++++----- .../plugin/UnifiedConfiguration.java | 21 +++------- .../listener/CustomPluginStateListener.java | 1 + .../module/iot/plugin/HttpVertxPlugin.java | 8 ++-- 9 files changed, 19 insertions(+), 159 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/ServiceRegistry.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar index fa75769049a1e0036436209788e16c216edd4891..8b5e72b4a4a93219518d66cbf05cc05a5e486a5e 100644 GIT binary patch delta 4241 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 delta 10401 zcma*N1z1$y7B)@|-QC^Y-KlhUICOVOjdX_$-CYXO(%oIsD2#w0Qj!A72Y7$p>;2#7 z|9xkkIs43d-nI7GYu7t_ttIJTZ!~o!SU6;;$19?R;WZj9T6hbCA!W6G@Z^K&`D<}9 zkcu-b6>9j^v-Mz<7b>fAsVj8*Mb)@=x+^rUu{tnO`5NxG$(doz$$Fm}^78|=^TfFb zUiPIhU28bL*mO*9EG3%f$Rjni$Hxe6kdfAz8Tsjj+g{Nq=cdi$cZzDX?B4utd#s4r zMaQ;@n?_>7$LI_O)-g{o+xRCn2Zrj7r~&d}a0og)j`14}=&4@qNHqK?C5DbvY@@gC z1`O@}Eb`~@o%D|KAlJocbAy^%C*2xx_ZGmO)A4Tp>W`E@Wj0lj{#Dgmqa*s9pHTm9 z?L#xc?9k+}kEI$k{Zr`+&H7Z9L-W8scmuovE$~zlz=+~J`N#0dQUAIzB;!!fTevuT zy1O_!TDf!lW&1BA?E{j=$<5Q#-PPhhU=LON1!H-DG5-U5Fl=pS^M65;{y{t1SvhsC|B3X2WJ>BXo%m`;N!L2t4gF7 z(D1Y*`jjd3{3`a!i0Ck+YZ>2@%N*=jIZTh4+gXCMXLwZ#nJ^1Df|CfbrRQ3nzsg8A ztfDqp7*rP?b_YfmvJWWHcl8C92MkRaCmHS&#$w1V$KoC6dmp4o#J(aGJGjbW0d< zM0~@njzt#s782V;YV}dAj@Lq3#_nLEIt#EcZn!Q=>W3M>a4TJ-h_7}7nL|=9$&RY` zYv7=#cXgZn+GMXCOS?b%Y3)4gdWWn$*&S-4Tv-Ef8P_jGE6F3Bi!_Ju=KL3lS;8lw zL(p{bemBUEH*h!S9-0nxvs!xkPBjR0wea(x_=??(_xE)^veV=;6*st2Fe^QaMK;5;OT#1dP@atILo zqT(X|fYK;S0uJMG6XYou(ewwIp8Uu~i;D&=L%ubsGPLf3daiU^upm{}2! z4cH5$1tnx+!`QeD>rxBLILY8EIU?)C@3)1tFvMaJ))@D3{bzKu%<-)ZmsffbQbA?P zX@{B!Es*nBIxXK263+uRuwpn*#enh}mh&2WG1~O}1uhEe8x)i2NT3oTm+0v|Zss?) zj^$vJqJ=|iU*;2A0s3XO?^ggKvb~ZJFj4{(ww}VZ`+i*9VX=voVi=?WLEG{{rO zi#1OttFRBkG2D8nY&`&$pfm&og95eBF-8QV2$-t5du=LmdwrM_FE{Cky2BJ9!gz4b zh}}(M)NKer#i7jb^*BI?I43D)!eJ_w9EC}Ft@G-UmmeYV;1=c$-5xi*#<9SRgs-+`z}QPE0R+E^ zpdBG+*I0JzFm1(EA0JPyT7Ex1qvsPEXyr!NrGynEML%_!p%-q$ctN4ZF&O8rZCY^SOzt_9T=)D+-=CX6eDtYusJ@Dhy4ub_55bSxzVo`u zY`T_KBD>tmuAx?ot5S04V2R6@Kk~v6VfT>tvu=jVJX}x5oj+}dLdyG$G8vBd#N)2- zS(MxcV-rv6!n((<;rc}wjGl{tlL{JgvYsk8gSA>Dk*WLZw>GP&IdElGILN{E;Fl$s$q1n53;Y8Xm zpPjNMfr4M0^M*yvS+u+9V5Il<(4KV-YgW+Ge!8Q@zr#6mv2g2WWBnz-Jg_^5n??XE zp^8p@Uzf$N%TNdkBi6d+lEGFhJyFKG+zLHZu|gfBcaX@Uc-3|4v#m=aj9*&o}z}8Yed-WC9&y0 z7h4Ai;KkT8BS9dv1Hr5VS){V@wKpu^O|jpVovcAfXX*@IE#l0;fBz!?cBqVWrbuzD zTM6uJ__a?N%1T@fySp37jyYO!gDo?o!dv2$Zy3tgOrcFH?GBMA(Ugx5z^Hq4G*DAb>?Bju$ z&JL2eay*flc^3F(V&%t=gEb5&U+7H2FiJ;BT4;?u%34b#dytY6eyh@_TRD0=1N^|q zVl53NJ~-ll*-!*|n&1I9Tb`~)$Q!dLGJcPvU>d793h$rOw-RrhEytp|&s-C#N+ zzlCW;Mq_XAW3-k+l3uaHw&BdccEa5d9~cz+GGPL9IETNiA;7_FtyCJ%Cn%F9&$#qV z!lCwTO1O6_GJt}k21z4(RKJqSNVPUIT3vdiTiN_VJWV}>12hIKp~2LQyAN)~WTJmM zNj-LF?ZFIAc!ARIXyGaXO~V;eqhqvej}{BgTBYO6xeBiz4_LZ%6unbKtjwq{Jwc4K zt>GE_s+#pB@7yHT263XSen~I%WsQXu;`z2?@B6#@(GAf1Ug6;D1D;qt-csl*q;rAf zns=LM&h8hg_&yoqW5#X-J6I9@1I|p#biFXdFdS=`O{>Nq`Ec8Ez|PTrshh~?FwI)~ zCArC`a6bvA%+)Gl4BY z1h$lplb{KJBb@GPMRhsxFwY^`ho!l_5X8Yxr1U35aa*y^Fi)vuJ3ZZVhh!IIz0orl2XX7kb{mBi2j7QdbJ5{ScfSp z>l;QBP6MZvRZk+I{5fL<0n*DVDsQHTNai7IdLaVWSZ38#X7$XWRp$eDsI;}wn+!)? zuEbh(y}D)TLGU8;iB})&XJLV&VukYVo|9pv6xdqrhIBp|Lr}hb9<3ou)bv;5X%Ot= z%s_hl6Y-mOe#hR0e&U@!<)SNI0-&IXA9$z8;~e=zSAUaRl?O`vFi{?O?(a#`q_^RL zqk}6Uuwf~%UxviSX2N0ylibJ@OIg9BQ}|uuxl$Ax<4W9EgD_%!? z7;9eri`m|t8=HH$erI`@s&C4c933{+XVPbkPZCB9yuPs=aS~R0-fvd9Dmz#t{2GWt z7J}%lviq&)plb9n0^!>yYx`O z@1wC#0WQ9=JbeU zQ?ZCG_U4mW=LFCj)NrzHabLI1m>u1JiQZ>}9R=+g4>n%Aw;SwCWobAS*nG8L!?p%< z7+$F?$u1d;*Mq{Tlmi0VUZS-dG`&BMU56x4`I5EHIqQv$bCu$;-0%0%cmzeqsXoK;TiyTci&(Tlc(dE30X8rv|HbgIdt4}j*VKZBnAaQ*s2Up5Tpf!E8C`*y+u)s zT*dMAo9aBM+IE)Nju64^BC{-H65mSMU{96677?s%L-pjNqstM7e0F%1?w@} zmkulp=3P(SLJy_6ub|-8Ci>>@#fZ3UEx6i%eMBlVN zcA*dksuunfH}s!1Z(%40L0{6469#O~CTm4tgr0#6I6{is9!AlKgzSq}#J7Yf0AjpWa; zs7eIEcAH(3I&SzELgh^>gD{@k`S1FucZF}yTu!(Yu%?z#^dIC!N5YQN8IR3<;~`uu zDX%@is%XeMCq$1VQWzh_u4ZC;E>v00d4pJQsHt>8tCGHhT^&QOm5fb0nl%UJHBwEt zowT)69D{pq$2Jf4><~3B()kd<^c*euWC0BFtj}Sa6)v)3vZH-AW={i5Zaj>S|2PyF z=KvV8+7XHyDd>2GM1*}^TuZ>YPceW0l~B=5h&o)>j2c#Gf09}VT+(|<$;A?A4$?KhY6^};_EGnncvJJ&SjAxJB+d{k_REix?)SKV*vQ;F?&Y&9;m(v$79}+Y**1f6 z&ZS3H8Hpki(zQ$(KOmL%&5YK63*T0Kb}6k@hh~FQ&^53hb#KmynhhVj7 z3GfyuUiwTIFH?Vjd{$Dy^GxON#Jl14C$wY&d|Sq{I+T{Vxyg0`V+f5shZp_nzUu&Z zv4q9$nfYtxgx5Gj7V!K4_%Sq!3q94j%n;2C; z(r}~gEFePkBOZCmTaE3R0=lMWk#_O`ew`*=8-fg?Jkv5I!+t+~{@N`R9ad?{f@RhC zdN^r<+9_CAw-?aChfYGk{RH$TkPSUQqdvR3lOZhCbID;Rq8NuzYhuql zfsPfDnD|E!Yrio1$py@GWfr@zlG@aXa`FfD zKu|_*lhmNRqoN24UQbi&yJzUD)U{mcr)5C(81gugHoN5@M{6wsi}o0@7UdURY`OHv zr5U?>TdG8t@+i34WYyvmuq4{N-+Q>Tx6-m^>726D%=Nx$)`=X(I2##8;DbfWpUd$W zR(!g=!BCfo9t&X}*AMPwzARnZpK-ixu>;B7Ehp*%^s0RESEoLcx-iFkPozmr+Sju> zh2hm4IRUp2v`J+n8ALlXB!N0EC@4k|s(2=Xv;~%q8@j1DCtsj5=k97_Xx{#Snd{J6 zb@QXa$aE812aX2)lm(pHB*ql);pr33N6=~|?vl>tO8M23O}@x71fyl_o8T3UXoK9) z@>tY~X*g_QljD{m=~f8djIqs^*V2z>_MhuEcW!_ecj4t?B|;LOhywfU4-!Mc@W@jGcekEs-_as3T#w4iH2|1av%4%d!i$Nqm&#e!?RURMu)SO*?7RJLL0m*6Dp$di`?JkXR zU^7R!i2_uZ4ZqlUN1h=$!7Z`0NDZF37E7w2yJdvLwDeD=y{@Q~>o{?-UJ>Am-1r6` zz~eH=QE)vKpJ2f?zd7=3xQ>FOj}6)MEriauvS-Ss7Wq)A4gbTtB|*J5I|2|*iX!!# zsu%eCn$2)4onofHDRxN`NAI}Xn-IMUUpi+TeW5FOwO@5nr;$4;vP$jle(524lg8Zx z5RHA?K#f+8Em~HXeOl9ENRu**xci9dI5!*M9gev_hyKQ*h#<;iF7_1+-r zKH+eIiWU@?5=12bShcwMA`OsvvmCgoETms_3PMtq_23A+%u6K>XDT;gmtY<*I?u zOrVk)P0}PZW^y@0#)q{<;}W$z=f!>dJiOR_#{=8NLx5FXz! z?{42Bj;b|TLluIa6)?zmgzpUZyAT(J)~TSlf+(Sypq8-^+5611cQ8M$Lt;1}N{uP0 zoNzU*JsVD!BZZB;>)OmidM7#nGp$pv0GStdiwhF6MC&S%qp*Qp*O`3Is9H$o7!=_`tgYpNjG+X(zb zo j+eJM@)>qijT{#1_T_{u&D9KPa1)Im8cnn95fR^&}Lw_TrUMccRDH~)0KPTpg%vl z+jo%jwQJIf2sWq$I!H8F&?o+0dY2EQ_|BZp8XqhFP*eQCqpTk zTG}RqM&kaqY8-Nv2%s=K!;t(aKWUe)b!jifOL+ax#TC7&x6xGpy82{2NIK*mWRrJ2LY@MqzH#20RT)^>o;m zR%PmJ%j~&QJadHxo{Da?6sIVj0@JWedZbg3sDjw#=%loLRIiNY&$<`7AT`-+KXEm9_b8STO+-^piJZ}a1anG`2c~qA~3X&+|rwE%) z_?#AUNRxqH-`6b+?Ry9zrf}v{<7lU|O@;AsSXHE`U4HOov|-hF z;(5nnKL1-<{??1@`%e?=W`5K*`648|JH91v)fawfP%l;%5hh;CM%7{OFcuMHUk_UA zOeiRUgq({LoV1T)5381`*w6NI>qW4<%7SVXg-VTiTkv)O$<}FjfCb&vB~~BU*8@K7 zb0Vw8N9qGR`-#~+=ycvE@LE^~(sDu-^rjOEu84QphH{>uzX=iD5ISMD&G}ziGW*jj{TEcsG~2l5U{G0AXT@| z5-?f4akSgmi;-=R_I;V~&4o-tmxn&RtHoy1m$UMw6Rsuh)DPucL~ibQwfiMjdPs5x z1ZP?k1$CmlPbqT^gdH#b1fgx4hO9_V8W^L|x*h(E(neJc;)$^Mk)i%(A-pKl?{-oN%ebi0aqJ#>wF+CdtSHi#9>L42q)`U>)4Le3%}HORTYcB7i0h^J zEvuKF@`5^Mgp8t*t5CqpuO9lijHJVdATehL+;?h_DHWhb4q<1XqCR+{}ufy9|PH@mr^U^IonXho)mI!wS+~VbEyN(_E09mJS z=qx+GN^`2E6!q{OaB;^lZ1}++t3rO(e04M_*kl!lTL9NzT`VjDkYU1$eG9r6LF%6H zqkdMTG-A+n(GA7dww)ZCG&>You0sqkU9{q230k;Z`PCfOytcs*F43$+ngv7k{&5hw zzTf!I>+ghJ22nJ@kcMmV+oRzt>yE~}IjChcij`KxNqwcQdUF4nsLqAeNLA!q(?)3p z66c{preGcpvy@rIo%8mnENAa15VBvO8-0?uR@X^C_M%vHeuJ~cbt;s|)_aTVz>g&v zTij%Og}lOwgjbsOrnz*^>{JNbTo%2#VeEd>b^Ft2vJ5bXl*lj4C9WN8T*BAA4!UcUbHuwSdTo8Zf2dk##7lKz z_V@Ya_Z!V>acC&0)Q9sKmWQJo6*+Aww&$wy93HOjcFs0zzvGWy?m$mF7iTsnD^H*$ z&=Uw^xA$;y?o6pugq6aKxD_3A_j0D_(Itt+H5Y#FcBBHauW!iQ(2_x{keh)}zCcC+ zM8{JSR#OiRkM5kats7$kq+)57P(>sfB+j@dJeA^JqV+u^afv@{iK}zQ&#ei;7yRJR zRDCgKR&}_ij2EMXO9*qSiVHttL@2M~TC@X-r6>UqRD7-PWnnj&&ilj_#VJ#ApzVpQ0?jPFCZs0W1a4x>r ztSB9cJrU2F$e*_6m`|M5Ii-{@=B}kZ<&!cY|B^RqmD7QqE;%Zf(}mYX{Tg~KEQfag zYl zvL)26aV;624>-&qD7;c&Nrw@t)ar>i&MG{tfJkUc<{fC~elS!}(CeJLxlToE09_D%ljp@ z-gXMmuiI&fk3TODB)U7$irT)%vkukBleHEt_6j=Ee$ z=4qJMSnkp<@{2~LLu>dWtli{%&a?frE>#h3JA^{%c*vJc62_9|CGnuoJ!dQQ8Q6{mUVl)B89-n^l4v8oZP)BL{im$52li;lm}&OjZX(1+EVA%D&Z6q6OqMiu+$n?00TM8i*AAdfrsNp3A_s@N z?bHH?vipzzE+-mHJjZ-r22(f`fX&RsJ#m`jL*gA4)){VOa!v|dOT-#ufS=vxH?Le3 zsCiU8bf3pC*KZbU+>Xug5_$$`2b3?|+yNP;lHpQqYHiJhS^N0-^( z`r}+@H)ne;oo^0~9ZqiMJ^)Ab1x|TKPTdd1B$EnPWHA?29WzvfU1ZG?y~5ev&@ZsQP-cOxuJzWXO+0cbvOVZXQ2nlX6yL4ZbJ?~R2SL3kn)O5- zjcSF5UJhUnXWceL${rS{B~8M3-L7GXLFb*9{Ka^a_w+aW76-q16-$sr;9@KOX8m7f-E6tbcZGNu9 zPTIW-=J9UMf9XD21y{x_T6l9D3GLWD;W|9&`7RwK#*+-b|C8$SJ6vVj%e)o{#v{=K z^& zRLaH9jvvbkYu^kx^R}8e2soEeSAvE?!G-;kZUnv};r%<`2rNj-_mqO;N=kxH|FAt- zI6ow{K*Ri_^q8$vNJ;{&0PZ9uegdwNlEAn^gQ0P7z{q5%Pa+~R5}5o)5iwZ(LG+LT z12%gQeRvd+gR}l6s(cV(z&wez$*`#ZM}E(rWFJhZLn-wqsK9?j`Tpy@{z~Pc{Yy9X zNtgGZv$OwHd`!>zgMD~-+=_o+kCiSxDT@4~_{6lnA>MwKJ_z&h}z%AscPxby4Uiu3tM)+8-(w}z!?{L$9 zSNzvu=U?_P$RF+fJACy&4?q9g++A2R*F@~tPj^^alTV}R|E5U@pHGC>~9 zF+6zbffM|>N`gHf#t+cd)zQx4iMO%8baMPh`w{iuqvhYqm{9lkp{(E}3bLp9QcFPs zQ_Bh_C!qo#QT(1lKOaPgk0NofJ|!yU|A(0Td5gypqQLe5lm-t`Vm$TK)9Uj8h<^Ag g{srvgdH^cpt1AH>;^, Object> services = new HashMap<>(); - - /** - * 注册服务 - * - * @param serviceClass 服务类 - * @param serviceImpl 服务实现 - * @param 服务类 - */ - public static void registerService(Class serviceClass, T serviceImpl) { - services.put(serviceClass, serviceImpl); - } - - /** - * 获得服务 - * - * @param serviceClass 服务类 - * @param 服务类 - * @return 服务实现 - */ - @SuppressWarnings("unchecked") - public static T getService(Class serviceClass) { - return (T) services.get(serviceClass); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java deleted file mode 100644 index b2a9f03607..0000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.common; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -// TODO @芋艿:要不要加个 mqtt 值了的前缀 -/** - * MQTT RPC 请求 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class RpcRequest { - - /** - * 方法名 - */ - private String method; - - /** - * 参数 - */ - // TODO @haohao:object 对象会不会不好序列化? - private Object[] params; - - /** - * 关联 ID - */ - private String correlationId; - - /** - * 回复地址 - */ - private String replyTo; - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java deleted file mode 100644 index f3225d08e7..0000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/RpcResponse.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.common; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * MQTT RPC 响应 - */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class RpcResponse { - - /** - * 关联 ID - */ - private String correlationId; - - /** - * 结果 - */ - // TODO @haohao:object 对象会不会不好反序列化? - private Object result; - - /** - * 错误 - */ - private String error; - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java deleted file mode 100644 index 620b007635..0000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/common/SerializationUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.yudao.module.iot.mqttrpc.common; - -import cn.hutool.json.JSONUtil; - -/** - * 序列化工具类 - * - */ -public class SerializationUtils { - - public static String serialize(Object obj) { - return JSONUtil.toJsonStr(obj); - } - - public static T deserialize(String json, Class clazz) { - return JSONUtil.toBean(json, clazz); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java index 2cb688cfa5..96ca833690 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/PluginStart.java @@ -1,22 +1,20 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import java.util.List; - -import javax.annotation.Resource; - +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; +import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import cn.iocoder.yudao.module.iot.service.plugin.PluginInfoService; +import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; -import lombok.extern.slf4j.Slf4j; - -import cn.iocoder.yudao.module.iot.service.plugin.PluginInfoService; -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; -import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; +import javax.annotation.Resource; +import java.util.List; +// TODO @芋艿:需要 review 下 @Component @Slf4j public class PluginStart implements ApplicationRunner { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index e02ec9be05..150051ce58 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -1,46 +1,35 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.api.ServiceRegistry; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.framework.plugin.listener.CustomPluginStateListener; import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; -import javax.annotation.Resource; import java.nio.file.Paths; +// TODO @芋艿:需要 review 下 @Slf4j @Configuration public class UnifiedConfiguration { - private static final String SERVICE_REGISTRY_INITIALIZED_MARKER = "serviceRegistryInitializedMarker"; - - @Resource - private DeviceDataApi deviceDataApi; @Value("${pf4j.pluginsDir:pluginsDir}") private String pluginsDir; - @Bean(SERVICE_REGISTRY_INITIALIZED_MARKER) - public Object serviceRegistryInitializedMarker() { - ServiceRegistry.registerService(DeviceDataApi.class, deviceDataApi); - log.info("[init][将 DeviceDataApi 实例注册到 ServiceRegistry 中]"); - return new Object(); - } - @Bean - @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) +// @DependsOn("deviceDataApiImpl") public SpringPluginManager pluginManager() { log.info("[init][实例化 SpringPluginManager]"); SpringPluginManager springPluginManager = new SpringPluginManager(Paths.get(pluginsDir)) { +// SpringPluginManager springPluginManager = new SpringPluginManager() { + @Override public void startPlugins() { // 禁用插件启动,避免插件启动时,启动所有插件 log.info("[init][禁用默认启动所有插件]"); } + }; springPluginManager.addPluginStateListener(new CustomPluginStateListener()); return springPluginManager; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java index c0802d7f57..4542868b03 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java @@ -5,6 +5,7 @@ import org.pf4j.PluginStateEvent; import org.pf4j.PluginStateListener; import org.springframework.stereotype.Component; +// TODO @芋艿:需要 review 下 @Component @Slf4j public class CustomPluginStateListener implements PluginStateListener { diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java index 1d6fcad92b..54d9c7c2bc 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/HttpVertxPlugin.java @@ -1,22 +1,22 @@ package cn.iocoder.yudao.module.iot.plugin; -import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; 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.pf4j.PluginWrapper; import org.pf4j.spring.SpringPlugin; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import lombok.extern.slf4j.Slf4j; - @Slf4j public class HttpVertxPlugin extends SpringPlugin { private static final int PORT = 8092; private Vertx vertx; + private DeviceDataApi deviceDataApi; public HttpVertxPlugin(PluginWrapper wrapper) { @@ -28,7 +28,7 @@ public class HttpVertxPlugin extends SpringPlugin { log.info("HttpVertxPlugin.start()"); // 获取 DeviceDataApi 实例 - deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class); + deviceDataApi = SpringUtil.getBean(DeviceDataApi.class); if (deviceDataApi == null) { log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!"); return; From d608c4b9844af070a2e45be6b6f20f5c5e4e3660 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 20 Jan 2025 20:02:46 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E3=80=91IoT=EF=BC=9A=E5=A2=9E=E5=8A=A0=20HttpPlugin?= =?UTF-8?q?=20=E7=8B=AC=E7=AB=8B=E5=90=AF=E5=8A=A8=E7=9A=84=20demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 2 +- .../yudao-module-iot-http-plugin/pom.xml | 2 +- .../iot/HttpPluginSpringbootApplication.java | 2 ++ .../module/iot/config/TestConfiguration.java | 34 +++++++++++++++++++ .../src/main/resources/application.yml | 5 +-- 5 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 0a9d0bf454..01e2f14547 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -67,7 +67,7 @@ 3.0.6 1.2.5 0.9.0 - 4.4.0 + 4.5.11 3.5.0 4.11.0 diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 22cb439681..4658a1f6bf 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -127,7 +127,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java index 6b553f92bf..2b871cadea 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/HttpPluginSpringbootApplication.java @@ -5,7 +5,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class HttpPluginSpringbootApplication { + public static void main(String[] args) { SpringApplication.run(HttpPluginSpringbootApplication.class, args); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java new file mode 100644 index 0000000000..b32a1f59fb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/config/TestConfiguration.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.config; + +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.api.device.dto.DeviceDataCreateReqDTO; +import cn.iocoder.yudao.module.iot.plugin.HttpVertxPlugin; +import org.pf4j.DefaultPluginManager; +import org.pf4j.PluginWrapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +// TODO 芋艿:临时实现; +@Configuration +public class TestConfiguration { + + @Bean + public DeviceDataApi deviceDataApi() { + return new DeviceDataApi() { + + @Override + public void saveDeviceData(DeviceDataCreateReqDTO createDTO) { + System.out.println("saveDeviceData"); + } + + }; + } + + // TODO @haohao:可能要看下,有没更好的方式 + @Bean(initMethod = "start") + public HttpVertxPlugin HttpVertxPlugin() { + PluginWrapper pluginWrapper = new PluginWrapper(new DefaultPluginManager(), null, null, null); + return new HttpVertxPlugin(pluginWrapper); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml index ea2234f83e..9056af48a3 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/resources/application.yml @@ -1,10 +1,7 @@ -server: - port: 8092 - spring: application: name: yudao-module-iot-http-plugin - + # MQTT-RPC 配置 mqtt: broker: tcp://chaojiniu.top:1883