Commit d9a08094d9f9640f94f7b2e3cb94961019b8efef
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 | 8 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpProtocol; |
| 9 | 9 | import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpProtocol; |
| 10 | 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 | 12 | import lombok.Getter; |
| 13 | 13 | import lombok.extern.slf4j.Slf4j; |
| 14 | 14 | import org.springframework.context.SmartLifecycle; |
| ... | ... | @@ -158,8 +158,8 @@ public class IotProtocolManager implements SmartLifecycle { |
| 158 | 158 | * @param config 协议实例配置 |
| 159 | 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 | 57 | * TCP 服务器 |
| 58 | 58 | */ |
| 59 | 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 | 71 | * 消息序列化器 |
| 68 | 72 | */ |
| 69 | 73 | private final IotMessageSerializer serializer; |
| 70 | - | |
| 71 | 74 | /** |
| 72 | 75 | * TCP 帧编解码器 |
| 73 | 76 | */ |
| 74 | 77 | private final IotTcpFrameCodec frameCodec; |
| 75 | 78 | |
| 76 | - /** | |
| 77 | - * TCP 连接管理器 | |
| 78 | - */ | |
| 79 | - private final IotTcpConnectionManager connectionManager; | |
| 80 | - | |
| 81 | 79 | public IotTcpProtocol(ProtocolInstanceProperties properties) { |
| 82 | 80 | IotTcpConfig tcpConfig = properties.getTcp(); |
| 83 | 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 | 29 | @Slf4j |
| 30 | 30 | public class IotTcpLengthFieldFrameCodec implements IotTcpFrameCodec { |
| 31 | 31 | |
| 32 | + /** | |
| 33 | + * 最大帧长度(64KB),防止 DoS 攻击 | |
| 34 | + */ | |
| 35 | + private static final int MAX_FRAME_LENGTH = 65536; | |
| 36 | + | |
| 32 | 37 | private final int lengthFieldOffset; |
| 33 | 38 | private final int lengthFieldLength; |
| 34 | 39 | private final int lengthAdjustment; |
| ... | ... | @@ -60,6 +65,7 @@ public class IotTcpLengthFieldFrameCodec implements IotTcpFrameCodec { |
| 60 | 65 | public RecordParser createDecodeParser(Handler<Buffer> handler) { |
| 61 | 66 | // 创建状态机:先读取头部,再读取消息体 |
| 62 | 67 | RecordParser parser = RecordParser.newFixed(headerLength); |
| 68 | + parser.maxRecordSize(MAX_FRAME_LENGTH); // 设置最大记录大小,防止 DoS 攻击 | |
| 63 | 69 | final AtomicReference<Integer> bodyLength = new AtomicReference<>(null); // 消息体长度,null 表示读取头部阶段 |
| 64 | 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<NetSocket> { |
| 77 | 77 | } |
| 78 | 78 | |
| 79 | 79 | @Override |
| 80 | + @SuppressWarnings("DuplicatedCode") | |
| 80 | 81 | public void handle(NetSocket socket) { |
| 82 | + // TODO @AI:clientId 去掉;其它模块也看看,怎么去掉下看看; | |
| 81 | 83 | String clientId = IdUtil.simpleUUID(); |
| 82 | 84 | log.debug("[handle][设备连接,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress()); |
| 83 | 85 | |
| ... | ... | @@ -92,9 +94,10 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 92 | 94 | }); |
| 93 | 95 | |
| 94 | 96 | // 2.1 设置消息处理器 |
| 97 | + // TODO @AI:去掉 clientId; | |
| 95 | 98 | Handler<Buffer> messageHandler = buffer -> { |
| 96 | 99 | try { |
| 97 | - processMessage(clientId, buffer, socket); | |
| 100 | + processMessage(buffer, socket); | |
| 98 | 101 | } catch (Exception e) { |
| 99 | 102 | log.error("[handle][消息处理失败,客户端 ID: {},地址: {}]", |
| 100 | 103 | clientId, socket.remoteAddress(), e); |
| ... | ... | @@ -110,11 +113,10 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 110 | 113 | /** |
| 111 | 114 | * 处理消息 |
| 112 | 115 | * |
| 113 | - * @param clientId 客户端 ID | |
| 114 | 116 | * @param buffer 消息 |
| 115 | 117 | * @param socket 网络连接 |
| 116 | 118 | */ |
| 117 | - private void processMessage(String clientId, Buffer buffer, NetSocket socket) { | |
| 119 | + private void processMessage(Buffer buffer, NetSocket socket) { | |
| 118 | 120 | IotDeviceMessage message = null; |
| 119 | 121 | try { |
| 120 | 122 | // 1. 反序列化消息 |
| ... | ... | @@ -127,29 +129,29 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 127 | 129 | // 2. 根据消息类型路由处理 |
| 128 | 130 | if (AUTH_METHOD.equals(message.getMethod())) { |
| 129 | 131 | // 认证请求 |
| 130 | - handleAuthenticationRequest(clientId, message, socket); | |
| 132 | + handleAuthenticationRequest(message, socket); | |
| 131 | 133 | } else if (IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod().equals(message.getMethod())) { |
| 132 | 134 | // 设备动态注册请求 |
| 133 | - handleRegisterRequest(clientId, message, socket); | |
| 135 | + handleRegisterRequest(message, socket); | |
| 134 | 136 | } else { |
| 135 | 137 | // 业务消息 |
| 136 | - handleBusinessRequest(clientId, message, socket); | |
| 138 | + handleBusinessRequest(null, message, socket); | |
| 137 | 139 | } |
| 138 | 140 | } catch (ServiceException e) { |
| 139 | 141 | // 业务异常,返回对应的错误码和错误信息 |
| 140 | - log.warn("[processMessage][业务异常,客户端 ID: {},错误: {}]", clientId, e.getMessage()); | |
| 142 | + log.warn("[processMessage][业务异常,客户端 ID: {},错误: {}]", null, e.getMessage()); | |
| 141 | 143 | String requestId = message != null ? message.getRequestId() : null; |
| 142 | 144 | String method = message != null ? message.getMethod() : null; |
| 143 | 145 | sendErrorResponse(socket, requestId, method, e.getCode(), e.getMessage()); |
| 144 | 146 | } catch (IllegalArgumentException e) { |
| 145 | 147 | // 参数校验失败,返回 400 |
| 146 | - log.warn("[processMessage][参数校验失败,客户端 ID: {},错误: {}]", clientId, e.getMessage()); | |
| 148 | + log.warn("[processMessage][参数校验失败,客户端 ID: {},错误: {}]", null, e.getMessage()); | |
| 147 | 149 | String requestId = message != null ? message.getRequestId() : null; |
| 148 | 150 | String method = message != null ? message.getMethod() : null; |
| 149 | 151 | sendErrorResponse(socket, requestId, method, BAD_REQUEST.getCode(), e.getMessage()); |
| 150 | 152 | } catch (Exception e) { |
| 151 | 153 | // 其他异常,返回 500,并重新抛出让上层关闭连接 |
| 152 | - log.error("[processMessage][处理消息失败,客户端 ID: {}]", clientId, e); | |
| 154 | + log.error("[processMessage][处理消息失败,客户端 ID: {}]", null, e); | |
| 153 | 155 | String requestId = message != null ? message.getRequestId() : null; |
| 154 | 156 | String method = message != null ? message.getMethod() : null; |
| 155 | 157 | sendErrorResponse(socket, requestId, method, |
| ... | ... | @@ -161,12 +163,11 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 161 | 163 | /** |
| 162 | 164 | * 处理认证请求 |
| 163 | 165 | * |
| 164 | - * @param clientId 客户端 ID | |
| 165 | 166 | * @param message 消息信息 |
| 166 | 167 | * @param socket 网络连接 |
| 167 | 168 | */ |
| 168 | 169 | @SuppressWarnings("DuplicatedCode") |
| 169 | - private void handleAuthenticationRequest(String clientId, IotDeviceMessage message, NetSocket socket) { | |
| 170 | + private void handleAuthenticationRequest(IotDeviceMessage message, NetSocket socket) { | |
| 170 | 171 | // 1. 解析认证参数 |
| 171 | 172 | IotDeviceAuthReqDTO authParams = JsonUtils.convertObject(message.getParams(), IotDeviceAuthReqDTO.class); |
| 172 | 173 | Assert.notNull(authParams, "认证参数不能为空"); |
| ... | ... | @@ -198,13 +199,12 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 198 | 199 | /** |
| 199 | 200 | * 处理设备动态注册请求(一型一密,不需要认证) |
| 200 | 201 | * |
| 201 | - * @param clientId 客户端 ID | |
| 202 | 202 | * @param message 消息信息 |
| 203 | 203 | * @param socket 网络连接 |
| 204 | 204 | * @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">阿里云 - 一型一密</a> |
| 205 | 205 | */ |
| 206 | 206 | @SuppressWarnings("DuplicatedCode") |
| 207 | - private void handleRegisterRequest(String clientId, IotDeviceMessage message, NetSocket socket) { | |
| 207 | + private void handleRegisterRequest(IotDeviceMessage message, NetSocket socket) { | |
| 208 | 208 | // 1. 解析注册参数 |
| 209 | 209 | IotDeviceRegisterReqDTO params = JsonUtils.convertObject(message.getParams(), IotDeviceRegisterReqDTO.class); |
| 210 | 210 | Assert.notNull(params, "注册参数不能为空"); |
| ... | ... | @@ -218,7 +218,7 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { |
| 218 | 218 | // 3. 发送成功响应 |
| 219 | 219 | sendSuccessResponse(socket, message.getRequestId(), |
| 220 | 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 | 55 | */ |
| 56 | 56 | @Getter |
| 57 | 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 | 70 | */ |
| 67 | 71 | private final IotMessageSerializer serializer; |
| 68 | 72 | |
| 69 | - /** | |
| 70 | - * UDP 会话管理器 | |
| 71 | - */ | |
| 72 | - private final IotUdpSessionManager sessionManager; | |
| 73 | - | |
| 74 | 73 | public IotUdpProtocol(ProtocolInstanceProperties properties) { |
| 75 | 74 | IotUdpConfig udpConfig = properties.getUdp(); |
| 76 | 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 | 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 | 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 | 8 | import lombok.RequiredArgsConstructor; |
| 8 | 9 | import lombok.extern.slf4j.Slf4j; |
| 9 | 10 | |
| ... | ... | @@ -16,7 +17,7 @@ import lombok.extern.slf4j.Slf4j; |
| 16 | 17 | @RequiredArgsConstructor |
| 17 | 18 | public class IotWebSocketDownstreamHandler { |
| 18 | 19 | |
| 19 | - private final IotDeviceMessageService deviceMessageService; | |
| 20 | + private final IotMessageSerializer serializer; | |
| 20 | 21 | |
| 21 | 22 | private final IotWebSocketConnectionManager connectionManager; |
| 22 | 23 | |
| ... | ... | @@ -37,9 +38,15 @@ public class IotWebSocketDownstreamHandler { |
| 37 | 38 | } |
| 38 | 39 | |
| 39 | 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 | 50 | if (success) { |
| 44 | 51 | log.info("[handle][下行消息发送成功,设备 ID: {},方法: {},消息 ID: {},数据长度: {} 字节]", |
| 45 | 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 | 3 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 5 | 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 | 7 | import lombok.extern.slf4j.Slf4j; |
| 8 | 8 | |
| 9 | 9 | /** |
| ... | ... | @@ -16,7 +16,7 @@ public class IotWebSocketDownstreamSubscriber extends IotProtocolDownstreamSubsc |
| 16 | 16 | |
| 17 | 17 | private final IotWebSocketDownstreamHandler downstreamHandler; |
| 18 | 18 | |
| 19 | - public IotWebSocketDownstreamSubscriber(IotWebSocketUpstreamProtocol protocol, | |
| 19 | + public IotWebSocketDownstreamSubscriber(IotWebSocketProtocol protocol, | |
| 20 | 20 | IotWebSocketDownstreamHandler downstreamHandler, |
| 21 | 21 | IotMessageBus messageBus) { |
| 22 | 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 | 3 | import cn.hutool.core.map.MapUtil; |
| 4 | +import cn.hutool.core.util.ArrayUtil; | |
| 4 | 5 | import cn.hutool.core.util.BooleanUtil; |
| 5 | 6 | import cn.hutool.core.util.IdUtil; |
| 6 | 7 | import cn.hutool.core.util.StrUtil; |
| ... | ... | @@ -11,17 +12,19 @@ import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; |
| 11 | 12 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; |
| 12 | 13 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO; |
| 13 | 14 | import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; |
| 15 | +import cn.iocoder.yudao.module.iot.core.enums.IotSerializeTypeEnum; | |
| 14 | 16 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 15 | 17 | import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity; |
| 16 | 18 | import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO; |
| 17 | 19 | import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterRespDTO; |
| 18 | 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 | 22 | import cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager.IotWebSocketConnectionManager; |
| 23 | +import cn.iocoder.yudao.module.iot.gateway.serialize.IotMessageSerializer; | |
| 22 | 24 | import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService; |
| 23 | 25 | import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; |
| 24 | 26 | import io.vertx.core.Handler; |
| 27 | +import io.vertx.core.buffer.Buffer; | |
| 25 | 28 | import io.vertx.core.http.ServerWebSocket; |
| 26 | 29 | import lombok.extern.slf4j.Slf4j; |
| 27 | 30 | |
| ... | ... | @@ -36,82 +39,120 @@ import java.util.Map; |
| 36 | 39 | @Slf4j |
| 37 | 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 | 58 | private final IotDeviceMessageService deviceMessageService; |
| 47 | - | |
| 48 | 59 | private final IotDeviceService deviceService; |
| 49 | - | |
| 50 | - private final IotWebSocketConnectionManager connectionManager; | |
| 51 | - | |
| 52 | 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 | 64 | IotDeviceMessageService deviceMessageService, |
| 58 | 65 | IotDeviceService deviceService, |
| 59 | - IotWebSocketConnectionManager connectionManager) { | |
| 66 | + IotWebSocketConnectionManager connectionManager, | |
| 67 | + IotMessageSerializer serializer) { | |
| 60 | 68 | this.deviceMessageService = deviceMessageService; |
| 61 | 69 | this.deviceService = deviceService; |
| 62 | 70 | this.connectionManager = connectionManager; |
| 71 | + this.serializer = serializer; | |
| 72 | + this.binaryPayload = serializer.getType() == IotSerializeTypeEnum.BINARY; | |
| 63 | 73 | this.deviceApi = SpringUtil.getBean(IotDeviceCommonApi.class); |
| 64 | 74 | this.serverId = protocol.getServerId(); |
| 75 | + // TODO @AI:通过 springutil;deviceService、deviceMessageService; | |
| 65 | 76 | } |
| 66 | 77 | |
| 67 | 78 | @Override |
| 79 | + @SuppressWarnings("DuplicatedCode") | |
| 68 | 80 | public void handle(ServerWebSocket socket) { |
| 69 | 81 | String clientId = IdUtil.simpleUUID(); |
| 70 | 82 | log.debug("[handle][设备连接,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress()); |
| 71 | 83 | |
| 72 | 84 | // 1. 设置异常和关闭处理器 |
| 85 | + // TODO @AI:clientId 去掉; | |
| 73 | 86 | socket.exceptionHandler(ex -> { |
| 74 | 87 | log.warn("[handle][连接异常,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress()); |
| 75 | - cleanupConnection(socket); | |
| 88 | + socket.close(); | |
| 76 | 89 | }); |
| 77 | 90 | socket.closeHandler(v -> { |
| 78 | 91 | log.debug("[handle][连接关闭,客户端 ID: {},地址: {}]", clientId, socket.remoteAddress()); |
| 79 | 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 | 111 | cleanupConnection(socket); |
| 90 | 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 | 142 | * @param clientId 客户端 ID |
| 99 | - * @param message 消息(JSON 字符串) | |
| 143 | + * @param payload 消息负载 | |
| 100 | 144 | * @param socket WebSocket 连接 |
| 101 | 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 | 148 | // 1.1 基础检查 |
| 105 | - if (StrUtil.isBlank(message)) { | |
| 149 | + if (ArrayUtil.isEmpty(payload)) { | |
| 106 | 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 | 153 | IotDeviceMessage deviceMessage; |
| 112 | 154 | try { |
| 113 | - deviceMessage = deviceMessageService.decodeDeviceMessage( | |
| 114 | - StrUtil.utf8Bytes(message), codecType); | |
| 155 | + deviceMessage = serializer.deserialize(payload); | |
| 115 | 156 | if (deviceMessage == null) { |
| 116 | 157 | throw new Exception("解码后消息为空"); |
| 117 | 158 | } |
| ... | ... | @@ -132,6 +173,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { |
| 132 | 173 | handleBusinessRequest(clientId, deviceMessage, socket); |
| 133 | 174 | } |
| 134 | 175 | } catch (Exception e) { |
| 176 | + // TODO @AI:参考 IotTcpUpstreamHandler 处理;业务、参数、其它 | |
| 135 | 177 | log.error("[processMessage][处理消息失败,客户端 ID: {},消息方法: {}]", |
| 136 | 178 | clientId, deviceMessage.getMethod(), e); |
| 137 | 179 | // 发送错误响应,避免客户端一直等待 |
| ... | ... | @@ -153,6 +195,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { |
| 153 | 195 | private void handleAuthenticationRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) { |
| 154 | 196 | try { |
| 155 | 197 | // 1.1 解析认证参数 |
| 198 | + // TODO @AI:参数解析;参考 tcp 对应的 handleAuthenticationRequest | |
| 156 | 199 | IotDeviceAuthReqDTO authParams = parseAuthParams(message.getParams()); |
| 157 | 200 | if (authParams == null) { |
| 158 | 201 | log.warn("[handleAuthenticationRequest][认证参数解析失败,客户端 ID: {}]", clientId); |
| ... | ... | @@ -204,6 +247,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { |
| 204 | 247 | * @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">阿里云 - 一型一密</a> |
| 205 | 248 | */ |
| 206 | 249 | private void handleRegisterRequest(String clientId, IotDeviceMessage message, ServerWebSocket socket) { |
| 250 | + // TODO @AI:参数解析;参考 tcp 对应的 handleRegisterRequest | |
| 207 | 251 | try { |
| 208 | 252 | // 1. 解析注册参数 |
| 209 | 253 | IotDeviceRegisterReqDTO params = parseRegisterParams(message.getParams()); |
| ... | ... | @@ -232,6 +276,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { |
| 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<ServerWebSocket> { |
| 270 | 315 | IotWebSocketConnectionManager.ConnectionInfo connectionInfo = new IotWebSocketConnectionManager.ConnectionInfo() |
| 271 | 316 | .setDeviceId(device.getId()) |
| 272 | 317 | .setProductKey(device.getProductKey()) |
| 273 | - .setDeviceName(device.getDeviceName()) | |
| 274 | - .setClientId(clientId) | |
| 275 | - .setCodecType(CODEC_TYPE); | |
| 276 | - // 注册连接 | |
| 318 | + .setDeviceName(device.getDeviceName()); | |
| 277 | 319 | connectionManager.registerConnection(socket, device.getId(), connectionInfo); |
| 278 | 320 | } |
| 279 | 321 | |
| ... | ... | @@ -314,6 +356,8 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { |
| 314 | 356 | } |
| 315 | 357 | } |
| 316 | 358 | |
| 359 | + // ===================== 发送响应消息 ===================== | |
| 360 | + | |
| 317 | 361 | /** |
| 318 | 362 | * 发送响应消息 |
| 319 | 363 | * |
| ... | ... | @@ -332,8 +376,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { |
| 332 | 376 | int code = success ? 0 : 401; |
| 333 | 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 | 380 | } catch (Exception e) { |
| 338 | 381 | log.error("[sendResponse][发送响应失败,requestId: {}]", requestId, e); |
| 339 | 382 | } |
| ... | ... | @@ -461,11 +504,22 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { |
| 461 | 504 | IotDeviceMessage responseMessage = IotDeviceMessage.replyOf(requestId, |
| 462 | 505 | IotDeviceMessageMethodEnum.DEVICE_REGISTER.getMethod(), registerResp, 0, null); |
| 463 | 506 | // 2. 发送响应 |
| 464 | - byte[] encodedData = deviceMessageService.encodeDeviceMessage(responseMessage, CODEC_TYPE); | |
| 465 | - socket.writeTextMessage(StrUtil.utf8Str(encodedData)); | |
| 507 | + writeResponse(socket, responseMessage); | |
| 466 | 508 | } catch (Exception e) { |
| 467 | 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 | 1 | package cn.iocoder.yudao.module.iot.gateway.protocol.websocket.manager; |
| 2 | 2 | |
| 3 | +import io.vertx.core.buffer.Buffer; | |
| 3 | 4 | import io.vertx.core.http.ServerWebSocket; |
| 4 | 5 | import lombok.Data; |
| 5 | 6 | import lombok.experimental.Accessors; |
| 6 | 7 | import lombok.extern.slf4j.Slf4j; |
| 7 | -import org.springframework.stereotype.Component; | |
| 8 | 8 | |
| 9 | 9 | import java.util.Map; |
| 10 | 10 | import java.util.concurrent.ConcurrentHashMap; |
| ... | ... | @@ -20,7 +20,6 @@ import java.util.concurrent.ConcurrentHashMap; |
| 20 | 20 | * @author 芋道源码 |
| 21 | 21 | */ |
| 22 | 22 | @Slf4j |
| 23 | -@Component | |
| 24 | 23 | public class IotWebSocketConnectionManager { |
| 25 | 24 | |
| 26 | 25 | /** |
| ... | ... | @@ -69,7 +68,8 @@ public class IotWebSocketConnectionManager { |
| 69 | 68 | return; |
| 70 | 69 | } |
| 71 | 70 | Long deviceId = connectionInfo.getDeviceId(); |
| 72 | - deviceSocketMap.remove(deviceId); | |
| 71 | + // 仅当 deviceSocketMap 中的 socket 是当前 socket 时才移除,避免误删新连接 | |
| 72 | + deviceSocketMap.remove(deviceId, socket); | |
| 73 | 73 | log.info("[unregisterConnection][注销设备连接,设备 ID: {},连接: {}]", |
| 74 | 74 | deviceId, socket.remoteAddress()); |
| 75 | 75 | } |
| ... | ... | @@ -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 | 162 | */ |
| 136 | 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 | 94 | - id: websocket-json |
| 95 | 95 | type: websocket |
| 96 | 96 | port: 8094 |
| 97 | - enabled: false | |
| 97 | + enabled: true | |
| 98 | 98 | serialize: json |
| 99 | 99 | websocket: |
| 100 | 100 | path: /ws |
| ... | ... | @@ -159,6 +159,7 @@ yudao: |
| 159 | 159 | max-message-size: 8192 |
| 160 | 160 | connect-timeout-seconds: 60 |
| 161 | 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 | 270 | }); |
| 271 | 271 | socket.handler(parser); |
| 272 | 272 | |
| 273 | - // 2.1 序列化 + 帧编码(复用 gateway 的编码逻辑) | |
| 273 | + // 2.1 序列化 + 帧编码 | |
| 274 | 274 | byte[] serializedData = SERIALIZER.serialize(request); |
| 275 | 275 | Buffer frameData = FRAME_CODEC.encode(serializedData); |
| 276 | 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 | 373 | }); |
| 374 | 374 | socket.handler(parser); |
| 375 | 375 | |
| 376 | - // 2.1 序列化 + 帧编码(复用 gateway 的编码逻辑) | |
| 376 | + // 2.1 序列化 + 帧编码 | |
| 377 | 377 | byte[] serializedData = SERIALIZER.serialize(request); |
| 378 | 378 | Buffer frameData = FRAME_CODEC.encode(serializedData); |
| 379 | 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 | 249 | }); |
| 250 | 250 | socket.handler(parser); |
| 251 | 251 | |
| 252 | - // 2.1 序列化 + 帧编码(复用 gateway 的编码逻辑) | |
| 252 | + // 2.1 序列化 + 帧编码 | |
| 253 | 253 | byte[] serializedData = SERIALIZER.serialize(request); |
| 254 | 254 | Buffer frameData = FRAME_CODEC.encode(serializedData); |
| 255 | 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 | 10 | import cn.iocoder.yudao.module.iot.core.topic.event.IotDeviceEventPostReqDTO; |
| 11 | 11 | import cn.iocoder.yudao.module.iot.core.topic.property.IotDevicePropertyPostReqDTO; |
| 12 | 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 | 15 | import io.vertx.core.Vertx; |
| 16 | 16 | import io.vertx.core.http.WebSocket; |
| 17 | 17 | import io.vertx.core.http.WebSocketClient; |
| ... | ... | @@ -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 | 66 | // ===================== 直连设备信息(根据实际情况修改,从 iot_device 表查询) ===================== |
| 67 | 67 | |
| ... | ... | @@ -95,10 +95,10 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { |
| 95 | 95 | .setUsername(authInfo.getUsername()) |
| 96 | 96 | .setPassword(authInfo.getPassword()); |
| 97 | 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 | 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 | 103 | // 2.1 创建 WebSocket 连接(同步) |
| 104 | 104 | WebSocket ws = createWebSocketConnection(); |
| ... | ... | @@ -109,7 +109,7 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { |
| 109 | 109 | |
| 110 | 110 | // 3. 解码响应 |
| 111 | 111 | if (response != null) { |
| 112 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 112 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 113 | 113 | log.info("[testAuth][响应消息: {}]", responseMessage); |
| 114 | 114 | } else { |
| 115 | 115 | log.warn("[testAuth][未收到响应]"); |
| ... | ... | @@ -137,10 +137,10 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { |
| 137 | 137 | registerReqDTO.setProductSecret("test-product-secret"); |
| 138 | 138 | IotDeviceMessage request = IotDeviceMessage.of(IdUtil.fastSimpleUUID(), |
| 139 | 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 | 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 | 145 | // 2.1 创建 WebSocket 连接(同步) |
| 146 | 146 | WebSocket ws = createWebSocketConnection(); |
| ... | ... | @@ -151,7 +151,7 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { |
| 151 | 151 | |
| 152 | 152 | // 3. 解码响应 |
| 153 | 153 | if (response != null) { |
| 154 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 154 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 155 | 155 | log.info("[testDeviceRegister][响应消息: {}]", responseMessage); |
| 156 | 156 | log.info("[testDeviceRegister][成功后可使用返回的 deviceSecret 进行一机一密认证]"); |
| 157 | 157 | } else { |
| ... | ... | @@ -186,16 +186,16 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { |
| 186 | 186 | .put("height", "2") |
| 187 | 187 | .build()), |
| 188 | 188 | null, null, null); |
| 189 | - // 2.2 编码 | |
| 190 | - byte[] payload = CODEC.encode(request); | |
| 189 | + // 2.2 序列化 | |
| 190 | + byte[] payload = SERIALIZER.serialize(request); | |
| 191 | 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 | 194 | // 3.1 发送并等待响应 |
| 195 | 195 | String response = sendAndReceive(ws, jsonMessage); |
| 196 | 196 | // 3.2 解码响应 |
| 197 | 197 | if (response != null) { |
| 198 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 198 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 199 | 199 | log.info("[testPropertyPost][响应消息: {}]", responseMessage); |
| 200 | 200 | } else { |
| 201 | 201 | log.warn("[testPropertyPost][未收到响应]"); |
| ... | ... | @@ -229,16 +229,16 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { |
| 229 | 229 | MapUtil.<String, Object>builder().put("rice", 3).build(), |
| 230 | 230 | System.currentTimeMillis()), |
| 231 | 231 | null, null, null); |
| 232 | - // 2.2 编码 | |
| 233 | - byte[] payload = CODEC.encode(request); | |
| 232 | + // 2.2 序列化 | |
| 233 | + byte[] payload = SERIALIZER.serialize(request); | |
| 234 | 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 | 237 | // 3.1 发送并等待响应 |
| 238 | 238 | String response = sendAndReceive(ws, jsonMessage); |
| 239 | 239 | // 3.2 解码响应 |
| 240 | 240 | if (response != null) { |
| 241 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 241 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 242 | 242 | log.info("[testEventPost][响应消息: {}]", responseMessage); |
| 243 | 243 | } else { |
| 244 | 244 | log.warn("[testEventPost][未收到响应]"); |
| ... | ... | @@ -308,13 +308,13 @@ public class IotDirectDeviceWebSocketProtocolIntegrationTest { |
| 308 | 308 | .setPassword(authInfo.getPassword()); |
| 309 | 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 | 312 | String jsonMessage = StrUtil.utf8Str(payload); |
| 313 | 313 | log.info("[authenticate][发送认证请求: {}]", jsonMessage); |
| 314 | 314 | |
| 315 | 315 | String response = sendAndReceive(ws, jsonMessage); |
| 316 | 316 | if (response != null) { |
| 317 | - return CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 317 | + return SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 318 | 318 | } |
| 319 | 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 | 14 | import cn.iocoder.yudao.module.iot.core.topic.topo.IotDeviceTopoDeleteReqDTO; |
| 15 | 15 | import cn.iocoder.yudao.module.iot.core.topic.topo.IotDeviceTopoGetReqDTO; |
| 16 | 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 | 19 | import io.vertx.core.Vertx; |
| 20 | 20 | import io.vertx.core.http.WebSocket; |
| 21 | 21 | import io.vertx.core.http.WebSocketClient; |
| ... | ... | @@ -67,9 +67,9 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 67 | 67 | |
| 68 | 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 | 74 | // ===================== 网关设备信息(根据实际情况修改,从 iot_device 表查询网关设备) ===================== |
| 75 | 75 | |
| ... | ... | @@ -110,10 +110,10 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 110 | 110 | .setUsername(authInfo.getUsername()) |
| 111 | 111 | .setPassword(authInfo.getPassword()); |
| 112 | 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 | 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 | 118 | // 2.1 创建 WebSocket 连接(同步) |
| 119 | 119 | WebSocket ws = createWebSocketConnection(); |
| ... | ... | @@ -124,7 +124,7 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 124 | 124 | |
| 125 | 125 | // 3. 解码响应 |
| 126 | 126 | if (response != null) { |
| 127 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 127 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 128 | 128 | log.info("[testAuth][响应消息: {}]", responseMessage); |
| 129 | 129 | } else { |
| 130 | 130 | log.warn("[testAuth][未收到响应]"); |
| ... | ... | @@ -164,16 +164,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 164 | 164 | IotDeviceMessageMethodEnum.TOPO_ADD.getMethod(), |
| 165 | 165 | params, |
| 166 | 166 | null, null, null); |
| 167 | - // 2.3 编码 | |
| 168 | - byte[] payload = CODEC.encode(request); | |
| 167 | + // 2.3 序列化 | |
| 168 | + byte[] payload = SERIALIZER.serialize(request); | |
| 169 | 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 | 172 | // 3.1 发送并等待响应 |
| 173 | 173 | String response = sendAndReceive(ws, jsonMessage); |
| 174 | 174 | // 3.2 解码响应 |
| 175 | 175 | if (response != null) { |
| 176 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 176 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 177 | 177 | log.info("[testTopoAdd][响应消息: {}]", responseMessage); |
| 178 | 178 | } else { |
| 179 | 179 | log.warn("[testTopoAdd][未收到响应]"); |
| ... | ... | @@ -205,16 +205,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 205 | 205 | IotDeviceMessageMethodEnum.TOPO_DELETE.getMethod(), |
| 206 | 206 | params, |
| 207 | 207 | null, null, null); |
| 208 | - // 2.2 编码 | |
| 209 | - byte[] payload = CODEC.encode(request); | |
| 208 | + // 2.2 序列化 | |
| 209 | + byte[] payload = SERIALIZER.serialize(request); | |
| 210 | 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 | 213 | // 3.1 发送并等待响应 |
| 214 | 214 | String response = sendAndReceive(ws, jsonMessage); |
| 215 | 215 | // 3.2 解码响应 |
| 216 | 216 | if (response != null) { |
| 217 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 217 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 218 | 218 | log.info("[testTopoDelete][响应消息: {}]", responseMessage); |
| 219 | 219 | } else { |
| 220 | 220 | log.warn("[testTopoDelete][未收到响应]"); |
| ... | ... | @@ -244,16 +244,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 244 | 244 | IotDeviceMessageMethodEnum.TOPO_GET.getMethod(), |
| 245 | 245 | params, |
| 246 | 246 | null, null, null); |
| 247 | - // 2.2 编码 | |
| 248 | - byte[] payload = CODEC.encode(request); | |
| 247 | + // 2.2 序列化 | |
| 248 | + byte[] payload = SERIALIZER.serialize(request); | |
| 249 | 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 | 252 | // 3.1 发送并等待响应 |
| 253 | 253 | String response = sendAndReceive(ws, jsonMessage); |
| 254 | 254 | // 3.2 解码响应 |
| 255 | 255 | if (response != null) { |
| 256 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 256 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 257 | 257 | log.info("[testTopoGet][响应消息: {}]", responseMessage); |
| 258 | 258 | } else { |
| 259 | 259 | log.warn("[testTopoGet][未收到响应]"); |
| ... | ... | @@ -287,16 +287,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 287 | 287 | IotDeviceMessageMethodEnum.SUB_DEVICE_REGISTER.getMethod(), |
| 288 | 288 | Collections.singletonList(subDevice), |
| 289 | 289 | null, null, null); |
| 290 | - // 2.2 编码 | |
| 291 | - byte[] payload = CODEC.encode(request); | |
| 290 | + // 2.2 序列化 | |
| 291 | + byte[] payload = SERIALIZER.serialize(request); | |
| 292 | 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 | 295 | // 3.1 发送并等待响应 |
| 296 | 296 | String response = sendAndReceive(ws, jsonMessage); |
| 297 | 297 | // 3.2 解码响应 |
| 298 | 298 | if (response != null) { |
| 299 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 299 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 300 | 300 | log.info("[testSubDeviceRegister][响应消息: {}]", responseMessage); |
| 301 | 301 | } else { |
| 302 | 302 | log.warn("[testSubDeviceRegister][未收到响应]"); |
| ... | ... | @@ -358,16 +358,16 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 358 | 358 | IotDeviceMessageMethodEnum.PROPERTY_PACK_POST.getMethod(), |
| 359 | 359 | params, |
| 360 | 360 | null, null, null); |
| 361 | - // 2.7 编码 | |
| 362 | - byte[] payload = CODEC.encode(request); | |
| 361 | + // 2.7 序列化 | |
| 362 | + byte[] payload = SERIALIZER.serialize(request); | |
| 363 | 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 | 366 | // 3.1 发送并等待响应 |
| 367 | 367 | String response = sendAndReceive(ws, jsonMessage); |
| 368 | 368 | // 3.2 解码响应 |
| 369 | 369 | if (response != null) { |
| 370 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 370 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 371 | 371 | log.info("[testPropertyPackPost][响应消息: {}]", responseMessage); |
| 372 | 372 | } else { |
| 373 | 373 | log.warn("[testPropertyPackPost][未收到响应]"); |
| ... | ... | @@ -438,13 +438,13 @@ public class IotGatewayDeviceWebSocketProtocolIntegrationTest { |
| 438 | 438 | .setPassword(authInfo.getPassword()); |
| 439 | 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 | 442 | String jsonMessage = StrUtil.utf8Str(payload); |
| 443 | 443 | log.info("[authenticate][发送认证请求: {}]", jsonMessage); |
| 444 | 444 | |
| 445 | 445 | String response = sendAndReceive(ws, jsonMessage); |
| 446 | 446 | if (response != null) { |
| 447 | - return CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 447 | + return SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 448 | 448 | } |
| 449 | 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 | 9 | import cn.iocoder.yudao.module.iot.core.topic.event.IotDeviceEventPostReqDTO; |
| 10 | 10 | import cn.iocoder.yudao.module.iot.core.topic.property.IotDevicePropertyPostReqDTO; |
| 11 | 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 | 14 | import io.vertx.core.Vertx; |
| 15 | 15 | import io.vertx.core.http.WebSocket; |
| 16 | 16 | import io.vertx.core.http.WebSocketClient; |
| ... | ... | @@ -60,9 +60,9 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { |
| 60 | 60 | |
| 61 | 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 | 67 | // ===================== 网关子设备信息(根据实际情况修改,从 iot_device 表查询子设备) ===================== |
| 68 | 68 | |
| ... | ... | @@ -96,10 +96,10 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { |
| 96 | 96 | .setUsername(authInfo.getUsername()) |
| 97 | 97 | .setPassword(authInfo.getPassword()); |
| 98 | 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 | 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 | 104 | // 2.1 创建 WebSocket 连接(同步) |
| 105 | 105 | WebSocket ws = createWebSocketConnection(); |
| ... | ... | @@ -110,7 +110,7 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { |
| 110 | 110 | |
| 111 | 111 | // 3. 解码响应 |
| 112 | 112 | if (response != null) { |
| 113 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 113 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 114 | 114 | log.info("[testAuth][响应消息: {}]", responseMessage); |
| 115 | 115 | } else { |
| 116 | 116 | log.warn("[testAuth][未收到响应]"); |
| ... | ... | @@ -146,16 +146,16 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { |
| 146 | 146 | .put("temperature", 36.5) |
| 147 | 147 | .build()), |
| 148 | 148 | null, null, null); |
| 149 | - // 2.2 编码 | |
| 150 | - byte[] payload = CODEC.encode(request); | |
| 149 | + // 2.2 序列化 | |
| 150 | + byte[] payload = SERIALIZER.serialize(request); | |
| 151 | 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 | 154 | // 3.1 发送并等待响应 |
| 155 | 155 | String response = sendAndReceive(ws, jsonMessage); |
| 156 | 156 | // 3.2 解码响应 |
| 157 | 157 | if (response != null) { |
| 158 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 158 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 159 | 159 | log.info("[testPropertyPost][响应消息: {}]", responseMessage); |
| 160 | 160 | } else { |
| 161 | 161 | log.warn("[testPropertyPost][未收到响应]"); |
| ... | ... | @@ -195,16 +195,16 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { |
| 195 | 195 | .build(), |
| 196 | 196 | System.currentTimeMillis()), |
| 197 | 197 | null, null, null); |
| 198 | - // 2.2 编码 | |
| 199 | - byte[] payload = CODEC.encode(request); | |
| 198 | + // 2.2 序列化 | |
| 199 | + byte[] payload = SERIALIZER.serialize(request); | |
| 200 | 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 | 203 | // 3.1 发送并等待响应 |
| 204 | 204 | String response = sendAndReceive(ws, jsonMessage); |
| 205 | 205 | // 3.2 解码响应 |
| 206 | 206 | if (response != null) { |
| 207 | - IotDeviceMessage responseMessage = CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 207 | + IotDeviceMessage responseMessage = SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 208 | 208 | log.info("[testEventPost][响应消息: {}]", responseMessage); |
| 209 | 209 | } else { |
| 210 | 210 | log.warn("[testEventPost][未收到响应]"); |
| ... | ... | @@ -274,13 +274,13 @@ public class IotGatewaySubDeviceWebSocketProtocolIntegrationTest { |
| 274 | 274 | .setPassword(authInfo.getPassword()); |
| 275 | 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 | 278 | String jsonMessage = StrUtil.utf8Str(payload); |
| 279 | 279 | log.info("[authenticate][发送认证请求: {}]", jsonMessage); |
| 280 | 280 | |
| 281 | 281 | String response = sendAndReceive(ws, jsonMessage); |
| 282 | 282 | if (response != null) { |
| 283 | - return CODEC.decode(StrUtil.utf8Bytes(response)); | |
| 283 | + return SERIALIZER.deserialize(StrUtil.utf8Bytes(response)); | |
| 284 | 284 | } |
| 285 | 285 | return null; |
| 286 | 286 | } | ... | ... |