Commit bf41d47fa843e29a7bbce04aa418bc539f6f2f52
1 parent
a5a3aea5
review:【IoT 物联网】网关 TCP 的接入代码
Showing
7 changed files
with
21 additions
and
10 deletions
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java
| ... | ... | @@ -85,6 +85,7 @@ public class IotGatewayConfiguration { |
| 85 | 85 | @Slf4j |
| 86 | 86 | public static class TcpProtocolConfiguration { |
| 87 | 87 | |
| 88 | + // TODO @haohao:close | |
| 88 | 89 | @Bean |
| 89 | 90 | public Vertx tcpVertx() { |
| 90 | 91 | return Vertx.vertx(); |
| ... | ... | @@ -92,16 +93,17 @@ public class IotGatewayConfiguration { |
| 92 | 93 | |
| 93 | 94 | @Bean |
| 94 | 95 | public IotTcpUpstreamProtocol iotTcpUpstreamProtocol(Vertx tcpVertx, IotGatewayProperties gatewayProperties, |
| 95 | - IotTcpConnectionManager connectionManager, IotDeviceMessageService messageService, | |
| 96 | - IotDeviceService deviceService, IotDeviceCommonApi deviceApi) { | |
| 96 | + IotTcpConnectionManager connectionManager, | |
| 97 | + IotDeviceMessageService messageService, | |
| 98 | + IotDeviceService deviceService, IotDeviceCommonApi deviceApi) { | |
| 97 | 99 | return new IotTcpUpstreamProtocol(tcpVertx, gatewayProperties, connectionManager, |
| 98 | 100 | messageService, deviceService, deviceApi); |
| 99 | 101 | } |
| 100 | 102 | |
| 101 | 103 | @Bean |
| 102 | 104 | public IotTcpDownstreamSubscriber iotTcpDownstreamSubscriber(IotTcpUpstreamProtocol tcpUpstreamProtocol, |
| 103 | - IotMessageBus messageBus, | |
| 104 | - IotTcpDownstreamHandler downstreamHandler) { | |
| 105 | + IotMessageBus messageBus, | |
| 106 | + IotTcpDownstreamHandler downstreamHandler) { | |
| 105 | 107 | return new IotTcpDownstreamSubscriber(tcpUpstreamProtocol, messageBus, downstreamHandler); |
| 106 | 108 | } |
| 107 | 109 | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java
| ... | ... | @@ -108,10 +108,12 @@ public class IotGatewayProperties { |
| 108 | 108 | */ |
| 109 | 109 | @NotNull(message = "是否开启不能为空") |
| 110 | 110 | private Boolean enabled; |
| 111 | + // TODO @haohao:加个默认值? | |
| 111 | 112 | /** |
| 112 | 113 | * 服务端口 |
| 113 | 114 | */ |
| 114 | 115 | private Integer serverPort; |
| 116 | + // TODO @haohao:应该不用?一般都监听 0.0.0.0 哈; | |
| 115 | 117 | /** |
| 116 | 118 | * 服务主机 |
| 117 | 119 | */ | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java
| ... | ... | @@ -79,7 +79,7 @@ public class IotEmqxDownstreamHandler { |
| 79 | 79 | // 2. 根据消息方法和回复状态,构建 topic |
| 80 | 80 | boolean isReply = IotDeviceMessageUtils.isReplyMessage(message); |
| 81 | 81 | |
| 82 | - // TODO @芋艿:看看基于 message 的 method 去反向推导; | |
| 82 | + // TODO @haohao:看看基于 message 的 method 去反向推导; | |
| 83 | 83 | // 3. 根据消息方法类型构建对应的主题 |
| 84 | 84 | switch (methodEnum) { |
| 85 | 85 | case PROPERTY_POST: |
| ... | ... | @@ -88,21 +88,18 @@ public class IotEmqxDownstreamHandler { |
| 88 | 88 | return IotMqttTopicUtils.buildPropertyPostReplyTopic(productKey, deviceName); |
| 89 | 89 | } |
| 90 | 90 | break; |
| 91 | - | |
| 92 | 91 | case PROPERTY_SET: |
| 93 | 92 | // 属性设置:只支持非回复消息(下行) |
| 94 | 93 | if (!isReply) { |
| 95 | 94 | return IotMqttTopicUtils.buildPropertySetTopic(productKey, deviceName); |
| 96 | 95 | } |
| 97 | 96 | break; |
| 98 | - | |
| 99 | 97 | case EVENT_POST: |
| 100 | 98 | // 事件上报:只支持回复消息(下行) |
| 101 | 99 | if (isReply) { |
| 102 | 100 | return IotMqttTopicUtils.buildEventPostReplyTopicGeneric(productKey, deviceName); |
| 103 | 101 | } |
| 104 | 102 | break; |
| 105 | - | |
| 106 | 103 | case SERVICE_INVOKE: |
| 107 | 104 | // 服务调用:支持请求和回复 |
| 108 | 105 | if (isReply) { |
| ... | ... | @@ -110,14 +107,12 @@ public class IotEmqxDownstreamHandler { |
| 110 | 107 | } else { |
| 111 | 108 | return IotMqttTopicUtils.buildServiceTopicGeneric(productKey, deviceName); |
| 112 | 109 | } |
| 113 | - | |
| 114 | 110 | case CONFIG_PUSH: |
| 115 | 111 | // 配置推送:平台向设备推送配置(下行请求),设备回复确认(上行回复) |
| 116 | 112 | if (!isReply) { |
| 117 | 113 | return IotMqttTopicUtils.buildConfigPushTopic(productKey, deviceName); |
| 118 | 114 | } |
| 119 | 115 | break; |
| 120 | - | |
| 121 | 116 | default: |
| 122 | 117 | log.warn("[buildTopicByMethod][未处理的消息方法: {}]", methodEnum); |
| 123 | 118 | break; | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java
| ... | ... | @@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentMap; |
| 16 | 16 | @Slf4j |
| 17 | 17 | public class IotTcpConnectionManager { |
| 18 | 18 | |
| 19 | + // TODO @haohao:要考虑,相同设备,多次连接的情况哇? | |
| 19 | 20 | /** |
| 20 | 21 | * 连接集合 |
| 21 | 22 | * |
| ... | ... | @@ -50,6 +51,7 @@ public class IotTcpConnectionManager { |
| 50 | 51 | * @param socket Netty Channel |
| 51 | 52 | */ |
| 52 | 53 | public void removeConnection(NetSocket socket) { |
| 54 | + // TODO @haohao:vertx 的 socket,有没办法设置一些属性,类似 netty 的;目的是,避免遍历 connectionMap 去操作哈; | |
| 53 | 55 | connectionMap.entrySet().stream() |
| 54 | 56 | .filter(entry -> entry.getValue().equals(socket)) |
| 55 | 57 | .findFirst() | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java
| ... | ... | @@ -64,6 +64,7 @@ public class IotTcpConnectionHandler implements Handler<Buffer> { |
| 64 | 64 | public void handle(Buffer buffer) { |
| 65 | 65 | log.info("[handle][接收到数据: {}]", buffer); |
| 66 | 66 | try { |
| 67 | + // TODO @haohao:可以调研下,做个对比表格哈; | |
| 67 | 68 | // 1. 处理认证 |
| 68 | 69 | if (!authenticated) { |
| 69 | 70 | handleAuthentication(buffer); |
| ... | ... | @@ -80,6 +81,11 @@ public class IotTcpConnectionHandler implements Handler<Buffer> { |
| 80 | 81 | private void handleAuthentication(Buffer buffer) { |
| 81 | 82 | // 1. 解析认证信息 |
| 82 | 83 | // TODO @芋艿:这里的认证协议,需要和设备端约定。默认为 productKey,deviceName,password |
| 84 | + // TODO @haohao:这里,要不也 json 解析?类似 http 是 { | |
| 85 | + // "clientId": "4aymZgOTOOCrDKRT.small", | |
| 86 | + // "username": "small&4aymZgOTOOCrDKRT", | |
| 87 | + // "password": "509e2b08f7598eb139d276388c600435913ba4c94cd0d50aebc5c0d1855bcb75" | |
| 88 | + //} | |
| 83 | 89 | String[] parts = buffer.toString().split(","); |
| 84 | 90 | if (parts.length != 3) { |
| 85 | 91 | log.error("[handleAuthentication][认证信息({})格式不正确]", buffer); | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java
| ... | ... | @@ -22,6 +22,7 @@ import org.springframework.stereotype.Component; |
| 22 | 22 | public class IotTcpDownstreamHandler { |
| 23 | 23 | |
| 24 | 24 | private final IotTcpConnectionManager connectionManager; |
| 25 | + | |
| 25 | 26 | private final IotDeviceMessageService messageService; |
| 26 | 27 | |
| 27 | 28 | /** |
| ... | ... | @@ -43,6 +44,7 @@ public class IotTcpDownstreamHandler { |
| 43 | 44 | // 3. 发送消息 |
| 44 | 45 | socket.write(Buffer.buffer(bytes)); |
| 45 | 46 | // TODO @芋艿:这里的换行符,需要和设备端约定 |
| 47 | + // TODO @haohao:tcp 要不定长?很少 \n 哈。然后有个 magic number;可以参考 dubbo rpc; | |
| 46 | 48 | socket.write("\n"); |
| 47 | 49 | } |
| 48 | 50 | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java
| ... | ... | @@ -16,6 +16,7 @@ public final class IotMqttTopicUtils { |
| 16 | 16 | */ |
| 17 | 17 | private static final String SYS_TOPIC_PREFIX = "/sys/"; |
| 18 | 18 | |
| 19 | + // TODO @haohao:这个要删除哇? | |
| 19 | 20 | /** |
| 20 | 21 | * 服务调用主题前缀 |
| 21 | 22 | */ |
| ... | ... | @@ -36,6 +37,7 @@ public final class IotMqttTopicUtils { |
| 36 | 37 | */ |
| 37 | 38 | public static final String MQTT_EVENT_PATH = "/mqtt/event"; |
| 38 | 39 | |
| 40 | + // TODO @haohao:这个要删除哇? | |
| 39 | 41 | /** |
| 40 | 42 | * MQTT 授权接口路径(预留) |
| 41 | 43 | * 对应 EMQX HTTP 授权插件的授权检查接口 | ... | ... |