Commit af0ff1ce2672b67f0b66528fbd3c68299719134c

Authored by YunaiV
1 parent 74db72c9

review:【IoT 物联网】mqtt broker 协议

yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttDownstreamSubscriber.java
@@ -48,15 +48,15 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi @@ -48,15 +48,15 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi
48 @Override 48 @Override
49 public void onMessage(IotDeviceMessage message) { 49 public void onMessage(IotDeviceMessage message) {
50 log.info("[onMessage][接收到下行消息:{}]", message); 50 log.info("[onMessage][接收到下行消息:{}]", message);
51 -  
52 try { 51 try {
53 // 根据消息方法处理不同的下行消息 52 // 根据消息方法处理不同的下行消息
54 String method = message.getMethod(); 53 String method = message.getMethod();
55 if (method == null) { 54 if (method == null) {
56 - log.warn("[onMessage][消息方法为空]"); 55 + log.warn("[onMessage][消息({})方法为空]", message);
57 return; 56 return;
58 } 57 }
59 58
  59 + // TODO @haohao:看看怎么融合下
60 if (method.startsWith("thing.service.property.")) { 60 if (method.startsWith("thing.service.property.")) {
61 handlePropertyMessage(message); 61 handlePropertyMessage(message);
62 } else if (method.startsWith("thing.service.") && !method.contains("property") && !method.contains("config") 62 } else if (method.startsWith("thing.service.") && !method.contains("property") && !method.contains("config")
@@ -83,6 +83,7 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi @@ -83,6 +83,7 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi
83 String method = message.getMethod(); 83 String method = message.getMethod();
84 84
85 // 通过 deviceId 获取设备信息 85 // 通过 deviceId 获取设备信息
  86 + // TODO @haohao:通过缓存拿;
86 IotDeviceGetReqDTO reqDTO = new IotDeviceGetReqDTO(); 87 IotDeviceGetReqDTO reqDTO = new IotDeviceGetReqDTO();
87 reqDTO.setId(message.getDeviceId()); 88 reqDTO.setId(message.getDeviceId());
88 IotDeviceRespDTO deviceInfo = deviceApi.getDevice(reqDTO).getData(); 89 IotDeviceRespDTO deviceInfo = deviceApi.getDevice(reqDTO).getData();
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttHttpAuthProtocol.java
@@ -12,6 +12,7 @@ import jakarta.annotation.PreDestroy; @@ -12,6 +12,7 @@ import jakarta.annotation.PreDestroy;
12 import lombok.RequiredArgsConstructor; 12 import lombok.RequiredArgsConstructor;
13 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
14 14
  15 +// TODO @haohao:可以融合到 IotMqttUpstreamProtocol 么?主要考虑,一个协议,一个 protocol;
15 /** 16 /**
16 * IoT 网关 MQTT HTTP 认证协议:提供 HTTP 认证接口供 EMQX 调用 17 * IoT 网关 MQTT HTTP 认证协议:提供 HTTP 认证接口供 EMQX 调用
17 * 18 *
@@ -82,6 +83,7 @@ public class IotMqttHttpAuthProtocol extends AbstractVerticle { @@ -82,6 +83,7 @@ public class IotMqttHttpAuthProtocol extends AbstractVerticle {
82 } 83 }
83 } 84 }
84 85
  86 + // TODO @haohao:这里不搞默认,必须填写哈;
85 /** 87 /**
86 * 获取认证服务端口 88 * 获取认证服务端口
87 * 从配置中获取,默认使用 8090 端口 89 * 从配置中获取,默认使用 8090 端口
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttUpstreamProtocol.http
  1 +### TODO 芋艿:这个文件是不是要留着;
1 ### IoT MQTT HTTP 认证服务测试文件 2 ### IoT MQTT HTTP 认证服务测试文件
2 ### 用于测试独立的 MQTT HTTP 认证服务接口 3 ### 用于测试独立的 MQTT HTTP 认证服务接口
3 ### 服务由 IotMqttHttpAuthProtocol 启动,运行在配置的端口上(默认 8090) 4 ### 服务由 IotMqttHttpAuthProtocol 启动,运行在配置的端口上(默认 8090)
@@ -101,7 +102,7 @@ Content-Type: application/json @@ -101,7 +102,7 @@ Content-Type: application/json
101 ### 假设配置了端口 8091: 102 ### 假设配置了端口 8091:
102 ### POST http://localhost:8091/mqtt/auth/authenticate 103 ### POST http://localhost:8091/mqtt/auth/authenticate
103 ### Content-Type: application/json 104 ### Content-Type: application/json
104 -### 105 +###
105 ### { 106 ### {
106 ### "clientid": "test_product.test_device", 107 ### "clientid": "test_product.test_device",
107 ### "username": "test_device&test_product", 108 ### "username": "test_device&test_product",
@@ -136,4 +137,4 @@ Content-Type: application/json @@ -136,4 +137,4 @@ Content-Type: application/json
136 ### url = "http://localhost:8090/mqtt/auth/disconnected" # 使用配置的端口 137 ### url = "http://localhost:8090/mqtt/auth/disconnected" # 使用配置的端口
137 ### events = ["client.disconnected"] 138 ### events = ["client.disconnected"]
138 ### } 139 ### }
139 -### ]  
140 \ No newline at end of file 140 \ No newline at end of file
  141 +### ]
141 \ No newline at end of file 142 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttUpstreamProtocol.java
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties; @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
9 import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttUpstreamRouter; 9 import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttUpstreamRouter;
10 import io.netty.handler.codec.mqtt.MqttQoS; 10 import io.netty.handler.codec.mqtt.MqttQoS;
11 import io.vertx.core.Vertx; 11 import io.vertx.core.Vertx;
  12 +import io.vertx.core.buffer.Buffer;
12 import io.vertx.mqtt.MqttClient; 13 import io.vertx.mqtt.MqttClient;
13 import io.vertx.mqtt.MqttClientOptions; 14 import io.vertx.mqtt.MqttClientOptions;
14 import jakarta.annotation.PostConstruct; 15 import jakarta.annotation.PostConstruct;
@@ -59,6 +60,7 @@ public class IotMqttUpstreamProtocol { @@ -59,6 +60,7 @@ public class IotMqttUpstreamProtocol {
59 60
60 // 创建 MQTT 客户端 61 // 创建 MQTT 客户端
61 MqttClientOptions options = new MqttClientOptions() 62 MqttClientOptions options = new MqttClientOptions()
  63 + // TODO @haohao:clientid 建议也配置文件;想通名字,会冲突哇?
62 .setClientId("yudao-iot-gateway-" + IdUtil.fastSimpleUUID()) 64 .setClientId("yudao-iot-gateway-" + IdUtil.fastSimpleUUID())
63 .setUsername(emqxProperties.getMqttUsername()) 65 .setUsername(emqxProperties.getMqttUsername())
64 .setPassword(emqxProperties.getMqttPassword()) 66 .setPassword(emqxProperties.getMqttPassword())
@@ -121,6 +123,7 @@ public class IotMqttUpstreamProtocol { @@ -121,6 +123,7 @@ public class IotMqttUpstreamProtocol {
121 */ 123 */
122 private void connectMqtt() { 124 private void connectMqtt() {
123 // 检查必要的 MQTT 配置 125 // 检查必要的 MQTT 配置
  126 + // TODO @haohao:这些通过配置文件的 validate 去做哈,简化下;
124 String host = emqxProperties.getMqttHost(); 127 String host = emqxProperties.getMqttHost();
125 Integer port = emqxProperties.getMqttPort(); 128 Integer port = emqxProperties.getMqttPort();
126 if (StrUtil.isBlank(host)) { 129 if (StrUtil.isBlank(host)) {
@@ -149,6 +152,7 @@ public class IotMqttUpstreamProtocol { @@ -149,6 +152,7 @@ public class IotMqttUpstreamProtocol {
149 // 订阅主题 152 // 订阅主题
150 subscribeToTopics(); 153 subscribeToTopics();
151 }) 154 })
  155 + // TODO @haohao:这个要不要改成,必须连接成功?不做重试;不然启动也蛮危险的?
152 .exceptionally(error -> { 156 .exceptionally(error -> {
153 log.error("[connectMqtt][连接 MQTT Broker 失败]", error); 157 log.error("[connectMqtt][连接 MQTT Broker 失败]", error);
154 reconnectWithDelay(); 158 reconnectWithDelay();
@@ -178,12 +182,14 @@ public class IotMqttUpstreamProtocol { @@ -178,12 +182,14 @@ public class IotMqttUpstreamProtocol {
178 */ 182 */
179 private void subscribeToTopics() { 183 private void subscribeToTopics() {
180 List<String> topicList = emqxProperties.getMqttTopics(); 184 List<String> topicList = emqxProperties.getMqttTopics();
  185 + // TODO @haohao:建议 topicList 直接 validate 校验
181 if (CollUtil.isEmpty(topicList)) { 186 if (CollUtil.isEmpty(topicList)) {
182 log.warn("[subscribeToTopics][未配置 MQTT 主题,使用默认主题]"); 187 log.warn("[subscribeToTopics][未配置 MQTT 主题,使用默认主题]");
183 topicList = List.of("/sys/#"); // 默认订阅所有系统主题 188 topicList = List.of("/sys/#"); // 默认订阅所有系统主题
184 } 189 }
185 190
186 for (String topic : topicList) { 191 for (String topic : topicList) {
  192 + // TODO @haohao:直接 validate 校验;嘿嘿,主要保证核心逻辑,简单点
187 if (StrUtil.isBlank(topic)) { 193 if (StrUtil.isBlank(topic)) {
188 log.warn("[subscribeToTopics][跳过空主题]"); 194 log.warn("[subscribeToTopics][跳过空主题]");
189 continue; 195 continue;
@@ -224,7 +230,7 @@ public class IotMqttUpstreamProtocol { @@ -224,7 +230,7 @@ public class IotMqttUpstreamProtocol {
224 return; 230 return;
225 } 231 }
226 232
227 - mqttClient.publish(topic, io.vertx.core.buffer.Buffer.buffer(payload), DEFAULT_QOS, false, false) 233 + mqttClient.publish(topic, Buffer.buffer(payload), DEFAULT_QOS, false, false)
228 .onSuccess(v -> log.debug("[publishMessage][发送消息成功][topic: {}]", topic)) 234 .onSuccess(v -> log.debug("[publishMessage][发送消息成功][topic: {}]", topic))
229 .onFailure(err -> log.error("[publishMessage][发送消息失败][topic: {}]", topic, err)); 235 .onFailure(err -> log.error("[publishMessage][发送消息失败][topic: {}]", topic, err));
230 } 236 }
@@ -238,6 +244,7 @@ public class IotMqttUpstreamProtocol { @@ -238,6 +244,7 @@ public class IotMqttUpstreamProtocol {
238 return IotDeviceMessageUtils.generateServerId(emqxProperties.getMqttPort()); 244 return IotDeviceMessageUtils.generateServerId(emqxProperties.getMqttPort());
239 } 245 }
240 246
  247 + // TODO @haohao:这个要删除哇?
241 /** 248 /**
242 * 获取 MQTT 客户端 249 * 获取 MQTT 客户端
243 * 250 *
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttEventHandler.java
@@ -56,6 +56,7 @@ public class IotMqttEventHandler extends IotMqttAbstractHandler { @@ -56,6 +56,7 @@ public class IotMqttEventHandler extends IotMqttAbstractHandler {
56 log.info("[handle][处理设备事件上报成功][topic: {}]", topic); 56 log.info("[handle][处理设备事件上报成功][topic: {}]", topic);
57 57
58 // 发送响应消息 58 // 发送响应消息
  59 + // TODO @haohao:这里应该只 ack 哈;reply 在 biz 业务处理了。handleUpstreamDeviceMessage
59 String method = "thing.event." + eventIdentifier + ".post"; 60 String method = "thing.event." + eventIdentifier + ".post";
60 sendResponse(topic, JSONUtil.parseObj(payload), method); 61 sendResponse(topic, JSONUtil.parseObj(payload), method);
61 } catch (Exception e) { 62 } catch (Exception e) {