Commit af0ff1ce2672b67f0b66528fbd3c68299719134c
1 parent
74db72c9
review:【IoT 物联网】mqtt broker 协议
Showing
5 changed files
with
17 additions
and
5 deletions
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) { |