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,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<NetSocket> { | @@ -77,7 +77,9 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { | ||
| 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<NetSocket> { | @@ -92,9 +94,10 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { | ||
| 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<NetSocket> { | @@ -110,11 +113,10 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { | ||
| 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<NetSocket> { | @@ -127,29 +129,29 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { | ||
| 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<NetSocket> { | @@ -161,12 +163,11 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { | ||
| 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<NetSocket> { | @@ -198,13 +199,12 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { | ||
| 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<NetSocket> { | @@ -218,7 +218,7 @@ public class IotTcpUpstreamHandler implements Handler<NetSocket> { | ||
| 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<ServerWebSocket> { | @@ -132,6 +173,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { | ||
| 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<ServerWebSocket> { | @@ -153,6 +195,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { | ||
| 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<ServerWebSocket> { | @@ -204,6 +247,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { | ||
| 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<ServerWebSocket> { | @@ -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,10 +315,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { | ||
| 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<ServerWebSocket> { | @@ -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,8 +376,7 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { | ||
| 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<ServerWebSocket> { | @@ -461,11 +504,22 @@ public class IotWebSocketUpstreamHandler implements Handler<ServerWebSocket> { | ||
| 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 | } |