Commit d9a08094d9f9640f94f7b2e3cb94961019b8efef

Authored by YunaiV
1 parent 3db18709

feat(iot):【协议改造】websocket 初步改造(50%)

Showing 19 changed files with 518 additions and 298 deletions
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/IotProtocolManager.java
@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.gateway.protocol.coap.IotCoapProtocol; @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.gateway.protocol.coap.IotCoapProtocol;
8 import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpProtocol; 8 import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpProtocol;
9 import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpProtocol; 9 import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpProtocol;
10 import cn.iocoder.yudao.module.iot.gateway.protocol.udp.IotUdpProtocol; 10 import cn.iocoder.yudao.module.iot.gateway.protocol.udp.IotUdpProtocol;
11 -import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.IotWebSocketUpstreamProtocol; 11 +import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.IotWebSocketProtocol;
12 import lombok.Getter; 12 import lombok.Getter;
13 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
14 import org.springframework.context.SmartLifecycle; 14 import org.springframework.context.SmartLifecycle;
@@ -158,8 +158,8 @@ public class IotProtocolManager implements SmartLifecycle { @@ -158,8 +158,8 @@ public class IotProtocolManager implements SmartLifecycle {
158 * @param config 协议实例配置 158 * @param config 协议实例配置
159 * @return WebSocket 协议实例 159 * @return WebSocket 协议实例
160 */ 160 */
161 - private IotWebSocketUpstreamProtocol createWebSocketProtocol(IotGatewayProperties.ProtocolInstanceProperties config) {  
162 - return new IotWebSocketUpstreamProtocol(config); 161 + private IotWebSocketProtocol createWebSocketProtocol(IotGatewayProperties.ProtocolInstanceProperties config) {
  162 + return new IotWebSocketProtocol(config);
163 } 163 }
164 164
165 } 165 }
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpProtocol.java
@@ -57,6 +57,10 @@ public class IotTcpProtocol implements IotProtocol { @@ -57,6 +57,10 @@ public class IotTcpProtocol implements IotProtocol {
57 * TCP 服务器 57 * TCP 服务器
58 */ 58 */
59 private NetServer tcpServer; 59 private NetServer tcpServer;
  60 + /**
  61 + * TCP 连接管理器
  62 + */
  63 + private final IotTcpConnectionManager connectionManager;
60 64
61 /** 65 /**
62 * 下行消息订阅者 66 * 下行消息订阅者
@@ -67,17 +71,11 @@ public class IotTcpProtocol implements IotProtocol { @@ -67,17 +71,11 @@ public class IotTcpProtocol implements IotProtocol {
67 * 消息序列化器 71 * 消息序列化器
68 */ 72 */
69 private final IotMessageSerializer serializer; 73 private final IotMessageSerializer serializer;
70 -  
71 /** 74 /**
72 * TCP 帧编解码器 75 * TCP 帧编解码器
73 */ 76 */
74 private final IotTcpFrameCodec frameCodec; 77 private final IotTcpFrameCodec frameCodec;
75 78
76 - /**  
77 - * TCP 连接管理器  
78 - */  
79 - private final IotTcpConnectionManager connectionManager;  
80 -  
81 public IotTcpProtocol(ProtocolInstanceProperties properties) { 79 public IotTcpProtocol(ProtocolInstanceProperties properties) {
82 IotTcpConfig tcpConfig = properties.getTcp(); 80 IotTcpConfig tcpConfig = properties.getTcp();
83 Assert.notNull(tcpConfig, "TCP 协议配置(tcp)不能为空"); 81 Assert.notNull(tcpConfig, "TCP 协议配置(tcp)不能为空");
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/codec/length/IotTcpLengthFieldFrameCodec.java
@@ -29,6 +29,11 @@ import java.util.concurrent.atomic.AtomicReference; @@ -29,6 +29,11 @@ import java.util.concurrent.atomic.AtomicReference;
29 @Slf4j 29 @Slf4j
30 public class IotTcpLengthFieldFrameCodec implements IotTcpFrameCodec { 30 public class IotTcpLengthFieldFrameCodec implements IotTcpFrameCodec {
31 31
  32 + /**
  33 + * 最大帧长度(64KB),防止 DoS 攻击
  34 + */
  35 + private static final int MAX_FRAME_LENGTH = 65536;
  36 +
32 private final int lengthFieldOffset; 37 private final int lengthFieldOffset;
33 private final int lengthFieldLength; 38 private final int lengthFieldLength;
34 private final int lengthAdjustment; 39 private final int lengthAdjustment;
@@ -60,6 +65,7 @@ public class IotTcpLengthFieldFrameCodec implements IotTcpFrameCodec { @@ -60,6 +65,7 @@ public class IotTcpLengthFieldFrameCodec implements IotTcpFrameCodec {
60 public RecordParser createDecodeParser(Handler<Buffer> handler) { 65 public RecordParser createDecodeParser(Handler<Buffer> handler) {
61 // 创建状态机:先读取头部,再读取消息体 66 // 创建状态机:先读取头部,再读取消息体
62 RecordParser parser = RecordParser.newFixed(headerLength); 67 RecordParser parser = RecordParser.newFixed(headerLength);
  68 + parser.maxRecordSize(MAX_FRAME_LENGTH); // 设置最大记录大小,防止 DoS 攻击
63 final AtomicReference<Integer> bodyLength = new AtomicReference<>(null); // 消息体长度,null 表示读取头部阶段 69 final AtomicReference<Integer> bodyLength = new AtomicReference<>(null); // 消息体长度,null 表示读取头部阶段
64 final AtomicReference<Buffer> headerBuffer = new AtomicReference<>(null); // 头部消息 70 final AtomicReference<Buffer> headerBuffer = new AtomicReference<>(null); // 头部消息
65 71
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/handler/upstream/IotTcpUpstreamHandler.java
@@ -77,7 +77,9 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -77,7 +77,9 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
77 } 77 }
78 78
79 @Override 79 @Override
  80 + @SuppressWarnings("DuplicatedCode")
80 public void handle(NetSocket socket) { 81 public void handle(NetSocket socket) {
  82 + // TODO @AI:clientId 去掉;其它模块也看看,怎么去掉下看看;
81 String clientId = IdUtil.simpleUUID(); 83 String clientId = IdUtil.simpleUUID();
82 log.debug("[handle][设备连接,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress()); 84 log.debug("[handle][设备连接,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress());
83 85
@@ -92,9 +94,10 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -92,9 +94,10 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
92 }); 94 });
93 95
94 // 2.1 设置消息处理器 96 // 2.1 设置消息处理器
  97 + // TODO @AI:去掉 clientId;
95 Handler<Buffer> messageHandler = buffer -> { 98 Handler<Buffer> messageHandler = buffer -> {
96 try { 99 try {
97 - processMessage(clientId, buffer, socket); 100 + processMessage(buffer, socket);
98 } catch (Exception e) { 101 } catch (Exception e) {
99 log.error("[handle][消息处理失败,客户端 ID: {},地址: {}]", 102 log.error("[handle][消息处理失败,客户端 ID: {},地址: {}]",
100 clientId, socket.remoteAddress(), e); 103 clientId, socket.remoteAddress(), e);
@@ -110,11 +113,10 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -110,11 +113,10 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
110 /** 113 /**
111 * 处理消息 114 * 处理消息
112 * 115 *
113 - * @param clientId 客户端 ID  
114 * @param buffer 消息 116 * @param buffer 消息
115 * @param socket 网络连接 117 * @param socket 网络连接
116 */ 118 */
117 - private void processMessage(String clientId, Buffer buffer, NetSocket socket) { 119 + private void processMessage(Buffer buffer, NetSocket socket) {
118 IotDeviceMessage message = null; 120 IotDeviceMessage message = null;
119 try { 121 try {
120 // 1. 反序列化消息 122 // 1. 反序列化消息
@@ -127,29 +129,29 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -127,29 +129,29 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
127 // 2. 根据消息类型路由处理 129 // 2. 根据消息类型路由处理
128 if (AUTH_METHOD.equals(message.getMethod())) { 130 if (AUTH_METHOD.equals(message.getMethod())) {
129 // 认证请求 131 // 认证请求
130 - handleAuthenticationRequest(clientId, message, socket); 132 + handleAuthenticationRequest(message, socket);
131 } else if (IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod().equals(message.getMethod())) { 133 } else if (IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod().equals(message.getMethod())) {
132 // 设备动态注册请求 134 // 设备动态注册请求
133 - handleRegisterRequest(clientId, message, socket); 135 + handleRegisterRequest(message, socket);
134 } else { 136 } else {
135 // 业务消息 137 // 业务消息
136 - handleBusinessRequest(clientId, message, socket); 138 + handleBusinessRequest(null, message, socket);
137 } 139 }
138 } catch (ServiceException e) { 140 } catch (ServiceException e) {
139 // 业务异常,返回对应的错误码和错误信息 141 // 业务异常,返回对应的错误码和错误信息
140 - log.warn("[processMessage][业务异常,客户端 ID: {},错误: {}]", clientId, e.getMessage()); 142 + log.warn("[processMessage][业务异常,客户端 ID: {},错误: {}]", null, e.getMessage());
141 String requestId = message != null ? message.getRequestId() : null; 143 String requestId = message != null ? message.getRequestId() : null;
142 String method = message != null ? message.getMethod() : null; 144 String method = message != null ? message.getMethod() : null;
143 sendErrorResponse(socket, requestId, method, e.getCode(), e.getMessage()); 145 sendErrorResponse(socket, requestId, method, e.getCode(), e.getMessage());
144 } catch (IllegalArgumentException e) { 146 } catch (IllegalArgumentException e) {
145 // 参数校验失败,返回 400 147 // 参数校验失败,返回 400
146 - log.warn("[processMessage][参数校验失败,客户端 ID: {},错误: {}]", clientId, e.getMessage()); 148 + log.warn("[processMessage][参数校验失败,客户端 ID: {},错误: {}]", null, e.getMessage());
147 String requestId = message != null ? message.getRequestId() : null; 149 String requestId = message != null ? message.getRequestId() : null;
148 String method = message != null ? message.getMethod() : null; 150 String method = message != null ? message.getMethod() : null;
149 sendErrorResponse(socket, requestId, method, BAD_REQUEST.getCode(), e.getMessage()); 151 sendErrorResponse(socket, requestId, method, BAD_REQUEST.getCode(), e.getMessage());
150 } catch (Exception e) { 152 } catch (Exception e) {
151 // 其他异常,返回 500,并重新抛出让上层关闭连接 153 // 其他异常,返回 500,并重新抛出让上层关闭连接
152 - log.error("[processMessage][处理消息失败,客户端 ID: {}]", clientId, e); 154 + log.error("[processMessage][处理消息失败,客户端 ID: {}]", null, e);
153 String requestId = message != null ? message.getRequestId() : null; 155 String requestId = message != null ? message.getRequestId() : null;
154 String method = message != null ? message.getMethod() : null; 156 String method = message != null ? message.getMethod() : null;
155 sendErrorResponse(socket, requestId, method, 157 sendErrorResponse(socket, requestId, method,
@@ -161,12 +163,11 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -161,12 +163,11 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
161 /** 163 /**
162 * 处理认证请求 164 * 处理认证请求
163 * 165 *
164 - * @param clientId 客户端 ID  
165 * @param message 消息信息 166 * @param message 消息信息
166 * @param socket 网络连接 167 * @param socket 网络连接
167 */ 168 */
168 @SuppressWarnings("DuplicatedCode") 169 @SuppressWarnings("DuplicatedCode")
169 - private void handleAuthenticationRequest(String clientId, IotDeviceMessage message, NetSocket socket) { 170 + private void handleAuthenticationRequest(IotDeviceMessage message, NetSocket socket) {
170 // 1. 解析认证参数 171 // 1. 解析认证参数
171 IotDeviceAuthReqDTO authParams = JsonUtils.convertObject(message.getParams(), IotDeviceAuthReqDTO.class); 172 IotDeviceAuthReqDTO authParams = JsonUtils.convertObject(message.getParams(), IotDeviceAuthReqDTO.class);
172 Assert.notNull(authParams, "认证参数不能为空"); 173 Assert.notNull(authParams, "认证参数不能为空");
@@ -198,13 +199,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -198,13 +199,12 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
198 /** 199 /**
199 * 处理设备动态注册请求(一型一密,不需要认证) 200 * 处理设备动态注册请求(一型一密,不需要认证)
200 * 201 *
201 - * @param clientId 客户端 ID  
202 * @param message 消息信息 202 * @param message 消息信息
203 * @param socket 网络连接 203 * @param socket 网络连接
204 * @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">阿里云 - 一型一密</a> 204 * @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">阿里云 - 一型一密</a>
205 */ 205 */
206 @SuppressWarnings("DuplicatedCode") 206 @SuppressWarnings("DuplicatedCode")
207 - private void handleRegisterRequest(String clientId, IotDeviceMessage message, NetSocket socket) { 207 + private void handleRegisterRequest(IotDeviceMessage message, NetSocket socket) {
208 // 1. 解析注册参数 208 // 1. 解析注册参数
209 IotDeviceRegisterReqDTO params = JsonUtils.convertObject(message.getParams(), IotDeviceRegisterReqDTO.class); 209 IotDeviceRegisterReqDTO params = JsonUtils.convertObject(message.getParams(), IotDeviceRegisterReqDTO.class);
210 Assert.notNull(params, "注册参数不能为空"); 210 Assert.notNull(params, "注册参数不能为空");
@@ -218,7 +218,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; { @@ -218,7 +218,7 @@ public class IotTcpUpstreamHandler implements Handler&lt;NetSocket&gt; {
218 // 3. 发送成功响应 218 // 3. 发送成功响应
219 sendSuccessResponse(socket, message.getRequestId(), 219 sendSuccessResponse(socket, message.getRequestId(),
220 IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod(), result.getData()); 220 IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod(), result.getData());
221 - log.info("[handleRegisterRequest][注册成功,客户端 ID: {},设备名: {}]", clientId, params.getDeviceName()); 221 + log.info("[handleRegisterRequest][注册成功,客户端 ID: {},设备名: {}]", null, params.getDeviceName());
222 } 222 }
223 223
224 /** 224 /**
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/udp/IotUdpProtocol.java
@@ -55,6 +55,10 @@ public class IotUdpProtocol implements IotProtocol { @@ -55,6 +55,10 @@ public class IotUdpProtocol implements IotProtocol {
55 */ 55 */
56 @Getter 56 @Getter
57 private DatagramSocket udpSocket; 57 private DatagramSocket udpSocket;
  58 + /**
  59 + * UDP 会话管理器
  60 + */
  61 + private final IotUdpSessionManager sessionManager;
58 62
59 /** 63 /**
60 * 下行消息订阅者 64 * 下行消息订阅者
@@ -66,11 +70,6 @@ public class IotUdpProtocol implements IotProtocol { @@ -66,11 +70,6 @@ public class IotUdpProtocol implements IotProtocol {
66 */ 70 */
67 private final IotMessageSerializer serializer; 71 private final IotMessageSerializer serializer;
68 72
69 - /**  
70 - * UDP 会话管理器  
71 - */  
72 - private final IotUdpSessionManager sessionManager;  
73 -  
74 public IotUdpProtocol(ProtocolInstanceProperties properties) { 73 public IotUdpProtocol(ProtocolInstanceProperties properties) {
75 IotUdpConfig udpConfig = properties.getUdp(); 74 IotUdpConfig udpConfig = properties.getUdp();
76 Assert.notNull(udpConfig, "UDP 协议配置(udp)不能为空"); 75 Assert.notNull(udpConfig, "UDP 协议配置(udp)不能为空");
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/IotWebSocketConfig.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.protocol.websocket;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import jakarta.validation.constraints.NotNull;
  5 +import lombok.Data;
  6 +
  7 +/**
  8 + * IoT WebSocket 协议配置
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +public class IotWebSocketConfig {
  14 +
  15 + /**
  16 + * WebSocket 路径(默认:/ws)
  17 + */
  18 + @NotEmpty(message = "WebSocket 路径不能为空")
  19 + private String path = "/ws";
  20 +
  21 + /**
  22 + * 最大消息大小(字节,默认 64KB)
  23 + */
  24 + @NotNull(message = "最大消息大小不能为空")
  25 + private Integer maxMessageSize = 65536;
  26 + /**
  27 + * 最大帧大小(字节,默认 64KB)
  28 + */
  29 + @NotNull(message = "最大帧大小不能为空")
  30 + private Integer maxFrameSize = 65536;
  31 +
  32 + /**
  33 + * 空闲超时时间(秒,默认 60)
  34 + */
  35 + @NotNull(message = "空闲超时时间不能为空")
  36 + private Integer idleTimeoutSeconds = 60;
  37 +
  38 + /**
  39 + * 是否启用 SSL(wss://)
  40 + */
  41 + @NotNull(message = "是否启用 SSL 不能为空")
  42 + private Boolean sslEnabled = false;
  43 +
  44 + /**
  45 + * SSL 证书路径
  46 + */
  47 + private String sslCertPath;
  48 +
  49 + /**
  50 + * SSL 私钥路径
  51 + */
  52 + private String sslKeyPath;
  53 +
  54 +}
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/IotWebSocketProtocol.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.protocol.websocket;
  2 +
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import cn.hutool.extra.spring.SpringUtil;
  5 +import cn.iocoder.yudao.module.iot.core.enums.IotProtocolTypeEnum;
  6 +import cn.iocoder.yudao.module.iot.core.enums.IotSerializeTypeEnum;
  7 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
  8 +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
  9 +import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties.ProtocolInstanceProperties;
  10 +import cn.iocoder.yudao.module.iot.gateway.protocol.IotProtocol;
  11 +import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.handler.downstream.IotWebSocketDownstreamSubscriber;
  12 +import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager.IotWebSocketConnectionManager;
  13 +import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.handler.downstream.IotWebSocketDownstreamHandler;
  14 +import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.handler.upstream.IotWebSocketUpstreamHandler;
  15 +import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializer;
  16 +import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializerManager;
  17 +import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService;
  18 +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
  19 +import io.vertx.core.Vertx;
  20 +import io.vertx.core.http.HttpServer;
  21 +import io.vertx.core.http.HttpServerOptions;
  22 +import io.vertx.core.net.PemKeyCertOptions;
  23 +import lombok.Getter;
  24 +import lombok.extern.slf4j.Slf4j;
  25 +import org.springframework.util.Assert;
  26 +
  27 +// TODO @AI:注释调整下,参考 IotTcpProtocol
  28 +/**
  29 + * IoT 网关 WebSocket 协议:接收设备上行消息
  30 + *
  31 + * @author 芋道源码
  32 + */
  33 +@Slf4j
  34 +public class IotWebSocketProtocol implements IotProtocol {
  35 +
  36 + /**
  37 + * 协议配置
  38 + */
  39 + private final ProtocolInstanceProperties properties;
  40 + /**
  41 + * 服务器 ID(用于消息追踪,全局唯一)
  42 + */
  43 + @Getter
  44 + private final String serverId;
  45 +
  46 + /**
  47 + * 运行状态
  48 + */
  49 + @Getter
  50 + private volatile boolean running = false;
  51 +
  52 + /**
  53 + * Vert.x 实例
  54 + */
  55 + private Vertx vertx;
  56 + /**
  57 + * WebSocket 服务器
  58 + */
  59 + private HttpServer httpServer;
  60 + /**
  61 + * WebSocket 连接管理器
  62 + */
  63 + private final IotWebSocketConnectionManager connectionManager;
  64 +
  65 + // TODO @AI:可以不用这个变量,从 properties 里面获取
  66 + /**
  67 + * WebSocket 配置
  68 + */
  69 + private final IotWebSocketConfig wsConfig;
  70 +
  71 + /**
  72 + * 下行消息订阅者
  73 + */
  74 + private final IotWebSocketDownstreamSubscriber downstreamSubscriber;
  75 +
  76 + /**
  77 + * 消息序列化器
  78 + */
  79 + private final IotMessageSerializer serializer;
  80 +
  81 + private final IotDeviceService deviceService;
  82 + private final IotDeviceMessageService messageService;
  83 +
  84 + public IotWebSocketProtocol(ProtocolInstanceProperties properties) {
  85 + Assert.notNull(properties, "协议实例配置不能为空");
  86 + Assert.notNull(properties.getWebsocket(), "WebSocket 协议配置(websocket)不能为空");
  87 + this.properties = properties;
  88 + this.wsConfig = properties.getWebsocket();
  89 + this.serverId = IotDeviceMessageUtils.generateServerId(properties.getPort());
  90 +
  91 + // 初始化序列化器
  92 + IotSerializeTypeEnum serializeType = IotSerializeTypeEnum.of(properties.getSerialize());
  93 + Assert.notNull(serializeType, "不支持的序列化类型:" + properties.getSerialize());
  94 + IotMessageSerializerManager serializerManager = SpringUtil.getBean(IotMessageSerializerManager.class);
  95 + this.serializer = serializerManager.get(serializeType);
  96 +
  97 + // 初始化基础依赖
  98 + this.deviceService = SpringUtil.getBean(IotDeviceService.class);
  99 + this.messageService = SpringUtil.getBean(IotDeviceMessageService.class);
  100 + this.connectionManager = new IotWebSocketConnectionManager();
  101 +
  102 + // 初始化下行消息订阅者
  103 + IotMessageBus messageBus = SpringUtil.getBean(IotMessageBus.class);
  104 + IotWebSocketDownstreamHandler downstreamHandler = new IotWebSocketDownstreamHandler(serializer, connectionManager);
  105 + this.downstreamSubscriber = new IotWebSocketDownstreamSubscriber(this, downstreamHandler, messageBus);
  106 + }
  107 +
  108 + @Override
  109 + public String getId() {
  110 + return properties.getId();
  111 + }
  112 +
  113 + @Override
  114 + public IotProtocolTypeEnum getType() {
  115 + return IotProtocolTypeEnum.WEBSOCKET;
  116 + }
  117 +
  118 + @Override
  119 + @SuppressWarnings("deprecation")
  120 + public void start() {
  121 + if (running) {
  122 + log.warn("[start][IoT WebSocket 协议 {} 已经在运行中]", getId());
  123 + return;
  124 + }
  125 +
  126 + // 1.1 创建 Vertx 实例
  127 + this.vertx = Vertx.vertx();
  128 +
  129 + // 1.2 创建服务器选项
  130 + HttpServerOptions options = new HttpServerOptions()
  131 + .setPort(properties.getPort())
  132 + .setIdleTimeout(wsConfig.getIdleTimeoutSeconds())
  133 + .setMaxWebSocketFrameSize(wsConfig.getMaxFrameSize())
  134 + .setMaxWebSocketMessageSize(wsConfig.getMaxMessageSize());
  135 + if (Boolean.TRUE.equals(wsConfig.getSslEnabled())) {
  136 + PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions()
  137 + .setKeyPath(wsConfig.getSslKeyPath())
  138 + .setCertPath(wsConfig.getSslCertPath());
  139 + options.setSsl(true).setKeyCertOptions(pemKeyCertOptions);
  140 + }
  141 +
  142 + // 1.3 创建服务器并设置 WebSocket 处理器
  143 + httpServer = vertx.createHttpServer(options);
  144 + httpServer.webSocketHandler(socket -> {
  145 + // 验证路径
  146 + if (ObjUtil.notEqual(wsConfig.getPath(), socket.path())) {
  147 + log.warn("[webSocketHandler][WebSocket 路径不匹配,拒绝连接,路径: {},期望: {}]",
  148 + socket.path(), wsConfig.getPath());
  149 + socket.reject();
  150 + return;
  151 + }
  152 + // 创建上行处理器
  153 + IotWebSocketUpstreamHandler handler = new IotWebSocketUpstreamHandler(this,
  154 + messageService, deviceService, connectionManager, serializer);
  155 + handler.handle(socket);
  156 + });
  157 +
  158 + // 1.4 启动服务器
  159 + try {
  160 + httpServer.listen().result();
  161 + running = true;
  162 + log.info("[start][IoT WebSocket 协议 {} 启动成功,端口:{},路径:{},serverId:{}]",
  163 + getId(), properties.getPort(), wsConfig.getPath(), serverId);
  164 +
  165 + // 2. 启动下行消息订阅者
  166 + downstreamSubscriber.start();
  167 + } catch (Exception e) {
  168 + log.error("[start][IoT WebSocket 协议 {} 启动失败]", getId(), e);
  169 + if (httpServer != null) {
  170 + httpServer.close();
  171 + httpServer = null;
  172 + }
  173 + if (vertx != null) {
  174 + vertx.close();
  175 + vertx = null;
  176 + }
  177 + throw e;
  178 + }
  179 + }
  180 +
  181 + @Override
  182 + public void stop() {
  183 + if (!running) {
  184 + return;
  185 + }
  186 + // 1. 停止下行消息订阅者
  187 + try {
  188 + downstreamSubscriber.stop();
  189 + log.info("[stop][IoT WebSocket 协议 {} 下行消息订阅者已停止]", getId());
  190 + } catch (Exception e) {
  191 + log.error("[stop][IoT WebSocket 协议 {} 下行消息订阅者停止失败]", getId(), e);
  192 + }
  193 +
  194 + // 2.1 关闭 WebSocket 服务器
  195 + if (httpServer != null) {
  196 + try {
  197 + httpServer.close().result();
  198 + log.info("[stop][IoT WebSocket 协议 {} 服务器已停止]", getId());
  199 + } catch (Exception e) {
  200 + log.error("[stop][IoT WebSocket 协议 {} 服务器停止失败]", getId(), e);
  201 + }
  202 + httpServer = null;
  203 + }
  204 + // 2.2 关闭 Vertx 实例
  205 + if (vertx != null) {
  206 + try {
  207 + vertx.close().result();
  208 + log.info("[stop][IoT WebSocket 协议 {} Vertx 已关闭]", getId());
  209 + } catch (Exception e) {
  210 + log.error("[stop][IoT WebSocket 协议 {} Vertx 关闭失败]", getId(), e);
  211 + }
  212 + vertx = null;
  213 + }
  214 + running = false;
  215 + log.info("[stop][IoT WebSocket 协议 {} 已停止]", getId());
  216 + }
  217 +
  218 +}
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/IotWebSocketUpstreamProtocol.java deleted
1 -package cn.iocoder.yudao.module.iot.gateway.protocol.websocket;  
2 -  
3 -import cn.hutool.core.util.ObjUtil;  
4 -import cn.iocoder.yudao.module.iot.core.enums.IotProtocolTypeEnum;  
5 -import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;  
6 -import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;  
7 -import cn.iocoder.yudao.module.iot.gateway.protocol.IotProtocol;  
8 -import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager.IotWebSocketConnectionManager;  
9 -import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.router.IotWebSocketUpstreamHandler;  
10 -import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService;  
11 -import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;  
12 -import io.vertx.core.Vertx;  
13 -import io.vertx.core.http.HttpServer;  
14 -import io.vertx.core.http.HttpServerOptions;  
15 -import io.vertx.core.net.PemKeyCertOptions;  
16 -import jakarta.annotation.PostConstruct;  
17 -import jakarta.annotation.PreDestroy;  
18 -import lombok.Getter;  
19 -import lombok.extern.slf4j.Slf4j;  
20 -  
21 -/**  
22 - * IoT 网关 WebSocket 协议:接收设备上行消息  
23 - *  
24 - * @author 芋道源码  
25 - */  
26 -@Slf4j  
27 -public class IotWebSocketUpstreamProtocol implements IotProtocol {  
28 -  
29 - private static final String ID = "websocket";  
30 -  
31 - private final IotGatewayProperties.WebSocketProperties wsProperties;  
32 -  
33 - private final IotDeviceService deviceService;  
34 -  
35 - private final IotDeviceMessageService messageService;  
36 -  
37 - private final IotWebSocketConnectionManager connectionManager;  
38 -  
39 - private final Vertx vertx;  
40 -  
41 - @Getter  
42 - private final String serverId;  
43 -  
44 - private HttpServer httpServer;  
45 -  
46 - private volatile boolean running = false;  
47 -  
48 - public IotWebSocketUpstreamProtocol(IotGatewayProperties.WebSocketProperties wsProperties,  
49 - IotDeviceService deviceService,  
50 - IotDeviceMessageService messageService,  
51 - IotWebSocketConnectionManager connectionManager,  
52 - Vertx vertx) {  
53 - this.wsProperties = wsProperties;  
54 - this.deviceService = deviceService;  
55 - this.messageService = messageService;  
56 - this.connectionManager = connectionManager;  
57 - this.vertx = vertx;  
58 - this.serverId = IotDeviceMessageUtils.generateServerId(wsProperties.getPort());  
59 - }  
60 -  
61 - @Override  
62 - public String getId() {  
63 - return ID;  
64 - }  
65 -  
66 - @Override  
67 - public IotProtocolTypeEnum getType() {  
68 - return IotProtocolTypeEnum.WEBSOCKET;  
69 - }  
70 -  
71 - @Override  
72 - @PostConstruct  
73 - @SuppressWarnings("deprecation")  
74 - public void start() {  
75 - // 1.1 创建服务器选项  
76 - HttpServerOptions options = new HttpServerOptions()  
77 - .setPort(wsProperties.getPort())  
78 - .setIdleTimeout(wsProperties.getIdleTimeoutSeconds())  
79 - .setMaxWebSocketFrameSize(wsProperties.getMaxFrameSize())  
80 - .setMaxWebSocketMessageSize(wsProperties.getMaxMessageSize());  
81 - // 1.2 配置 SSL(如果启用)  
82 - if (Boolean.TRUE.equals(wsProperties.getSslEnabled())) {  
83 - PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions()  
84 - .setKeyPath(wsProperties.getSslKeyPath())  
85 - .setCertPath(wsProperties.getSslCertPath());  
86 - options.setSsl(true).setKeyCertOptions(pemKeyCertOptions);  
87 - }  
88 -  
89 - // 2. 创建服务器并设置 WebSocket 处理器  
90 - httpServer = vertx.createHttpServer(options);  
91 - httpServer.webSocketHandler(socket -> {  
92 - // 验证路径  
93 - if (ObjUtil.notEqual(wsProperties.getPath(), socket.path())) {  
94 - log.warn("[webSocketHandler][WebSocket 路径不匹配,拒绝连接,路径: {},期望: {}]",  
95 - socket.path(), wsProperties.getPath());  
96 - socket.reject();  
97 - return;  
98 - }  
99 - // 创建上行处理器  
100 - IotWebSocketUpstreamHandler handler = new IotWebSocketUpstreamHandler(this,  
101 - messageService, deviceService, connectionManager);  
102 - handler.handle(socket);  
103 - });  
104 -  
105 - // 3. 启动服务器  
106 - try {  
107 - httpServer.listen().result();  
108 - running = true;  
109 - log.info("[start][IoT 网关 WebSocket 协议启动成功,端口:{},路径:{}]", wsProperties.getPort(), wsProperties.getPath());  
110 - } catch (Exception e) {  
111 - log.error("[start][IoT 网关 WebSocket 协议启动失败]", e);  
112 - throw e;  
113 - }  
114 - }  
115 -  
116 - @Override  
117 - @PreDestroy  
118 - public void stop() {  
119 - if (httpServer != null) {  
120 - try {  
121 - httpServer.close().result();  
122 - running = false;  
123 - log.info("[stop][IoT 网关 WebSocket 协议已停止]");  
124 - } catch (Exception e) {  
125 - log.error("[stop][IoT 网关 WebSocket 协议停止失败]", e);  
126 - }  
127 - }  
128 - }  
129 -  
130 - @Override  
131 - public boolean isRunning() {  
132 - return running;  
133 - }  
134 -  
135 -}  
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/router/IotWebSocketDownstreamHandler.java renamed to yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/handler/downstream/IotWebSocketDownstreamHandler.java
1 -package cn.iocoder.yudao.module.iot.gateway.protocol.websocket.router; 1 +package cn.iocoder.yudao.module.iot.gateway.protocol.websocket.handler.downstream;
2 2
3 -import cn.hutool.core.util.StrUtil;  
4 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 3 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.module.iot.core.enums.IotSerializeTypeEnum;
5 import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager.IotWebSocketConnectionManager; 6 import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager.IotWebSocketConnectionManager;
6 -import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; 7 +import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializer;
7 import lombok.RequiredArgsConstructor; 8 import lombok.RequiredArgsConstructor;
8 import lombok.extern.slf4j.Slf4j; 9 import lombok.extern.slf4j.Slf4j;
9 10
@@ -16,7 +17,7 @@ import lombok.extern.slf4j.Slf4j; @@ -16,7 +17,7 @@ import lombok.extern.slf4j.Slf4j;
16 @RequiredArgsConstructor 17 @RequiredArgsConstructor
17 public class IotWebSocketDownstreamHandler { 18 public class IotWebSocketDownstreamHandler {
18 19
19 - private final IotDeviceMessageService deviceMessageService; 20 + private final IotMessageSerializer serializer;
20 21
21 private final IotWebSocketConnectionManager connectionManager; 22 private final IotWebSocketConnectionManager connectionManager;
22 23
@@ -37,9 +38,15 @@ public class IotWebSocketDownstreamHandler { @@ -37,9 +38,15 @@ public class IotWebSocketDownstreamHandler {
37 } 38 }
38 39
39 // 2. 编码消息并发送到设备 40 // 2. 编码消息并发送到设备
40 - byte[] bytes = deviceMessageService.encodeDeviceMessage(message, connectionInfo.getCodecType());  
41 - String jsonMessage = StrUtil.utf8Str(bytes);  
42 - boolean success = connectionManager.sendToDevice(message.getDeviceId(), jsonMessage); 41 + byte[] bytes = serializer.serialize(message);
  42 + // TODO @AI:参考别的模块的做法,直接发?类似 tcp 这种;
  43 + boolean success;
  44 + if (serializer.getType() == IotSerializeTypeEnum.BINARY) {
  45 + success = connectionManager.sendToDevice(message.getDeviceId(), bytes);
  46 + } else {
  47 + String jsonMessage = StrUtil.utf8Str(bytes);
  48 + success = connectionManager.sendToDevice(message.getDeviceId(), jsonMessage);
  49 + }
43 if (success) { 50 if (success) {
44 log.info("[handle][下行消息发送成功,设备 ID: {},方法: {},消息 ID: {},数据长度: {} 字节]", 51 log.info("[handle][下行消息发送成功,设备 ID: {},方法: {},消息 ID: {},数据长度: {} 字节]",
45 message.getDeviceId(), message.getMethod(), message.getId(), bytes.length); 52 message.getDeviceId(), message.getMethod(), message.getId(), bytes.length);
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/IotWebSocketDownstreamSubscriber.java renamed to yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/handler/downstream/IotWebSocketDownstreamSubscriber.java
1 -package cn.iocoder.yudao.module.iot.gateway.protocol.websocket; 1 +package cn.iocoder.yudao.module.iot.gateway.protocol.websocket.handler.downstream;
2 2
3 import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; 3 import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
4 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 4 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
5 import cn.iocoder.yudao.module.iot.gateway.protocol.IotProtocolDownstreamSubscriber; 5 import cn.iocoder.yudao.module.iot.gateway.protocol.IotProtocolDownstreamSubscriber;
6 -import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.router.IotWebSocketDownstreamHandler; 6 +import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.IotWebSocketProtocol;
7 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
8 8
9 /** 9 /**
@@ -16,7 +16,7 @@ public class IotWebSocketDownstreamSubscriber extends IotProtocolDownstreamSubsc @@ -16,7 +16,7 @@ public class IotWebSocketDownstreamSubscriber extends IotProtocolDownstreamSubsc
16 16
17 private final IotWebSocketDownstreamHandler downstreamHandler; 17 private final IotWebSocketDownstreamHandler downstreamHandler;
18 18
19 - public IotWebSocketDownstreamSubscriber(IotWebSocketUpstreamProtocol protocol, 19 + public IotWebSocketDownstreamSubscriber(IotWebSocketProtocol protocol,
20 IotWebSocketDownstreamHandler downstreamHandler, 20 IotWebSocketDownstreamHandler downstreamHandler,
21 IotMessageBus messageBus) { 21 IotMessageBus messageBus) {
22 super(protocol, messageBus); 22 super(protocol, messageBus);
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/router/IotWebSocketUpstreamHandler.java renamed to yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/handler/upstream/IotWebSocketUpstreamHandler.java
1 -package cn.iocoder.yudao.module.iot.gateway.protocol.websocket.router; 1 +package cn.iocoder.yudao.module.iot.gateway.protocol.websocket.handler.upstream;
2 2
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
  4 +import cn.hutool.core.util.ArrayUtil;
4 import cn.hutool.core.util.BooleanUtil; 5 import cn.hutool.core.util.BooleanUtil;
5 import cn.hutool.core.util.IdUtil; 6 import cn.hutool.core.util.IdUtil;
6 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
@@ -11,17 +12,19 @@ import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; @@ -11,17 +12,19 @@ import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
11 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; 12 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
12 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO; 13 import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
13 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; 14 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
  15 +import cn.iocoder.yudao.module.iot.core.enums.IotSerializeTypeEnum;
14 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 16 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
15 import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity; 17 import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity;
16 import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO; 18 import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO;
17 import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterRespDTO; 19 import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterRespDTO;
18 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; 20 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
19 -import cn.iocoder.yudao.module.iot.gateway.codec.alink.IotAlinkDeviceMessageCodec;  
20 -import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.IotWebSocketUpstreamProtocol; 21 +import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.IotWebSocketProtocol;
21 import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager.IotWebSocketConnectionManager; 22 import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager.IotWebSocketConnectionManager;
  23 +import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializer;
22 import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService; 24 import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService;
23 import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; 25 import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
24 import io.vertx.core.Handler; 26 import io.vertx.core.Handler;
  27 +import io.vertx.core.buffer.Buffer;
25 import io.vertx.core.http.ServerWebSocket; 28 import io.vertx.core.http.ServerWebSocket;
26 import lombok.extern.slf4j.Slf4j; 29 import lombok.extern.slf4j.Slf4j;
27 30
@@ -36,82 +39,120 @@ import java.util.Map; @@ -36,82 +39,120 @@ import java.util.Map;
36 @Slf4j 39 @Slf4j
37 public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { 40 public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> {
38 41
  42 + private static final String AUTH_METHOD = "auth";
  43 +
  44 + private final String serverId;
  45 +
39 /** 46 /**
40 - * 默认消息编解码类型 47 + * 消息序列化器(处理业务消息序列化/反序列化)
41 */ 48 */
42 - private static final String CODEC_TYPE = IotAlinkDeviceMessageCodec.TYPE; 49 + private final IotMessageSerializer serializer;
  50 + /**
  51 + * 连接管理器
  52 + */
  53 + private final IotWebSocketConnectionManager connectionManager;
43 54
44 - private static final String AUTH_METHOD = "auth"; 55 + // TODO @AI:是不是可以去掉?
  56 + private final boolean binaryPayload;
45 57
46 private final IotDeviceMessageService deviceMessageService; 58 private final IotDeviceMessageService deviceMessageService;
47 -  
48 private final IotDeviceService deviceService; 59 private final IotDeviceService deviceService;
49 -  
50 - private final IotWebSocketConnectionManager connectionManager;  
51 -  
52 private final IotDeviceCommonApi deviceApi; 60 private final IotDeviceCommonApi deviceApi;
53 61
54 - private final String serverId;  
55 -  
56 - public IotWebSocketUpstreamHandler(IotWebSocketUpstreamProtocol protocol, 62 + // TODO @AI:参数、顺序参考 IotTcpUpstreamHandler
  63 + public IotWebSocketUpstreamHandler(IotWebSocketProtocol protocol,
57 IotDeviceMessageService deviceMessageService, 64 IotDeviceMessageService deviceMessageService,
58 IotDeviceService deviceService, 65 IotDeviceService deviceService,
59 - IotWebSocketConnectionManager connectionManager) { 66 + IotWebSocketConnectionManager connectionManager,
  67 + IotMessageSerializer serializer) {
60 this.deviceMessageService = deviceMessageService; 68 this.deviceMessageService = deviceMessageService;
61 this.deviceService = deviceService; 69 this.deviceService = deviceService;
62 this.connectionManager = connectionManager; 70 this.connectionManager = connectionManager;
  71 + this.serializer = serializer;
  72 + this.binaryPayload = serializer.getType() == IotSerializeTypeEnum.BINARY;
63 this.deviceApi = SpringUtil.getBean(IotDeviceCommonApi.class); 73 this.deviceApi = SpringUtil.getBean(IotDeviceCommonApi.class);
64 this.serverId = protocol.getServerId(); 74 this.serverId = protocol.getServerId();
  75 + // TODO @AI:通过 springutil;deviceService、deviceMessageService;
65 } 76 }
66 77
67 @Override 78 @Override
  79 + @SuppressWarnings("DuplicatedCode")
68 public void handle(ServerWebSocket socket) { 80 public void handle(ServerWebSocket socket) {
69 String clientId = IdUtil.simpleUUID(); 81 String clientId = IdUtil.simpleUUID();
70 log.debug("[handle][设备连接,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress()); 82 log.debug("[handle][设备连接,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress());
71 83
72 // 1. 设置异常和关闭处理器 84 // 1. 设置异常和关闭处理器
  85 + // TODO @AI:clientId 去掉;
73 socket.exceptionHandler(ex -> { 86 socket.exceptionHandler(ex -> {
74 log.warn("[handle][连接异常,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress()); 87 log.warn("[handle][连接异常,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress());
75 - cleanupConnection(socket); 88 + socket.close();
76 }); 89 });
77 socket.closeHandler(v -> { 90 socket.closeHandler(v -> {
78 log.debug("[handle][连接关闭,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress()); 91 log.debug("[handle][连接关闭,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress());
79 cleanupConnection(socket); 92 cleanupConnection(socket);
80 }); 93 });
81 94
82 - // 2. 设置文本消息处理器  
83 - socket.textMessageHandler(message -> {  
84 - try {  
85 - processMessage(clientId, message, socket);  
86 - } catch (Exception e) {  
87 - log.error("[handle][消息解码失败,断开连接,客户端 ID: {},地址: {},错误: {}]",  
88 - clientId, socket.remoteAddress(), e.getMessage()); 95 + // 2. 设置消息处理器(JSON 使用文本,BINARY 使用二进制)
  96 + // TODO @AI:是不是 text、binary 保持统一?用一个 mesagehandler?
  97 + if (binaryPayload) {
  98 + socket.binaryMessageHandler(buffer -> {
  99 + try {
  100 + processMessage(clientId, buffer.getBytes(), socket);
  101 + } catch (Exception e) {
  102 + log.error("[handle][消息解码失败,断开连接,客户端 ID: {},地址: {},错误: {}]",
  103 + clientId, socket.remoteAddress(), e.getMessage());
  104 + cleanupConnection(socket);
  105 + socket.close();
  106 + }
  107 + });
  108 + socket.textMessageHandler(message -> {
  109 + log.warn("[handle][收到文本帧但当前序列化为 BINARY,断开连接,客户端 ID: {},地址: {}]",
  110 + clientId, socket.remoteAddress());
89 cleanupConnection(socket); 111 cleanupConnection(socket);
90 socket.close(); 112 socket.close();
91 - }  
92 - }); 113 + });
  114 + } else {
  115 + socket.textMessageHandler(message -> {
  116 + try {
  117 + processMessage(clientId, StrUtil.utf8Bytes(message), socket);
  118 + } catch (Exception e) {
  119 + log.error("[handle][消息解码失败,断开连接,客户端 ID: {},地址: {},错误: {}]",
  120 + clientId, socket.remoteAddress(), e.getMessage());
  121 + // TODO @AI:是不是不用 cleanupConnection?closehandler 本身就吹了了;
  122 + cleanupConnection(socket);
  123 + socket.close();
  124 + }
  125 + });
  126 + socket.binaryMessageHandler(buffer -> {
  127 + try {
  128 + processMessage(clientId, buffer.getBytes(), socket);
  129 + } catch (Exception e) {
  130 + log.error("[handle][消息解码失败,断开连接,客户端 ID: {},地址: {},错误: {}]",
  131 + clientId, socket.remoteAddress(), e.getMessage());
  132 + cleanupConnection(socket);
  133 + socket.close();
  134 + }
  135 + });
  136 + }
93 } 137 }
94 138
95 /** 139 /**
96 * 处理消息 140 * 处理消息
97 * 141 *
98 * @param clientId 客户端 ID 142 * @param clientId 客户端 ID
99 - * @param message 消息(JSON 字符串) 143 + * @param payload 消息负载
100 * @param socket WebSocket 连接 144 * @param socket WebSocket 连接
101 * @throws Exception 消息解码失败时抛出异常 145 * @throws Exception 消息解码失败时抛出异常
102 */ 146 */
103 - private void processMessage(String clientId, String message, ServerWebSocket socket) throws Exception { 147 + private void processMessage(String clientId, byte[] payload, ServerWebSocket socket) throws Exception {
104 // 1.1 基础检查 148 // 1.1 基础检查
105 - if (StrUtil.isBlank(message)) { 149 + if (ArrayUtil.isEmpty(payload)) {
106 return; 150 return;
107 } 151 }
108 - // 1.2 解码消息(已认证连接使用其 codecType,未认证连接使用默认 CODEC_TYPE)  
109 - IotWebSocketConnectionManager.ConnectionInfo connectionInfo = connectionManager.getConnectionInfo(socket);  
110 - String codecType = connectionInfo != null ? connectionInfo.getCodecType() : CODEC_TYPE; 152 + // 1.2 解码消息
111 IotDeviceMessage deviceMessage; 153 IotDeviceMessage deviceMessage;
112 try { 154 try {
113 - deviceMessage = deviceMessageService.decodeDeviceMessage(  
114 - StrUtil.utf8Bytes(message), codecType); 155 + deviceMessage = serializer.deserialize(payload);
115 if (deviceMessage == null) { 156 if (deviceMessage == null) {
116 throw new Exception("解码后消息为空"); 157 throw new Exception("解码后消息为空");
117 } 158 }
@@ -132,6 +173,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; { @@ -132,6 +173,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
132 handleBusinessRequest(clientId, deviceMessage, socket); 173 handleBusinessRequest(clientId, deviceMessage, socket);
133 } 174 }
134 } catch (Exception e) { 175 } catch (Exception e) {
  176 + // TODO @AI:参考 IotTcpUpstreamHandler 处理;业务、参数、其它
135 log.error("[processMessage][处理消息失败,客户端 ID: {},消息方法: {}]", 177 log.error("[processMessage][处理消息失败,客户端 ID: {},消息方法: {}]",
136 clientId, deviceMessage.getMethod(), e); 178 clientId, deviceMessage.getMethod(), e);
137 // 发送错误响应,避免客户端一直等待 179 // 发送错误响应,避免客户端一直等待
@@ -153,6 +195,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; { @@ -153,6 +195,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
153 private void handleAuthenticationRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) { 195 private void handleAuthenticationRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) {
154 try { 196 try {
155 // 1.1 解析认证参数 197 // 1.1 解析认证参数
  198 + // TODO @AI:参数解析;参考 tcp 对应的 handleAuthenticationRequest
156 IotDeviceAuthReqDTO authParams = parseAuthParams(message.getParams()); 199 IotDeviceAuthReqDTO authParams = parseAuthParams(message.getParams());
157 if (authParams == null) { 200 if (authParams == null) {
158 log.warn("[handleAuthenticationRequest][认证参数解析失败,客户端 ID: {}]", clientId); 201 log.warn("[handleAuthenticationRequest][认证参数解析失败,客户端 ID: {}]", clientId);
@@ -204,6 +247,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; { @@ -204,6 +247,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
204 * @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">阿里云 - 一型一密</a> 247 * @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">阿里云 - 一型一密</a>
205 */ 248 */
206 private void handleRegisterRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) { 249 private void handleRegisterRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) {
  250 + // TODO @AI:参数解析;参考 tcp 对应的 handleRegisterRequest
207 try { 251 try {
208 // 1. 解析注册参数 252 // 1. 解析注册参数
209 IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams()); 253 IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams());
@@ -232,6 +276,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; { @@ -232,6 +276,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
232 } 276 }
233 } 277 }
234 278
  279 + // TODO @AI:参考对应的 tcp 的 handleBusinessRequest
235 /** 280 /**
236 * 处理业务请求 281 * 处理业务请求
237 * 282 *
@@ -270,10 +315,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; { @@ -270,10 +315,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
270 IotWebSocketConnectionManager.ConnectionInfo connectionInfo = new IotWebSocketConnectionManager.ConnectionInfo() 315 IotWebSocketConnectionManager.ConnectionInfo connectionInfo = new IotWebSocketConnectionManager.ConnectionInfo()
271 .setDeviceId(device.getId()) 316 .setDeviceId(device.getId())
272 .setProductKey(device.getProductKey()) 317 .setProductKey(device.getProductKey())
273 - .setDeviceName(device.getDeviceName())  
274 - .setClientId(clientId)  
275 - .setCodecType(CODEC_TYPE);  
276 - // 注册连接 318 + .setDeviceName(device.getDeviceName());
277 connectionManager.registerConnection(socket, device.getId(), connectionInfo); 319 connectionManager.registerConnection(socket, device.getId(), connectionInfo);
278 } 320 }
279 321
@@ -314,6 +356,8 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; { @@ -314,6 +356,8 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
314 } 356 }
315 } 357 }
316 358
  359 + // ===================== 发送响应消息 =====================
  360 +
317 /** 361 /**
318 * 发送响应消息 362 * 发送响应消息
319 * 363 *
@@ -332,8 +376,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; { @@ -332,8 +376,7 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
332 int code = success ? 0 : 401; 376 int code = success ? 0 : 401;
333 IotDeviceMessage responseMessage = IotDeviceMessage.replyOf(requestId, AUTH_METHOD, responseData, code, message); 377 IotDeviceMessage responseMessage = IotDeviceMessage.replyOf(requestId, AUTH_METHOD, responseData, code, message);
334 378
335 - byte[] encodedData = deviceMessageService.encodeDeviceMessage(responseMessage, CODEC_TYPE);  
336 - socket.writeTextMessage(StrUtil.utf8Str(encodedData)); 379 + writeResponse(socket, responseMessage);
337 } catch (Exception e) { 380 } catch (Exception e) {
338 log.error("[sendResponse][发送响应失败,requestId: {}]", requestId, e); 381 log.error("[sendResponse][发送响应失败,requestId: {}]", requestId, e);
339 } 382 }
@@ -461,11 +504,22 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; { @@ -461,11 +504,22 @@ public class IotWebSocketUpstreamHandler implements Handler&lt;ServerWebSocket&gt; {
461 IotDeviceMessage responseMessage = IotDeviceMessage.replyOf(requestId, 504 IotDeviceMessage responseMessage = IotDeviceMessage.replyOf(requestId,
462 IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod(), registerResp, 0, null); 505 IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod(), registerResp, 0, null);
463 // 2. 发送响应 506 // 2. 发送响应
464 - byte[] encodedData = deviceMessageService.encodeDeviceMessage(responseMessage, CODEC_TYPE);  
465 - socket.writeTextMessage(StrUtil.utf8Str(encodedData)); 507 + writeResponse(socket, responseMessage);
466 } catch (Exception e) { 508 } catch (Exception e) {
467 log.error("[sendRegisterSuccessResponse][发送注册成功响应失败,requestId: {}]", requestId, e); 509 log.error("[sendRegisterSuccessResponse][发送注册成功响应失败,requestId: {}]", requestId, e);
468 } 510 }
469 } 511 }
470 512
  513 + /**
  514 + * 写入响应消息
  515 + */
  516 + private void writeResponse(ServerWebSocket socket, IotDeviceMessage responseMessage) {
  517 + byte[] payload = serializer.serialize(responseMessage);
  518 + if (binaryPayload) {
  519 + socket.writeBinaryMessage(Buffer.buffer(payload));
  520 + } else {
  521 + socket.writeTextMessage(StrUtil.utf8Str(payload));
  522 + }
  523 + }
  524 +
471 } 525 }
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/manager/IotWebSocketConnectionManager.java
1 package cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager; 1 package cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager;
2 2
  3 +import io.vertx.core.buffer.Buffer;
3 import io.vertx.core.http.ServerWebSocket; 4 import io.vertx.core.http.ServerWebSocket;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.experimental.Accessors; 6 import lombok.experimental.Accessors;
6 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
7 -import org.springframework.stereotype.Component;  
8 8
9 import java.util.Map; 9 import java.util.Map;
10 import java.util.concurrent.ConcurrentHashMap; 10 import java.util.concurrent.ConcurrentHashMap;
@@ -20,7 +20,6 @@ import java.util.concurrent.ConcurrentHashMap; @@ -20,7 +20,6 @@ import java.util.concurrent.ConcurrentHashMap;
20 * @author 芋道源码 20 * @author 芋道源码
21 */ 21 */
22 @Slf4j 22 @Slf4j
23 -@Component  
24 public class IotWebSocketConnectionManager { 23 public class IotWebSocketConnectionManager {
25 24
26 /** 25 /**
@@ -69,7 +68,8 @@ public class IotWebSocketConnectionManager { @@ -69,7 +68,8 @@ public class IotWebSocketConnectionManager {
69 return; 68 return;
70 } 69 }
71 Long deviceId = connectionInfo.getDeviceId(); 70 Long deviceId = connectionInfo.getDeviceId();
72 - deviceSocketMap.remove(deviceId); 71 + // 仅当 deviceSocketMap 中的 socket 是当前 socket 时才移除,避免误删新连接
  72 + deviceSocketMap.remove(deviceId, socket);
73 log.info("[unregisterConnection][注销设备连接,设备 ID: {},连接: {}]", 73 log.info("[unregisterConnection][注销设备连接,设备 ID: {},连接: {}]",
74 deviceId, socket.remoteAddress()); 74 deviceId, socket.remoteAddress());
75 } 75 }
@@ -115,6 +115,33 @@ public class IotWebSocketConnectionManager { @@ -115,6 +115,33 @@ public class IotWebSocketConnectionManager {
115 } 115 }
116 } 116 }
117 117
  118 + // TODO @AI:没必要这里加一个;
  119 + /**
  120 + * 发送消息到设备(二进制消息)
  121 + *
  122 + * @param deviceId 设备 ID
  123 + * @param payload 二进制消息
  124 + * @return 是否发送成功
  125 + */
  126 + public boolean sendToDevice(Long deviceId, byte[] payload) {
  127 + ServerWebSocket socket = deviceSocketMap.get(deviceId);
  128 + if (socket == null) {
  129 + log.warn("[sendToDevice][设备未连接,设备 ID: {}]", deviceId);
  130 + return false;
  131 + }
  132 +
  133 + try {
  134 + socket.writeBinaryMessage(Buffer.buffer(payload));
  135 + log.debug("[sendToDevice][发送消息成功,设备 ID: {},数据长度: {} 字节]", deviceId, payload.length);
  136 + return true;
  137 + } catch (Exception e) {
  138 + log.error("[sendToDevice][发送消息失败,设备 ID: {}]", deviceId, e);
  139 + // 发送失败时清理连接
  140 + unregisterConnection(socket);
  141 + return false;
  142 + }
  143 + }
  144 +
118 /** 145 /**
119 * 连接信息(包含认证信息) 146 * 连接信息(包含认证信息)
120 */ 147 */
@@ -135,15 +162,6 @@ public class IotWebSocketConnectionManager { @@ -135,15 +162,6 @@ public class IotWebSocketConnectionManager {
135 */ 162 */
136 private String deviceName; 163 private String deviceName;
137 164
138 - /**  
139 - * 客户端 ID  
140 - */  
141 - private String clientId;  
142 - /**  
143 - * 消息编解码类型(认证后确定)  
144 - */  
145 - private String codecType;  
146 -  
147 } 165 }
148 166
149 } 167 }
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml
@@ -94,7 +94,7 @@ yudao: @@ -94,7 +94,7 @@ yudao:
94 - id: websocket-json 94 - id: websocket-json
95 type: websocket 95 type: websocket
96 port: 8094 96 port: 8094
97 - enabled: false 97 + enabled: true
98 serialize: json 98 serialize: json
99 websocket: 99 websocket:
100 path: /ws 100 path: /ws
@@ -159,6 +159,7 @@ yudao: @@ -159,6 +159,7 @@ yudao:
159 max-message-size: 8192 159 max-message-size: 8192
160 connect-timeout-seconds: 60 160 connect-timeout-seconds: 60
161 ssl-enabled: false 161 ssl-enabled: false
  162 +
162 --- #################### 日志相关配置 #################### 163 --- #################### 日志相关配置 ####################
163 164
164 # 基础日志配置 165 # 基础日志配置
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotDirectDeviceTcpProtocolIntegrationTest.java
@@ -270,7 +270,7 @@ public class IotDirectDeviceTcpProtocolIntegrationTest { @@ -270,7 +270,7 @@ public class IotDirectDeviceTcpProtocolIntegrationTest {
270 }); 270 });
271 socket.handler(parser); 271 socket.handler(parser);
272 272
273 - // 2.1 序列化 + 帧编码(复用 gateway 的编码逻辑) 273 + // 2.1 序列化 + 帧编码
274 byte[] serializedData = SERIALIZER.serialize(request); 274 byte[] serializedData = SERIALIZER.serialize(request);
275 Buffer frameData = FRAME_CODEC.encode(serializedData); 275 Buffer frameData = FRAME_CODEC.encode(serializedData);
276 log.info("[sendAndReceive][发送消息: {},数据长度: {} 字节]", request.getMethod(), frameData.length()); 276 log.info("[sendAndReceive][发送消息: {},数据长度: {} 字节]", request.getMethod(), frameData.length());
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotGatewayDeviceTcpProtocolIntegrationTest.java
@@ -373,7 +373,7 @@ public class IotGatewayDeviceTcpProtocolIntegrationTest { @@ -373,7 +373,7 @@ public class IotGatewayDeviceTcpProtocolIntegrationTest {
373 }); 373 });
374 socket.handler(parser); 374 socket.handler(parser);
375 375
376 - // 2.1 序列化 + 帧编码(复用 gateway 的编码逻辑) 376 + // 2.1 序列化 + 帧编码
377 byte[] serializedData = SERIALIZER.serialize(request); 377 byte[] serializedData = SERIALIZER.serialize(request);
378 Buffer frameData = FRAME_CODEC.encode(serializedData); 378 Buffer frameData = FRAME_CODEC.encode(serializedData);
379 log.info("[sendAndReceive][发送消息: {},数据长度: {} 字节]", request.getMethod(), frameData.length()); 379 log.info("[sendAndReceive][发送消息: {},数据长度: {} 字节]", request.getMethod(), frameData.length());
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotGatewaySubDeviceTcpProtocolIntegrationTest.java
@@ -249,7 +249,7 @@ public class IotGatewaySubDeviceTcpProtocolIntegrationTest { @@ -249,7 +249,7 @@ public class IotGatewaySubDeviceTcpProtocolIntegrationTest {
249 }); 249 });
250 socket.handler(parser); 250 socket.handler(parser);
251 251
252 - // 2.1 序列化 + 帧编码(复用 gateway 的编码逻辑) 252 + // 2.1 序列化 + 帧编码
253 byte[] serializedData = SERIALIZER.serialize(request); 253 byte[] serializedData = SERIALIZER.serialize(request);
254 Buffer frameData = FRAME_CODEC.encode(serializedData); 254 Buffer frameData = FRAME_CODEC.encode(serializedData);
255 log.info("[sendAndReceive][发送消息: {},数据长度: {} 字节]", request.getMethod(), frameData.length()); 255 log.info("[sendAndReceive][发送消息: {},数据长度: {} 字节]", request.getMethod(), frameData.length());
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/IotDirectDeviceWebSocketProtocolIntegrationTest.java
@@ -10,8 +10,8 @@ import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO; @@ -10,8 +10,8 @@ import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO;
10 import cn.iocoder.yudao.module.iot.core.topic.event.IotDeviceEventPostReqDTO; 10 import cn.iocoder.yudao.module.iot.core.topic.event.IotDeviceEventPostReqDTO;
11 import cn.iocoder.yudao.module.iot.core.topic.property.IotDevicePropertyPostReqDTO; 11 import cn.iocoder.yudao.module.iot.core.topic.property.IotDevicePropertyPostReqDTO;
12 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; 12 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
13 -import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec;  
14 -import cn.iocoder.yudao.module.iot.gateway.codec.alink.IotAlinkDeviceMessageCodec; 13 +import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializer;
  14 +import cn.iocoder.yudao.module.iot.gateway.serialize.json.IotJsonSerializer;
15 import io.vertx.core.Vertx; 15 import io.vertx.core.Vertx;
16 import io.vertx.core.http.WebSocket; 16 import io.vertx.core.http.WebSocket;
17 import io.vertx.core.http.WebSocketClient; 17 import io.vertx.core.http.WebSocketClient;
@@ -61,7 +61,7 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { @@ -61,7 +61,7 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest {
61 61
62 // ===================== 编解码器选择 ===================== 62 // ===================== 编解码器选择 =====================
63 63
64 - private static final IotDeviceMessageCodec CODEC = new IotAlinkDeviceMessageCodec(); 64 + private static final IotMessageSerializer SERIALIZER = new IotJsonSerializer();
65 65
66 // ===================== 直连设备信息(根据实际情况修改,从 iot_device 表查询) ===================== 66 // ===================== 直连设备信息(根据实际情况修改,从 iot_device 表查询) =====================
67 67
@@ -95,10 +95,10 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { @@ -95,10 +95,10 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest {
95 .setUsername(authInfo.getUsername()) 95 .setUsername(authInfo.getUsername())
96 .setPassword(authInfo.getPassword()); 96 .setPassword(authInfo.getPassword());
97 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null); 97 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null);
98 - // 1.2 编码  
99 - byte[] payload = CODEC.encode(request); 98 + // 1.2 序列化
  99 + byte[] payload = SERIALIZER.serialize(request);
100 String jsonMessage = StrUtil.utf8Str(payload); 100 String jsonMessage = StrUtil.utf8Str(payload);
101 - log.info("[testAuth][Codec: {}, 请求消息: {}]", CODEC.type(), request); 101 + log.info("[testAuth][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
102 102
103 // 2.1 创建 WebSocket 连接(同步) 103 // 2.1 创建 WebSocket 连接(同步)
104 WebSocket ws = createWebSocketConnection(); 104 WebSocket ws = createWebSocketConnection();
@@ -109,7 +109,7 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { @@ -109,7 +109,7 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest {
109 109
110 // 3. 解码响应 110 // 3. 解码响应
111 if (response != null) { 111 if (response != null) {
112 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 112 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
113 log.info("[testAuth][响应消息: {}]", responseMessage); 113 log.info("[testAuth][响应消息: {}]", responseMessage);
114 } else { 114 } else {
115 log.warn("[testAuth][未收到响应]"); 115 log.warn("[testAuth][未收到响应]");
@@ -137,10 +137,10 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { @@ -137,10 +137,10 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest {
137 registerReqDTO.setProductSecret("test-product-secret"); 137 registerReqDTO.setProductSecret("test-product-secret");
138 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), 138 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(),
139 IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod(), registerReqDTO, null, null, null); 139 IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod(), registerReqDTO, null, null, null);
140 - // 1.2 编码  
141 - byte[] payload = CODEC.encode(request); 140 + // 1.2 序列化
  141 + byte[] payload = SERIALIZER.serialize(request);
142 String jsonMessage = StrUtil.utf8Str(payload); 142 String jsonMessage = StrUtil.utf8Str(payload);
143 - log.info("[testDeviceRegister][Codec: {}, 请求消息: {}]", CODEC.type(), request); 143 + log.info("[testDeviceRegister][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
144 144
145 // 2.1 创建 WebSocket 连接(同步) 145 // 2.1 创建 WebSocket 连接(同步)
146 WebSocket ws = createWebSocketConnection(); 146 WebSocket ws = createWebSocketConnection();
@@ -151,7 +151,7 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { @@ -151,7 +151,7 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest {
151 151
152 // 3. 解码响应 152 // 3. 解码响应
153 if (response != null) { 153 if (response != null) {
154 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 154 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
155 log.info("[testDeviceRegister][响应消息: {}]", responseMessage); 155 log.info("[testDeviceRegister][响应消息: {}]", responseMessage);
156 log.info("[testDeviceRegister][成功后可使用返回的 deviceSecret 进行一机一密认证]"); 156 log.info("[testDeviceRegister][成功后可使用返回的 deviceSecret 进行一机一密认证]");
157 } else { 157 } else {
@@ -186,16 +186,16 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { @@ -186,16 +186,16 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest {
186 .put("height", "2") 186 .put("height", "2")
187 .build()), 187 .build()),
188 null, null, null); 188 null, null, null);
189 - // 2.2 编码  
190 - byte[] payload = CODEC.encode(request); 189 + // 2.2 序列化
  190 + byte[] payload = SERIALIZER.serialize(request);
191 String jsonMessage = StrUtil.utf8Str(payload); 191 String jsonMessage = StrUtil.utf8Str(payload);
192 - log.info("[testPropertyPost][Codec: {}, 请求消息: {}]", CODEC.type(), request); 192 + log.info("[testPropertyPost][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
193 193
194 // 3.1 发送并等待响应 194 // 3.1 发送并等待响应
195 String response = sendAndReceive(ws, jsonMessage); 195 String response = sendAndReceive(ws, jsonMessage);
196 // 3.2 解码响应 196 // 3.2 解码响应
197 if (response != null) { 197 if (response != null) {
198 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 198 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
199 log.info("[testPropertyPost][响应消息: {}]", responseMessage); 199 log.info("[testPropertyPost][响应消息: {}]", responseMessage);
200 } else { 200 } else {
201 log.warn("[testPropertyPost][未收到响应]"); 201 log.warn("[testPropertyPost][未收到响应]");
@@ -229,16 +229,16 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { @@ -229,16 +229,16 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest {
229 MapUtil.<String, Object>builder().put("rice", 3).build(), 229 MapUtil.<String, Object>builder().put("rice", 3).build(),
230 System.currentTimeMillis()), 230 System.currentTimeMillis()),
231 null, null, null); 231 null, null, null);
232 - // 2.2 编码  
233 - byte[] payload = CODEC.encode(request); 232 + // 2.2 序列化
  233 + byte[] payload = SERIALIZER.serialize(request);
234 String jsonMessage = StrUtil.utf8Str(payload); 234 String jsonMessage = StrUtil.utf8Str(payload);
235 - log.info("[testEventPost][Codec: {}, 请求消息: {}]", CODEC.type(), request); 235 + log.info("[testEventPost][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
236 236
237 // 3.1 发送并等待响应 237 // 3.1 发送并等待响应
238 String response = sendAndReceive(ws, jsonMessage); 238 String response = sendAndReceive(ws, jsonMessage);
239 // 3.2 解码响应 239 // 3.2 解码响应
240 if (response != null) { 240 if (response != null) {
241 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 241 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
242 log.info("[testEventPost][响应消息: {}]", responseMessage); 242 log.info("[testEventPost][响应消息: {}]", responseMessage);
243 } else { 243 } else {
244 log.warn("[testEventPost][未收到响应]"); 244 log.warn("[testEventPost][未收到响应]");
@@ -308,13 +308,13 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { @@ -308,13 +308,13 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest {
308 .setPassword(authInfo.getPassword()); 308 .setPassword(authInfo.getPassword());
309 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null); 309 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null);
310 310
311 - byte[] payload = CODEC.encode(request); 311 + byte[] payload = SERIALIZER.serialize(request);
312 String jsonMessage = StrUtil.utf8Str(payload); 312 String jsonMessage = StrUtil.utf8Str(payload);
313 log.info("[authenticate][发送认证请求: {}]", jsonMessage); 313 log.info("[authenticate][发送认证请求: {}]", jsonMessage);
314 314
315 String response = sendAndReceive(ws, jsonMessage); 315 String response = sendAndReceive(ws, jsonMessage);
316 if (response != null) { 316 if (response != null) {
317 - return CODEC.decode(StrUtil.utf8Bytes(response)); 317 + return SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
318 } 318 }
319 return null; 319 return null;
320 } 320 }
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/IotGatewayDeviceWebSocketProtocolIntegrationTest.java
@@ -14,8 +14,8 @@ import cn.iocoder.yudao.module.iot.core.topic.topo.IotDeviceTopoAddReqDTO; @@ -14,8 +14,8 @@ import cn.iocoder.yudao.module.iot.core.topic.topo.IotDeviceTopoAddReqDTO;
14 import cn.iocoder.yudao.module.iot.core.topic.topo.IotDeviceTopoDeleteReqDTO; 14 import cn.iocoder.yudao.module.iot.core.topic.topo.IotDeviceTopoDeleteReqDTO;
15 import cn.iocoder.yudao.module.iot.core.topic.topo.IotDeviceTopoGetReqDTO; 15 import cn.iocoder.yudao.module.iot.core.topic.topo.IotDeviceTopoGetReqDTO;
16 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; 16 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
17 -import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec;  
18 -import cn.iocoder.yudao.module.iot.gateway.codec.alink.IotAlinkDeviceMessageCodec; 17 +import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializer;
  18 +import cn.iocoder.yudao.module.iot.gateway.serialize.json.IotJsonSerializer;
19 import io.vertx.core.Vertx; 19 import io.vertx.core.Vertx;
20 import io.vertx.core.http.WebSocket; 20 import io.vertx.core.http.WebSocket;
21 import io.vertx.core.http.WebSocketClient; 21 import io.vertx.core.http.WebSocketClient;
@@ -67,9 +67,9 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -67,9 +67,9 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
67 67
68 private static Vertx vertx; 68 private static Vertx vertx;
69 69
70 - // ===================== 编解码器选择 ===================== 70 + // ===================== 序列化器选择 =====================
71 71
72 - private static final IotDeviceMessageCodec CODEC = new IotAlinkDeviceMessageCodec(); 72 + private static final IotMessageSerializer SERIALIZER = new IotJsonSerializer();
73 73
74 // ===================== 网关设备信息(根据实际情况修改,从 iot_device 表查询网关设备) ===================== 74 // ===================== 网关设备信息(根据实际情况修改,从 iot_device 表查询网关设备) =====================
75 75
@@ -110,10 +110,10 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -110,10 +110,10 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
110 .setUsername(authInfo.getUsername()) 110 .setUsername(authInfo.getUsername())
111 .setPassword(authInfo.getPassword()); 111 .setPassword(authInfo.getPassword());
112 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null); 112 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null);
113 - // 1.2 编码  
114 - byte[] payload = CODEC.encode(request); 113 + // 1.2 序列化
  114 + byte[] payload = SERIALIZER.serialize(request);
115 String jsonMessage = StrUtil.utf8Str(payload); 115 String jsonMessage = StrUtil.utf8Str(payload);
116 - log.info("[testAuth][Codec: {}, 请求消息: {}]", CODEC.type(), request); 116 + log.info("[testAuth][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
117 117
118 // 2.1 创建 WebSocket 连接(同步) 118 // 2.1 创建 WebSocket 连接(同步)
119 WebSocket ws = createWebSocketConnection(); 119 WebSocket ws = createWebSocketConnection();
@@ -124,7 +124,7 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -124,7 +124,7 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
124 124
125 // 3. 解码响应 125 // 3. 解码响应
126 if (response != null) { 126 if (response != null) {
127 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 127 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
128 log.info("[testAuth][响应消息: {}]", responseMessage); 128 log.info("[testAuth][响应消息: {}]", responseMessage);
129 } else { 129 } else {
130 log.warn("[testAuth][未收到响应]"); 130 log.warn("[testAuth][未收到响应]");
@@ -164,16 +164,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -164,16 +164,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
164 IotDeviceMessageMethodEnum.TOPO_ADD.getMethod(), 164 IotDeviceMessageMethodEnum.TOPO_ADD.getMethod(),
165 params, 165 params,
166 null, null, null); 166 null, null, null);
167 - // 2.3 编码  
168 - byte[] payload = CODEC.encode(request); 167 + // 2.3 序列化
  168 + byte[] payload = SERIALIZER.serialize(request);
169 String jsonMessage = StrUtil.utf8Str(payload); 169 String jsonMessage = StrUtil.utf8Str(payload);
170 - log.info("[testTopoAdd][Codec: {}, 请求消息: {}]", CODEC.type(), request); 170 + log.info("[testTopoAdd][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
171 171
172 // 3.1 发送并等待响应 172 // 3.1 发送并等待响应
173 String response = sendAndReceive(ws, jsonMessage); 173 String response = sendAndReceive(ws, jsonMessage);
174 // 3.2 解码响应 174 // 3.2 解码响应
175 if (response != null) { 175 if (response != null) {
176 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 176 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
177 log.info("[testTopoAdd][响应消息: {}]", responseMessage); 177 log.info("[testTopoAdd][响应消息: {}]", responseMessage);
178 } else { 178 } else {
179 log.warn("[testTopoAdd][未收到响应]"); 179 log.warn("[testTopoAdd][未收到响应]");
@@ -205,16 +205,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -205,16 +205,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
205 IotDeviceMessageMethodEnum.TOPO_DELETE.getMethod(), 205 IotDeviceMessageMethodEnum.TOPO_DELETE.getMethod(),
206 params, 206 params,
207 null, null, null); 207 null, null, null);
208 - // 2.2 编码  
209 - byte[] payload = CODEC.encode(request); 208 + // 2.2 序列化
  209 + byte[] payload = SERIALIZER.serialize(request);
210 String jsonMessage = StrUtil.utf8Str(payload); 210 String jsonMessage = StrUtil.utf8Str(payload);
211 - log.info("[testTopoDelete][Codec: {}, 请求消息: {}]", CODEC.type(), request); 211 + log.info("[testTopoDelete][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
212 212
213 // 3.1 发送并等待响应 213 // 3.1 发送并等待响应
214 String response = sendAndReceive(ws, jsonMessage); 214 String response = sendAndReceive(ws, jsonMessage);
215 // 3.2 解码响应 215 // 3.2 解码响应
216 if (response != null) { 216 if (response != null) {
217 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 217 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
218 log.info("[testTopoDelete][响应消息: {}]", responseMessage); 218 log.info("[testTopoDelete][响应消息: {}]", responseMessage);
219 } else { 219 } else {
220 log.warn("[testTopoDelete][未收到响应]"); 220 log.warn("[testTopoDelete][未收到响应]");
@@ -244,16 +244,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -244,16 +244,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
244 IotDeviceMessageMethodEnum.TOPO_GET.getMethod(), 244 IotDeviceMessageMethodEnum.TOPO_GET.getMethod(),
245 params, 245 params,
246 null, null, null); 246 null, null, null);
247 - // 2.2 编码  
248 - byte[] payload = CODEC.encode(request); 247 + // 2.2 序列化
  248 + byte[] payload = SERIALIZER.serialize(request);
249 String jsonMessage = StrUtil.utf8Str(payload); 249 String jsonMessage = StrUtil.utf8Str(payload);
250 - log.info("[testTopoGet][Codec: {}, 请求消息: {}]", CODEC.type(), request); 250 + log.info("[testTopoGet][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
251 251
252 // 3.1 发送并等待响应 252 // 3.1 发送并等待响应
253 String response = sendAndReceive(ws, jsonMessage); 253 String response = sendAndReceive(ws, jsonMessage);
254 // 3.2 解码响应 254 // 3.2 解码响应
255 if (response != null) { 255 if (response != null) {
256 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 256 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
257 log.info("[testTopoGet][响应消息: {}]", responseMessage); 257 log.info("[testTopoGet][响应消息: {}]", responseMessage);
258 } else { 258 } else {
259 log.warn("[testTopoGet][未收到响应]"); 259 log.warn("[testTopoGet][未收到响应]");
@@ -287,16 +287,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -287,16 +287,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
287 IotDeviceMessageMethodEnum.SUB_DEVICE_REGISTER.getMethod(), 287 IotDeviceMessageMethodEnum.SUB_DEVICE_REGISTER.getMethod(),
288 Collections.singletonList(subDevice), 288 Collections.singletonList(subDevice),
289 null, null, null); 289 null, null, null);
290 - // 2.2 编码  
291 - byte[] payload = CODEC.encode(request); 290 + // 2.2 序列化
  291 + byte[] payload = SERIALIZER.serialize(request);
292 String jsonMessage = StrUtil.utf8Str(payload); 292 String jsonMessage = StrUtil.utf8Str(payload);
293 - log.info("[testSubDeviceRegister][Codec: {}, 请求消息: {}]", CODEC.type(), request); 293 + log.info("[testSubDeviceRegister][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
294 294
295 // 3.1 发送并等待响应 295 // 3.1 发送并等待响应
296 String response = sendAndReceive(ws, jsonMessage); 296 String response = sendAndReceive(ws, jsonMessage);
297 // 3.2 解码响应 297 // 3.2 解码响应
298 if (response != null) { 298 if (response != null) {
299 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 299 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
300 log.info("[testSubDeviceRegister][响应消息: {}]", responseMessage); 300 log.info("[testSubDeviceRegister][响应消息: {}]", responseMessage);
301 } else { 301 } else {
302 log.warn("[testSubDeviceRegister][未收到响应]"); 302 log.warn("[testSubDeviceRegister][未收到响应]");
@@ -358,16 +358,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -358,16 +358,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
358 IotDeviceMessageMethodEnum.PROPERTY_PACK_POST.getMethod(), 358 IotDeviceMessageMethodEnum.PROPERTY_PACK_POST.getMethod(),
359 params, 359 params,
360 null, null, null); 360 null, null, null);
361 - // 2.7 编码  
362 - byte[] payload = CODEC.encode(request); 361 + // 2.7 序列化
  362 + byte[] payload = SERIALIZER.serialize(request);
363 String jsonMessage = StrUtil.utf8Str(payload); 363 String jsonMessage = StrUtil.utf8Str(payload);
364 - log.info("[testPropertyPackPost][Codec: {}, 请求消息: {}]", CODEC.type(), request); 364 + log.info("[testPropertyPackPost][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
365 365
366 // 3.1 发送并等待响应 366 // 3.1 发送并等待响应
367 String response = sendAndReceive(ws, jsonMessage); 367 String response = sendAndReceive(ws, jsonMessage);
368 // 3.2 解码响应 368 // 3.2 解码响应
369 if (response != null) { 369 if (response != null) {
370 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 370 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
371 log.info("[testPropertyPackPost][响应消息: {}]", responseMessage); 371 log.info("[testPropertyPackPost][响应消息: {}]", responseMessage);
372 } else { 372 } else {
373 log.warn("[testPropertyPackPost][未收到响应]"); 373 log.warn("[testPropertyPackPost][未收到响应]");
@@ -438,13 +438,13 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { @@ -438,13 +438,13 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest {
438 .setPassword(authInfo.getPassword()); 438 .setPassword(authInfo.getPassword());
439 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null); 439 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null);
440 440
441 - byte[] payload = CODEC.encode(request); 441 + byte[] payload = SERIALIZER.serialize(request);
442 String jsonMessage = StrUtil.utf8Str(payload); 442 String jsonMessage = StrUtil.utf8Str(payload);
443 log.info("[authenticate][发送认证请求: {}]", jsonMessage); 443 log.info("[authenticate][发送认证请求: {}]", jsonMessage);
444 444
445 String response = sendAndReceive(ws, jsonMessage); 445 String response = sendAndReceive(ws, jsonMessage);
446 if (response != null) { 446 if (response != null) {
447 - return CODEC.decode(StrUtil.utf8Bytes(response)); 447 + return SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
448 } 448 }
449 return null; 449 return null;
450 } 450 }
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/websocket/IotGatewaySubDeviceWebSocketProtocolIntegrationTest.java
@@ -9,8 +9,8 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; @@ -9,8 +9,8 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
9 import cn.iocoder.yudao.module.iot.core.topic.event.IotDeviceEventPostReqDTO; 9 import cn.iocoder.yudao.module.iot.core.topic.event.IotDeviceEventPostReqDTO;
10 import cn.iocoder.yudao.module.iot.core.topic.property.IotDevicePropertyPostReqDTO; 10 import cn.iocoder.yudao.module.iot.core.topic.property.IotDevicePropertyPostReqDTO;
11 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; 11 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
12 -import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec;  
13 -import cn.iocoder.yudao.module.iot.gateway.codec.alink.IotAlinkDeviceMessageCodec; 12 +import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializer;
  13 +import cn.iocoder.yudao.module.iot.gateway.serialize.json.IotJsonSerializer;
14 import io.vertx.core.Vertx; 14 import io.vertx.core.Vertx;
15 import io.vertx.core.http.WebSocket; 15 import io.vertx.core.http.WebSocket;
16 import io.vertx.core.http.WebSocketClient; 16 import io.vertx.core.http.WebSocketClient;
@@ -60,9 +60,9 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { @@ -60,9 +60,9 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest {
60 60
61 private static Vertx vertx; 61 private static Vertx vertx;
62 62
63 - // ===================== 编解码器选择 ===================== 63 + // ===================== 序列化器选择 =====================
64 64
65 - private static final IotDeviceMessageCodec CODEC = new IotAlinkDeviceMessageCodec(); 65 + private static final IotMessageSerializer SERIALIZER = new IotJsonSerializer();
66 66
67 // ===================== 网关子设备信息(根据实际情况修改,从 iot_device 表查询子设备) ===================== 67 // ===================== 网关子设备信息(根据实际情况修改,从 iot_device 表查询子设备) =====================
68 68
@@ -96,10 +96,10 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { @@ -96,10 +96,10 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest {
96 .setUsername(authInfo.getUsername()) 96 .setUsername(authInfo.getUsername())
97 .setPassword(authInfo.getPassword()); 97 .setPassword(authInfo.getPassword());
98 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null); 98 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null);
99 - // 1.2 编码  
100 - byte[] payload = CODEC.encode(request); 99 + // 1.2 序列化
  100 + byte[] payload = SERIALIZER.serialize(request);
101 String jsonMessage = StrUtil.utf8Str(payload); 101 String jsonMessage = StrUtil.utf8Str(payload);
102 - log.info("[testAuth][Codec: {}, 请求消息: {}]", CODEC.type(), request); 102 + log.info("[testAuth][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
103 103
104 // 2.1 创建 WebSocket 连接(同步) 104 // 2.1 创建 WebSocket 连接(同步)
105 WebSocket ws = createWebSocketConnection(); 105 WebSocket ws = createWebSocketConnection();
@@ -110,7 +110,7 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { @@ -110,7 +110,7 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest {
110 110
111 // 3. 解码响应 111 // 3. 解码响应
112 if (response != null) { 112 if (response != null) {
113 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 113 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
114 log.info("[testAuth][响应消息: {}]", responseMessage); 114 log.info("[testAuth][响应消息: {}]", responseMessage);
115 } else { 115 } else {
116 log.warn("[testAuth][未收到响应]"); 116 log.warn("[testAuth][未收到响应]");
@@ -146,16 +146,16 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { @@ -146,16 +146,16 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest {
146 .put("temperature", 36.5) 146 .put("temperature", 36.5)
147 .build()), 147 .build()),
148 null, null, null); 148 null, null, null);
149 - // 2.2 编码  
150 - byte[] payload = CODEC.encode(request); 149 + // 2.2 序列化
  150 + byte[] payload = SERIALIZER.serialize(request);
151 String jsonMessage = StrUtil.utf8Str(payload); 151 String jsonMessage = StrUtil.utf8Str(payload);
152 - log.info("[testPropertyPost][Codec: {}, 请求消息: {}]", CODEC.type(), request); 152 + log.info("[testPropertyPost][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
153 153
154 // 3.1 发送并等待响应 154 // 3.1 发送并等待响应
155 String response = sendAndReceive(ws, jsonMessage); 155 String response = sendAndReceive(ws, jsonMessage);
156 // 3.2 解码响应 156 // 3.2 解码响应
157 if (response != null) { 157 if (response != null) {
158 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 158 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
159 log.info("[testPropertyPost][响应消息: {}]", responseMessage); 159 log.info("[testPropertyPost][响应消息: {}]", responseMessage);
160 } else { 160 } else {
161 log.warn("[testPropertyPost][未收到响应]"); 161 log.warn("[testPropertyPost][未收到响应]");
@@ -195,16 +195,16 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { @@ -195,16 +195,16 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest {
195 .build(), 195 .build(),
196 System.currentTimeMillis()), 196 System.currentTimeMillis()),
197 null, null, null); 197 null, null, null);
198 - // 2.2 编码  
199 - byte[] payload = CODEC.encode(request); 198 + // 2.2 序列化
  199 + byte[] payload = SERIALIZER.serialize(request);
200 String jsonMessage = StrUtil.utf8Str(payload); 200 String jsonMessage = StrUtil.utf8Str(payload);
201 - log.info("[testEventPost][Codec: {}, 请求消息: {}]", CODEC.type(), request); 201 + log.info("[testEventPost][Serialize: {}, 请求消息: {}]", SERIALIZER.getType(), request);
202 202
203 // 3.1 发送并等待响应 203 // 3.1 发送并等待响应
204 String response = sendAndReceive(ws, jsonMessage); 204 String response = sendAndReceive(ws, jsonMessage);
205 // 3.2 解码响应 205 // 3.2 解码响应
206 if (response != null) { 206 if (response != null) {
207 - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); 207 + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
208 log.info("[testEventPost][响应消息: {}]", responseMessage); 208 log.info("[testEventPost][响应消息: {}]", responseMessage);
209 } else { 209 } else {
210 log.warn("[testEventPost][未收到响应]"); 210 log.warn("[testEventPost][未收到响应]");
@@ -274,13 +274,13 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { @@ -274,13 +274,13 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest {
274 .setPassword(authInfo.getPassword()); 274 .setPassword(authInfo.getPassword());
275 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null); 275 IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), "auth", authReqDTO, null, null, null);
276 276
277 - byte[] payload = CODEC.encode(request); 277 + byte[] payload = SERIALIZER.serialize(request);
278 String jsonMessage = StrUtil.utf8Str(payload); 278 String jsonMessage = StrUtil.utf8Str(payload);
279 log.info("[authenticate][发送认证请求: {}]", jsonMessage); 279 log.info("[authenticate][发送认证请求: {}]", jsonMessage);
280 280
281 String response = sendAndReceive(ws, jsonMessage); 281 String response = sendAndReceive(ws, jsonMessage);
282 if (response != null) { 282 if (response != null) {
283 - return CODEC.decode(StrUtil.utf8Bytes(response)); 283 + return SERIALIZER.deserialize(StrUtil.utf8Bytes(response));
284 } 284 }
285 return null; 285 return null;
286 } 286 }