Commit 6b79cab09a5334844f8159a086e85365c82e86d0

Authored by YunaiV
1 parent c9b9fc1f

review:【iot 物联网】tcp 协议的接入

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageServiceImpl.java
@@ -236,8 +236,8 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { @@ -236,8 +236,8 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService {
236 236
237 @Override 237 @Override
238 public Long getDeviceMessageCount(LocalDateTime createTime) { 238 public Long getDeviceMessageCount(LocalDateTime createTime) {
239 - return deviceMessageMapper  
240 - .selectCountByCreateTime(createTime != null ? LocalDateTimeUtil.toEpochMilli(createTime) : null); 239 + return deviceMessageMapper.selectCountByCreateTime(
  240 + createTime != null ? LocalDateTimeUtil.toEpochMilli(createTime) : null);
241 } 241 }
242 242
243 @Override 243 @Override
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/alink/IotAlinkDeviceMessageCodec.java
@@ -18,6 +18,8 @@ import org.springframework.stereotype.Component; @@ -18,6 +18,8 @@ import org.springframework.stereotype.Component;
18 @Component 18 @Component
19 public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec { 19 public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec {
20 20
  21 + private static final String TYPE = "Alink";
  22 +
21 @Data 23 @Data
22 @NoArgsConstructor 24 @NoArgsConstructor
23 @AllArgsConstructor 25 @AllArgsConstructor
@@ -63,6 +65,11 @@ public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec { @@ -63,6 +65,11 @@ public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec {
63 } 65 }
64 66
65 @Override 67 @Override
  68 + public String type() {
  69 + return TYPE;
  70 + }
  71 +
  72 + @Override
66 public byte[] encode(IotDeviceMessage message) { 73 public byte[] encode(IotDeviceMessage message) {
67 AlinkMessage alinkMessage = new AlinkMessage(message.getRequestId(), AlinkMessage.VERSION_1, 74 AlinkMessage alinkMessage = new AlinkMessage(message.getRequestId(), AlinkMessage.VERSION_1,
68 message.getMethod(), message.getParams(), message.getData(), message.getCode(), message.getMsg()); 75 message.getMethod(), message.getParams(), message.getData(), message.getCode(), message.getMsg());
@@ -79,9 +86,4 @@ public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec { @@ -79,9 +86,4 @@ public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec {
79 alinkMessage.getData(), alinkMessage.getCode(), alinkMessage.getMsg()); 86 alinkMessage.getData(), alinkMessage.getCode(), alinkMessage.getMsg());
80 } 87 }
81 88
82 - @Override  
83 - public String type() {  
84 - return "Alink";  
85 - }  
86 -  
87 } 89 }
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpBinaryDeviceMessageCodec.java
@@ -11,17 +11,29 @@ import lombok.Data; @@ -11,17 +11,29 @@ import lombok.Data;
11 import lombok.NoArgsConstructor; 11 import lombok.NoArgsConstructor;
12 import org.springframework.stereotype.Component; 12 import org.springframework.stereotype.Component;
13 13
  14 +// TODO @haohao:【重要】是不是二进制更彻底哈?
  15 +// 包头(4 字节)
  16 +// 消息 ID string;nvarchar(length + string)
  17 +// version(可选,不要干脆)
  18 +// method string;nvarchar;为什么不要 opcode?因为 IotTcpJsonDeviceMessageCodec 里面,实际已经没 opcode 了
  19 +// reply bit;0 请求,1 响应
  20 +// 请求时:
  21 +// params;nvarchar;json 处理
  22 +// 响应时:
  23 +// code
  24 +// msg nvarchar
  25 +// data;nvarchar;json 处理
14 /** 26 /**
15 * TCP 二进制格式 {@link IotDeviceMessage} 编解码器 27 * TCP 二进制格式 {@link IotDeviceMessage} 编解码器
16 * 28 *
17 - * 使用自定义二进制协议格式:  
18 - * 包头(4 字节) | 功能码(2 字节) | 消息序号(2 字节) | 包体数据(变长) 29 + * 使用自定义二进制协议格式:包头(4 字节) | 功能码(2 字节) | 消息序号(2 字节) | 包体数据(变长)
19 * 30 *
20 * @author 芋道源码 31 * @author 芋道源码
21 */ 32 */
22 @Component 33 @Component
23 public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { 34 public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
24 35
  36 + // TODO @haohao:是不是叫 TCP_Binary 好点哈?
25 public static final String TYPE = "TCP_BINARY"; 37 public static final String TYPE = "TCP_BINARY";
26 38
27 @Data 39 @Data
@@ -34,11 +46,13 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -34,11 +46,13 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
34 */ 46 */
35 private Short code; 47 private Short code;
36 48
  49 + // TODO @haohao:这个和 AlinkMessage 里面,是一个东西哇?
37 /** 50 /**
38 * 消息序号 51 * 消息序号
39 */ 52 */
40 private Short mid; 53 private Short mid;
41 54
  55 + // TODO @haohao:这个字段,是不是没用到呀?感觉应该也不在消息列哈?
42 /** 56 /**
43 * 设备 ID 57 * 设备 ID
44 */ 58 */
@@ -59,6 +73,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -59,6 +73,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
59 */ 73 */
60 private Object data; 74 private Object data;
61 75
  76 + // TODO @haohao:这个可以改成 code 哇?更好理解一点;
62 /** 77 /**
63 * 响应错误码 78 * 响应错误码
64 */ 79 */
@@ -69,6 +84,8 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -69,6 +84,8 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
69 */ 84 */
70 private String msg; 85 private String msg;
71 86
  87 + // TODO @haohao:TcpBinaryMessage 和 TcpJsonMessage 保持一致哈?
  88 +
72 } 89 }
73 90
74 @Override 91 @Override
@@ -83,13 +100,14 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -83,13 +100,14 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
83 100
84 try { 101 try {
85 // 1. 确定功能码 102 // 1. 确定功能码
86 - short code = MessageMethod.STATE_ONLINE.equals(message.getMethod()) ? TcpDataPackage.CODE_HEARTBEAT  
87 - : TcpDataPackage.CODE_MESSAGE_UP; 103 + short code = MessageMethod.STATE_ONLINE.equals(message.getMethod())
  104 + ? TcpDataPackage.CODE_HEARTBEAT : TcpDataPackage.CODE_MESSAGE_UP;
88 105
89 // 2. 构建负载数据 106 // 2. 构建负载数据
90 String payload = buildPayload(message); 107 String payload = buildPayload(message);
91 108
92 // 3. 构建 TCP 数据包 109 // 3. 构建 TCP 数据包
  110 + // TODO @haohao:这个和 AlinkMessage.id 是不是一致的哈?
93 short mid = (short) (System.currentTimeMillis() % Short.MAX_VALUE); 111 short mid = (short) (System.currentTimeMillis() % Short.MAX_VALUE);
94 TcpDataPackage dataPackage = new TcpDataPackage(code, mid, payload); 112 TcpDataPackage dataPackage = new TcpDataPackage(code, mid, payload);
95 113
@@ -101,7 +119,6 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -101,7 +119,6 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
101 } 119 }
102 120
103 @Override 121 @Override
104 - @SuppressWarnings("DataFlowIssue")  
105 public IotDeviceMessage decode(byte[] bytes) { 122 public IotDeviceMessage decode(byte[] bytes) {
106 Assert.notNull(bytes, "待解码数据不能为空"); 123 Assert.notNull(bytes, "待解码数据不能为空");
107 Assert.isTrue(bytes.length > 0, "待解码数据不能为空"); 124 Assert.isTrue(bytes.length > 0, "待解码数据不能为空");
@@ -188,21 +205,20 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -188,21 +205,20 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
188 Assert.notNull(dataPackage, "数据包对象不能为空"); 205 Assert.notNull(dataPackage, "数据包对象不能为空");
189 Assert.notNull(dataPackage.getPayload(), "负载不能为空"); 206 Assert.notNull(dataPackage.getPayload(), "负载不能为空");
190 207
191 - Buffer buffer = Buffer.buffer();  
192 -  
193 // 1. 计算包体长度(除了包头 4 字节) 208 // 1. 计算包体长度(除了包头 4 字节)
194 int payloadLength = dataPackage.getPayload().getBytes().length; 209 int payloadLength = dataPackage.getPayload().getBytes().length;
195 int totalLength = 2 + 2 + payloadLength; 210 int totalLength = 2 + 2 + payloadLength;
196 211
197 - // 2. 写入包头:总长度(4 字节) 212 + // 2. 写入数据
  213 + Buffer buffer = Buffer.buffer();
  214 + // 2.1 写入包头:总长度(4 字节)
198 buffer.appendInt(totalLength); 215 buffer.appendInt(totalLength);
199 - // 3. 写入功能码(2 字节) 216 + // 2.2 写入功能码(2 字节)
200 buffer.appendShort(dataPackage.getCode()); 217 buffer.appendShort(dataPackage.getCode());
201 - // 4. 写入消息序号(2 字节) 218 + // 2.3 写入消息序号(2 字节)
202 buffer.appendShort(dataPackage.getMid()); 219 buffer.appendShort(dataPackage.getMid());
203 - // 5. 写入包体数据(不定长) 220 + // 2.4 写入包体数据(不定长)
204 buffer.appendBytes(dataPackage.getPayload().getBytes()); 221 buffer.appendBytes(dataPackage.getPayload().getBytes());
205 -  
206 return buffer; 222 return buffer;
207 } 223 }
208 224
@@ -216,18 +232,14 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -216,18 +232,14 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
216 Assert.isTrue(buffer.length() >= 8, "数据包长度不足"); 232 Assert.isTrue(buffer.length() >= 8, "数据包长度不足");
217 233
218 int index = 0; 234 int index = 0;
219 -  
220 // 1. 跳过包头(4 字节) 235 // 1. 跳过包头(4 字节)
221 index += 4; 236 index += 4;
222 -  
223 // 2. 获取功能码(2 字节) 237 // 2. 获取功能码(2 字节)
224 short code = buffer.getShort(index); 238 short code = buffer.getShort(index);
225 index += 2; 239 index += 2;
226 -  
227 // 3. 获取消息序号(2 字节) 240 // 3. 获取消息序号(2 字节)
228 short mid = buffer.getShort(index); 241 short mid = buffer.getShort(index);
229 index += 2; 242 index += 2;
230 -  
231 // 4. 获取包体数据 243 // 4. 获取包体数据
232 String payload = ""; 244 String payload = "";
233 if (index < buffer.length()) { 245 if (index < buffer.length()) {
@@ -239,14 +251,17 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -239,14 +251,17 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
239 251
240 // ==================== 内部类 ==================== 252 // ==================== 内部类 ====================
241 253
  254 + // TODO @haohao:会不会存在 reply 的时候,有 data、msg、code 参数哈。
242 /** 255 /**
243 * 负载信息类 256 * 负载信息类
244 */ 257 */
245 @Data 258 @Data
246 @AllArgsConstructor 259 @AllArgsConstructor
247 private static class PayloadInfo { 260 private static class PayloadInfo {
  261 +
248 private String requestId; 262 private String requestId;
249 private Object params; 263 private Object params;
  264 +
250 } 265 }
251 266
252 /** 267 /**
@@ -255,6 +270,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -255,6 +270,7 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
255 @Data 270 @Data
256 @AllArgsConstructor 271 @AllArgsConstructor
257 private static class TcpDataPackage { 272 private static class TcpDataPackage {
  273 +
258 // 功能码定义 274 // 功能码定义
259 public static final short CODE_REGISTER = 10; 275 public static final short CODE_REGISTER = 10;
260 public static final short CODE_REGISTER_REPLY = 11; 276 public static final short CODE_REGISTER_REPLY = 11;
@@ -263,9 +279,11 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -263,9 +279,11 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
263 public static final short CODE_MESSAGE_UP = 30; 279 public static final short CODE_MESSAGE_UP = 30;
264 public static final short CODE_MESSAGE_DOWN = 40; 280 public static final short CODE_MESSAGE_DOWN = 40;
265 281
  282 + // TODO @haohao:要不改成 opCode
266 private short code; 283 private short code;
267 private short mid; 284 private short mid;
268 private String payload; 285 private String payload;
  286 +
269 } 287 }
270 288
271 // ==================== 常量定义 ==================== 289 // ==================== 常量定义 ====================
@@ -274,12 +292,15 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -274,12 +292,15 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
274 * 消息方法常量 292 * 消息方法常量
275 */ 293 */
276 public static class MessageMethod { 294 public static class MessageMethod {
  295 +
277 public static final String PROPERTY_POST = "thing.property.post"; // 数据上报 296 public static final String PROPERTY_POST = "thing.property.post"; // 数据上报
278 public static final String STATE_ONLINE = "thing.state.online"; // 心跳 297 public static final String STATE_ONLINE = "thing.state.online"; // 心跳
  298 +
279 } 299 }
280 300
281 // ==================== 自定义异常 ==================== 301 // ==================== 自定义异常 ====================
282 302
  303 + // TODO @haohao:全局异常搞个。看着可以服用哈。
283 /** 304 /**
284 * TCP 编解码异常 305 * TCP 编解码异常
285 */ 306 */
@@ -288,4 +309,5 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec { @@ -288,4 +309,5 @@ public class IotTcpBinaryDeviceMessageCodec implements IotDeviceMessageCodec {
288 super(message, cause); 309 super(message, cause);
289 } 310 }
290 } 311 }
  312 +
291 } 313 }
292 \ No newline at end of file 314 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/tcp/IotTcpJsonDeviceMessageCodec.java
@@ -12,15 +12,14 @@ import org.springframework.stereotype.Component; @@ -12,15 +12,14 @@ import org.springframework.stereotype.Component;
12 /** 12 /**
13 * TCP JSON 格式 {@link IotDeviceMessage} 编解码器 13 * TCP JSON 格式 {@link IotDeviceMessage} 编解码器
14 * 14 *
15 - * 采用纯 JSON 格式传输  
16 - *  
17 - * JSON 消息格式: 15 + * 采用纯 JSON 格式传输,格式如下:
18 * { 16 * {
19 - * "id": "消息 ID",  
20 - * "method": "消息方法",  
21 - * "deviceId": "设备 ID",  
22 - * "params": {...},  
23 - * "timestamp": 时间戳 17 + * "id": "消息 ID",
  18 + * "method": "消息方法",
  19 + * "deviceId": "设备 ID",
  20 + * "params": {...},
  21 + * "timestamp": 时间戳
  22 + * // TODO @haohao:貌似少了 code、msg、timestamp
24 * } 23 * }
25 * 24 *
26 * @author 芋道源码 25 * @author 芋道源码
@@ -45,6 +44,7 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -45,6 +44,7 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
45 */ 44 */
46 private String method; 45 private String method;
47 46
  47 + // TODO @haohao:这个字段,是不是没用到呀?感觉应该也不在消息列哈?
48 /** 48 /**
49 * 设备 ID 49 * 设备 ID
50 */ 50 */
@@ -84,14 +84,9 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -84,14 +84,9 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
84 84
85 @Override 85 @Override
86 public byte[] encode(IotDeviceMessage message) { 86 public byte[] encode(IotDeviceMessage message) {
87 - TcpJsonMessage tcpJsonMessage = new TcpJsonMessage(  
88 - message.getRequestId(),  
89 - message.getMethod(), 87 + TcpJsonMessage tcpJsonMessage = new TcpJsonMessage(message.getRequestId(), message.getMethod(),
90 message.getDeviceId(), 88 message.getDeviceId(),
91 - message.getParams(),  
92 - message.getData(),  
93 - message.getCode(),  
94 - message.getMsg(), 89 + message.getParams(), message.getData(), message.getCode(), message.getMsg(),
95 System.currentTimeMillis()); 90 System.currentTimeMillis());
96 return JsonUtils.toJsonByte(tcpJsonMessage); 91 return JsonUtils.toJsonByte(tcpJsonMessage);
97 } 92 }
@@ -102,13 +97,9 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec { @@ -102,13 +97,9 @@ public class IotTcpJsonDeviceMessageCodec implements IotDeviceMessageCodec {
102 TcpJsonMessage tcpJsonMessage = JsonUtils.parseObject(bytes, TcpJsonMessage.class); 97 TcpJsonMessage tcpJsonMessage = JsonUtils.parseObject(bytes, TcpJsonMessage.class);
103 Assert.notNull(tcpJsonMessage, "消息不能为空"); 98 Assert.notNull(tcpJsonMessage, "消息不能为空");
104 Assert.notBlank(tcpJsonMessage.getMethod(), "消息方法不能为空"); 99 Assert.notBlank(tcpJsonMessage.getMethod(), "消息方法不能为空");
105 - IotDeviceMessage iotDeviceMessage = IotDeviceMessage.of(  
106 - tcpJsonMessage.getId(),  
107 - tcpJsonMessage.getMethod(),  
108 - tcpJsonMessage.getParams(),  
109 - tcpJsonMessage.getData(),  
110 - tcpJsonMessage.getCode(),  
111 - tcpJsonMessage.getMsg()); 100 + // TODO @haohao:这个我已经改了哈。一些属性,可以放在一行,好理解一点~
  101 + IotDeviceMessage iotDeviceMessage = IotDeviceMessage.of(tcpJsonMessage.getId(), tcpJsonMessage.getMethod(),
  102 + tcpJsonMessage.getParams(), tcpJsonMessage.getData(), tcpJsonMessage.getCode(), tcpJsonMessage.getMsg());
112 iotDeviceMessage.setDeviceId(tcpJsonMessage.getDeviceId()); 103 iotDeviceMessage.setDeviceId(tcpJsonMessage.getDeviceId());
113 return iotDeviceMessage; 104 return iotDeviceMessage;
114 } 105 }
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpDownstreamSubscriber.java
@@ -27,10 +27,12 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber&lt;IotDevic @@ -27,10 +27,12 @@ public class IotTcpDownstreamSubscriber implements IotMessageSubscriber&lt;IotDevic
27 27
28 private final IotTcpUpstreamProtocol protocol; 28 private final IotTcpUpstreamProtocol protocol;
29 29
  30 + // todo @haohao:不用的变量,可以去掉哈
30 private final IotDeviceService deviceService; 31 private final IotDeviceService deviceService;
31 32
32 private final IotTcpSessionManager sessionManager; 33 private final IotTcpSessionManager sessionManager;
33 34
  35 + // TODO @haohao:lombok 简化
34 public IotTcpDownstreamSubscriber(IotTcpUpstreamProtocol protocol, 36 public IotTcpDownstreamSubscriber(IotTcpUpstreamProtocol protocol,
35 IotDeviceMessageService messageService, 37 IotDeviceMessageService messageService,
36 IotDeviceService deviceService, 38 IotDeviceService deviceService,
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/manager/IotTcpAuthManager.java
@@ -24,6 +24,7 @@ public class IotTcpAuthManager { @@ -24,6 +24,7 @@ public class IotTcpAuthManager {
24 */ 24 */
25 private final Map<NetSocket, AuthInfo> authStatusMap = new ConcurrentHashMap<>(); 25 private final Map<NetSocket, AuthInfo> authStatusMap = new ConcurrentHashMap<>();
26 26
  27 + // TODO @haohao:得考虑,一个设备连接多次?
27 /** 28 /**
28 * 设备 ID -> NetSocket 的映射(用于快速查找) 29 * 设备 ID -> NetSocket 的映射(用于快速查找)
29 */ 30 */
@@ -37,6 +38,7 @@ public class IotTcpAuthManager { @@ -37,6 +38,7 @@ public class IotTcpAuthManager {
37 */ 38 */
38 public void registerAuth(NetSocket socket, AuthInfo authInfo) { 39 public void registerAuth(NetSocket socket, AuthInfo authInfo) {
39 // 如果设备已有其他连接,先清理旧连接 40 // 如果设备已有其他连接,先清理旧连接
  41 + // TODO @haohao:是不是允许同时连接?就像 mqtt 应该也允许重复连接哈?
40 NetSocket oldSocket = deviceSocketMap.get(authInfo.getDeviceId()); 42 NetSocket oldSocket = deviceSocketMap.get(authInfo.getDeviceId());
41 if (oldSocket != null && oldSocket != socket) { 43 if (oldSocket != null && oldSocket != socket) {
42 log.info("[registerAuth][设备已有其他连接,清理旧连接] 设备 ID: {}, 旧连接: {}", 44 log.info("[registerAuth][设备已有其他连接,清理旧连接] 设备 ID: {}, 旧连接: {}",
@@ -66,6 +68,7 @@ public class IotTcpAuthManager { @@ -66,6 +68,7 @@ public class IotTcpAuthManager {
66 } 68 }
67 } 69 }
68 70
  71 + // TODO @haohao:建议暂时没用的方法,可以删除掉;整体聚焦!
69 /** 72 /**
70 * 注销设备认证信息 73 * 注销设备认证信息
71 * 74 *
@@ -158,6 +161,7 @@ public class IotTcpAuthManager { @@ -158,6 +161,7 @@ public class IotTcpAuthManager {
158 int count = authStatusMap.size(); 161 int count = authStatusMap.size();
159 authStatusMap.clear(); 162 authStatusMap.clear();
160 deviceSocketMap.clear(); 163 deviceSocketMap.clear();
  164 + // TODO @haohao:第一个括号是方法,第二个括号是明细日志;其它日志,也可以检查下哈。
161 log.info("[clearAll][清理所有认证信息] 清理数量: {}", count); 165 log.info("[clearAll][清理所有认证信息] 清理数量: {}", count);
162 } 166 }
163 167
@@ -166,6 +170,7 @@ public class IotTcpAuthManager { @@ -166,6 +170,7 @@ public class IotTcpAuthManager {
166 */ 170 */
167 @Data 171 @Data
168 public static class AuthInfo { 172 public static class AuthInfo {
  173 +
169 /** 174 /**
170 * 设备编号 175 * 设备编号
171 */ 176 */
@@ -181,6 +186,7 @@ public class IotTcpAuthManager { @@ -181,6 +186,7 @@ public class IotTcpAuthManager {
181 */ 186 */
182 private String deviceName; 187 private String deviceName;
183 188
  189 + // TODO @haohao:令牌不要存储,万一有安全问题哈;
184 /** 190 /**
185 * 认证令牌 191 * 认证令牌
186 */ 192 */
@@ -190,5 +196,7 @@ public class IotTcpAuthManager { @@ -190,5 +196,7 @@ public class IotTcpAuthManager {
190 * 客户端 ID 196 * 客户端 ID
191 */ 197 */
192 private String clientId; 198 private String clientId;
  199 +
193 } 200 }
  201 +
194 } 202 }
195 \ No newline at end of file 203 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/manager/IotTcpSessionManager.java
@@ -7,6 +7,7 @@ import org.springframework.stereotype.Component; @@ -7,6 +7,7 @@ import org.springframework.stereotype.Component;
7 import java.util.Map; 7 import java.util.Map;
8 import java.util.concurrent.ConcurrentHashMap; 8 import java.util.concurrent.ConcurrentHashMap;
9 9
  10 +// TODO @haohao:IotTcpSessionManager、IotTcpAuthManager 是不是融合哈?
10 /** 11 /**
11 * IoT 网关 TCP 会话管理器 12 * IoT 网关 TCP 会话管理器
12 * <p> 13 * <p>
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java
@@ -21,6 +21,7 @@ public class IotTcpDownstreamHandler { @@ -21,6 +21,7 @@ public class IotTcpDownstreamHandler {
21 21
22 private final IotTcpSessionManager sessionManager; 22 private final IotTcpSessionManager sessionManager;
23 23
  24 + // TODO @haohao:这个可以使用 lombok 简化构造方法
24 public IotTcpDownstreamHandler(IotDeviceMessageService messageService, 25 public IotTcpDownstreamHandler(IotDeviceMessageService messageService,
25 IotDeviceService deviceService, IotTcpSessionManager sessionManager) { 26 IotDeviceService deviceService, IotTcpSessionManager sessionManager) {
26 this.messageService = messageService; 27 this.messageService = messageService;
@@ -38,6 +39,7 @@ public class IotTcpDownstreamHandler { @@ -38,6 +39,7 @@ public class IotTcpDownstreamHandler {
38 log.info("[handle][处理下行消息] 设备 ID: {}, 方法: {}, 消息 ID: {}", 39 log.info("[handle][处理下行消息] 设备 ID: {}, 方法: {}, 消息 ID: {}",
39 message.getDeviceId(), message.getMethod(), message.getId()); 40 message.getDeviceId(), message.getMethod(), message.getId());
40 41
  42 + // TODO @haohao 1. 和 2. 可以合成 1.1 1.2 并且中间可以不空行;
41 // 1. 获取设备信息 43 // 1. 获取设备信息
42 IotDeviceRespDTO device = deviceService.getDeviceFromCache(message.getDeviceId()); 44 IotDeviceRespDTO device = deviceService.getDeviceFromCache(message.getDeviceId());
43 if (device == null) { 45 if (device == null) {
@@ -62,11 +64,12 @@ public class IotTcpDownstreamHandler { @@ -62,11 +64,12 @@ public class IotTcpDownstreamHandler {
62 } else { 64 } else {
63 log.error("[handle][下行消息发送失败] 设备 ID: {}, 方法: {}, 消息 ID: {}", 65 log.error("[handle][下行消息发送失败] 设备 ID: {}, 方法: {}, 消息 ID: {}",
64 message.getDeviceId(), message.getMethod(), message.getId()); 66 message.getDeviceId(), message.getMethod(), message.getId());
65 - } 67 + } // TODO @haohao:下面这个空行,可以考虑去掉的哈。
66 68
67 } catch (Exception e) { 69 } catch (Exception e) {
68 log.error("[handle][处理下行消息失败] 设备 ID: {}, 方法: {}, 消息内容: {}", 70 log.error("[handle][处理下行消息失败] 设备 ID: {}, 方法: {}, 消息内容: {}",
69 message.getDeviceId(), message.getMethod(), message.getParams(), e); 71 message.getDeviceId(), message.getMethod(), message.getParams(), e);
70 } 72 }
71 } 73 }
  74 +
72 } 75 }
73 \ No newline at end of file 76 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpUpstreamHandler.java
@@ -8,6 +8,7 @@ import cn.hutool.json.JSONObject; @@ -8,6 +8,7 @@ import cn.hutool.json.JSONObject;
8 import cn.hutool.json.JSONUtil; 8 import cn.hutool.json.JSONUtil;
9 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 9 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
10 import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; 10 import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
  11 +import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
11 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO; 12 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
12 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 13 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
13 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; 14 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
@@ -28,8 +29,10 @@ import lombok.extern.slf4j.Slf4j; @@ -28,8 +29,10 @@ import lombok.extern.slf4j.Slf4j;
28 @Slf4j 29 @Slf4j
29 public class IotTcpUpstreamHandler implements Handler<NetSocket> { 30 public class IotTcpUpstreamHandler implements Handler<NetSocket> {
30 31
  32 + // TODO @haohao:这两个变量,可以复用 IotTcpBinaryDeviceMessageCodec 的 TYPE
31 private static final String CODEC_TYPE_JSON = "TCP_JSON"; 33 private static final String CODEC_TYPE_JSON = "TCP_JSON";
32 private static final String CODEC_TYPE_BINARY = "TCP_BINARY"; 34 private static final String CODEC_TYPE_BINARY = "TCP_BINARY";
  35 +
33 private static final String AUTH_METHOD = "auth"; 36 private static final String AUTH_METHOD = "auth";
34 37
35 private final IotDeviceMessageService deviceMessageService; 38 private final IotDeviceMessageService deviceMessageService;
@@ -89,6 +92,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -89,6 +92,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
89 return; 92 return;
90 } 93 }
91 94
  95 + // TODO @haohao:2. 和 3. 可以合并成 2.1 2.2 ,都是异常的情况。然后 3. 可以 return 直接;
92 // 2. 获取设备信息 96 // 2. 获取设备信息
93 IotDeviceRespDTO device = deviceService.getDeviceFromCache(messageInfo.message.getDeviceId()); 97 IotDeviceRespDTO device = deviceService.getDeviceFromCache(messageInfo.message.getDeviceId());
94 if (device == null) { 98 if (device == null) {
@@ -114,12 +118,13 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -114,12 +118,13 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
114 private void handleAuthRequest(String clientId, IotDeviceMessage message, NetSocket socket, String codecType) { 118 private void handleAuthRequest(String clientId, IotDeviceMessage message, NetSocket socket, String codecType) {
115 try { 119 try {
116 // 1. 验证认证请求 120 // 1. 验证认证请求
  121 + // TODO @haohao:ObjUtil.notEquals。减少取反
117 if (!AUTH_METHOD.equals(message.getMethod())) { 122 if (!AUTH_METHOD.equals(message.getMethod())) {
118 sendError(socket, message.getRequestId(), "请先进行认证", codecType); 123 sendError(socket, message.getRequestId(), "请先进行认证", codecType);
119 return; 124 return;
120 } 125 }
121 126
122 - // 2. 解析认证参数 127 + // 2. 解析认证参数 // TODO @haohao:1. 和 2. 可以合并成 1.1 1.2 都是参数校验
123 AuthParams authParams = parseAuthParams(message.getParams()); 128 AuthParams authParams = parseAuthParams(message.getParams());
124 if (authParams == null) { 129 if (authParams == null) {
125 sendError(socket, message.getRequestId(), "认证参数不完整", codecType); 130 sendError(socket, message.getRequestId(), "认证参数不完整", codecType);
@@ -127,6 +132,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -127,6 +132,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
127 } 132 }
128 133
129 // 3. 执行认证流程 134 // 3. 执行认证流程
  135 + // TODO @haohao:成功失败、都大哥日志,会不会更好哈?
130 if (performAuthentication(authParams, socket, message.getRequestId(), codecType)) { 136 if (performAuthentication(authParams, socket, message.getRequestId(), codecType)) {
131 log.info("[handleAuthRequest][认证成功] 客户端 ID: {}, username: {}", clientId, authParams.username); 137 log.info("[handleAuthRequest][认证成功] 客户端 ID: {}, username: {}", clientId, authParams.username);
132 } 138 }
@@ -157,6 +163,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -157,6 +163,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
157 /** 163 /**
158 * 解码消息 164 * 解码消息
159 */ 165 */
  166 + // TODO @haohao:是不是还是直接管理后台配置协议,然后直接使用就好啦。暂时不考虑动态解析哈。保持一致,降低理解成本哈。
160 private MessageInfo decodeMessage(Buffer buffer) { 167 private MessageInfo decodeMessage(Buffer buffer) {
161 try { 168 try {
162 String rawData = buffer.toString(); 169 String rawData = buffer.toString();
@@ -172,6 +179,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -172,6 +179,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
172 /** 179 /**
173 * 执行认证 180 * 执行认证
174 */ 181 */
  182 + // TODO @haohao:下面的 1. 2. 可以合并下,本质也是校验哈。
175 private boolean performAuthentication(AuthParams authParams, NetSocket socket, String requestId, String codecType) { 183 private boolean performAuthentication(AuthParams authParams, NetSocket socket, String requestId, String codecType) {
176 // 1. 执行认证 184 // 1. 执行认证
177 if (!authenticateDevice(authParams)) { 185 if (!authenticateDevice(authParams)) {
@@ -202,7 +210,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -202,7 +210,6 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
202 deviceMessageService.sendDeviceMessage(onlineMessage, deviceInfo.getProductKey(), deviceInfo.getDeviceName(), 210 deviceMessageService.sendDeviceMessage(onlineMessage, deviceInfo.getProductKey(), deviceInfo.getDeviceName(),
203 serverId); 211 serverId);
204 sendSuccess(socket, requestId, "认证成功", codecType); 212 sendSuccess(socket, requestId, "认证成功", codecType);
205 -  
206 return true; 213 return true;
207 } 214 }
208 215
@@ -252,8 +259,9 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -252,8 +259,9 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
252 * 判断是否为 JSON 格式 259 * 判断是否为 JSON 格式
253 */ 260 */
254 private boolean isJsonFormat(String data) { 261 private boolean isJsonFormat(String data) {
255 - if (StrUtil.isBlank(data)) 262 + if (StrUtil.isBlank(data)) {
256 return false; 263 return false;
  264 + }
257 String trimmed = data.trim(); 265 String trimmed = data.trim();
258 return (trimmed.startsWith("{") && trimmed.endsWith("}")) || (trimmed.startsWith("[") && trimmed.endsWith("]")); 266 return (trimmed.startsWith("{") && trimmed.endsWith("}")) || (trimmed.startsWith("[") && trimmed.endsWith("]"));
259 } 267 }
@@ -262,15 +270,14 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -262,15 +270,14 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
262 * 解析认证参数 270 * 解析认证参数
263 */ 271 */
264 private AuthParams parseAuthParams(Object params) { 272 private AuthParams parseAuthParams(Object params) {
265 - if (params == null) 273 + if (params == null) {
266 return null; 274 return null;
267 - 275 + }
268 JSONObject paramsJson = params instanceof JSONObject ? (JSONObject) params 276 JSONObject paramsJson = params instanceof JSONObject ? (JSONObject) params
269 : JSONUtil.parseObj(params.toString()); 277 : JSONUtil.parseObj(params.toString());
270 String clientId = paramsJson.getStr("clientId"); 278 String clientId = paramsJson.getStr("clientId");
271 String username = paramsJson.getStr("username"); 279 String username = paramsJson.getStr("username");
272 String password = paramsJson.getStr("password"); 280 String password = paramsJson.getStr("password");
273 -  
274 return StrUtil.hasBlank(clientId, username, password) ? null : new AuthParams(clientId, username, password); 281 return StrUtil.hasBlank(clientId, username, password) ? null : new AuthParams(clientId, username, password);
275 } 282 }
276 283
@@ -278,11 +285,8 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -278,11 +285,8 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
278 * 认证设备 285 * 认证设备
279 */ 286 */
280 private boolean authenticateDevice(AuthParams authParams) { 287 private boolean authenticateDevice(AuthParams authParams) {
281 - CommonResult<Boolean> result = deviceApi  
282 - .authDevice(new cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO()  
283 - .setClientId(authParams.clientId)  
284 - .setUsername(authParams.username)  
285 - .setPassword(authParams.password)); 288 + CommonResult<Boolean> result = deviceApi.authDevice(new IotDeviceAuthReqDTO()
  289 + .setClientId(authParams.clientId).setUsername(authParams.username).setPassword(authParams.password));
286 return result.isSuccess() && result.getData(); 290 return result.isSuccess() && result.getData();
287 } 291 }
288 292
@@ -291,6 +295,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -291,6 +295,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
291 */ 295 */
292 private void registerAuthInfo(NetSocket socket, IotDeviceRespDTO device, IotDeviceAuthUtils.DeviceInfo deviceInfo, 296 private void registerAuthInfo(NetSocket socket, IotDeviceRespDTO device, IotDeviceAuthUtils.DeviceInfo deviceInfo,
293 String token, String clientId) { 297 String token, String clientId) {
  298 + // TODO @haohao:可以链式调用;
294 IotTcpAuthManager.AuthInfo auth = new IotTcpAuthManager.AuthInfo(); 299 IotTcpAuthManager.AuthInfo auth = new IotTcpAuthManager.AuthInfo();
295 auth.setDeviceId(device.getId()); 300 auth.setDeviceId(device.getId());
296 auth.setProductKey(deviceInfo.getProductKey()); 301 auth.setProductKey(deviceInfo.getProductKey());
@@ -316,6 +321,8 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -316,6 +321,8 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
316 sendResponse(socket, true, message, requestId, codecType); 321 sendResponse(socket, true, message, requestId, codecType);
317 } 322 }
318 323
  324 + // TODO @haohao:使用 lombok,方便 jdk8 兼容
  325 +
319 /** 326 /**
320 * 认证参数 327 * 认证参数
321 */ 328 */
@@ -327,4 +334,5 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -327,4 +334,5 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
327 */ 334 */
328 private record MessageInfo(IotDeviceMessage message, String codecType) { 335 private record MessageInfo(IotDeviceMessage message, String codecType) {
329 } 336 }
  337 +
330 } 338 }
331 \ No newline at end of file 339 \ No newline at end of file