From df210f968dbe04e39d885e5f5c2d0d33b812d03e Mon Sep 17 00:00:00 2001 From: godotg Date: Mon, 12 Sep 2022 09:03:04 +0800 Subject: [PATCH] =?UTF-8?q?feat[json]:=20=E6=94=AF=E6=8C=81json=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=A0=BC=E5=BC=8F=E7=9A=84=E6=9C=8D=E5=8A=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/core/json/JsonWebsocketClient.java | 61 ++++++++++++++++++ .../net/core/json/JsonWebsocketServer.java | 64 +++++++++++++++++++ .../net/handler/codec/json/JsonPacket.java | 50 +++++++++++++++ .../codec/json/JsonWebSocketCodecHandler.java | 61 ++++++++++++++++++ .../json/client/JsonWebsocketClientTest.java | 57 +++++++++++++++++ .../json/client/JsonWsClientController.java | 38 +++++++++++ .../json/server/JsonWebsocketServerTest.java | 40 ++++++++++++ .../json/server/JsonWsServerController.java | 45 +++++++++++++ 8 files changed, 416 insertions(+) create mode 100644 net/src/main/java/com/zfoo/net/core/json/JsonWebsocketClient.java create mode 100644 net/src/main/java/com/zfoo/net/core/json/JsonWebsocketServer.java create mode 100644 net/src/main/java/com/zfoo/net/handler/codec/json/JsonPacket.java create mode 100644 net/src/main/java/com/zfoo/net/handler/codec/json/JsonWebSocketCodecHandler.java create mode 100644 net/src/test/java/com/zfoo/net/core/json/client/JsonWebsocketClientTest.java create mode 100644 net/src/test/java/com/zfoo/net/core/json/client/JsonWsClientController.java create mode 100644 net/src/test/java/com/zfoo/net/core/json/server/JsonWebsocketServerTest.java create mode 100644 net/src/test/java/com/zfoo/net/core/json/server/JsonWsServerController.java diff --git a/net/src/main/java/com/zfoo/net/core/json/JsonWebsocketClient.java b/net/src/main/java/com/zfoo/net/core/json/JsonWebsocketClient.java new file mode 100644 index 00000000..abc58d44 --- /dev/null +++ b/net/src/main/java/com/zfoo/net/core/json/JsonWebsocketClient.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.net.core.json; + +import com.zfoo.net.core.AbstractClient; +import com.zfoo.net.handler.ClientRouteHandler; +import com.zfoo.net.handler.codec.json.JsonWebSocketCodecHandler; +import com.zfoo.protocol.util.IOUtils; +import com.zfoo.util.net.HostAndPort; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolConfig; +import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler; +import io.netty.handler.stream.ChunkedWriteHandler; + +/** + * @author godotg + * @version 3.0 + */ +public class JsonWebsocketClient extends AbstractClient { + + private WebSocketClientProtocolConfig webSocketClientProtocolConfig; + + public JsonWebsocketClient(HostAndPort host, WebSocketClientProtocolConfig webSocketClientProtocolConfig) { + super(host); + this.webSocketClientProtocolConfig = webSocketClientProtocolConfig; + } + + @Override + public ChannelInitializer channelChannelInitializer() { + return new ChannelHandlerInitializer(); + } + + + public class ChannelHandlerInitializer extends ChannelInitializer { + @Override + public void initChannel(SocketChannel channel) { + channel.pipeline().addLast(new HttpClientCodec(8 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB)); + channel.pipeline().addLast(new HttpObjectAggregator(16 * IOUtils.BYTES_PER_MB)); + channel.pipeline().addLast(new WebSocketClientProtocolHandler(webSocketClientProtocolConfig)); + channel.pipeline().addLast(new ChunkedWriteHandler()); + channel.pipeline().addLast(new JsonWebSocketCodecHandler()); + channel.pipeline().addLast(new ClientRouteHandler()); + } + } + +} diff --git a/net/src/main/java/com/zfoo/net/core/json/JsonWebsocketServer.java b/net/src/main/java/com/zfoo/net/core/json/JsonWebsocketServer.java new file mode 100644 index 00000000..70a587b3 --- /dev/null +++ b/net/src/main/java/com/zfoo/net/core/json/JsonWebsocketServer.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.net.core.json; + +import com.zfoo.net.core.AbstractServer; +import com.zfoo.net.handler.ServerRouteHandler; +import com.zfoo.net.handler.codec.json.JsonWebSocketCodecHandler; +import com.zfoo.net.handler.codec.websocket.WebSocketCodecHandler; +import com.zfoo.protocol.util.IOUtils; +import com.zfoo.util.net.HostAndPort; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.handler.stream.ChunkedWriteHandler; + +/** + * @author godotg + * @version 3.0 + */ +public class JsonWebsocketServer extends AbstractServer { + + public JsonWebsocketServer(HostAndPort host) { + super(host); + } + + @Override + public ChannelInitializer channelChannelInitializer() { + return new ChannelHandlerInitializer(); + } + + + public static class ChannelHandlerInitializer extends ChannelInitializer { + + @Override + public void initChannel(SocketChannel channel) { + // 编解码 http 请求 + channel.pipeline().addLast(new HttpServerCodec(8 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB, 16 * IOUtils.BYTES_PER_KB)); + // 聚合解码 HttpRequest/HttpContent/LastHttpContent 到 FullHttpRequest + // 保证接收的 Http 请求的完整性 + channel.pipeline().addLast(new HttpObjectAggregator(16 * IOUtils.BYTES_PER_MB)); + // 处理其他的 WebSocketFrame + channel.pipeline().addLast(new WebSocketServerProtocolHandler("/websocket")); + // 写文件内容,支持异步发送大的码流,一般用于发送文件流 + channel.pipeline().addLast(new ChunkedWriteHandler()); + // 编解码WebSocketFrame二进制协议 + channel.pipeline().addLast(new JsonWebSocketCodecHandler()); + channel.pipeline().addLast(new ServerRouteHandler()); + } + } + +} diff --git a/net/src/main/java/com/zfoo/net/handler/codec/json/JsonPacket.java b/net/src/main/java/com/zfoo/net/handler/codec/json/JsonPacket.java new file mode 100644 index 00000000..122659a1 --- /dev/null +++ b/net/src/main/java/com/zfoo/net/handler/codec/json/JsonPacket.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + * + */ + +package com.zfoo.net.handler.codec.json; + +import com.zfoo.protocol.IPacket; + +/** + * @author godotg + * @version 3.0 + */ +public class JsonPacket { + + private short protocolId; + + private IPacket packet; + + public static JsonPacket valueOf(short protocolId, IPacket packet) { + var jsonPacket = new JsonPacket(); + jsonPacket.protocolId = protocolId; + jsonPacket.packet = packet; + return jsonPacket; + } + + public short getProtocolId() { + return protocolId; + } + + public void setProtocolId(short protocolId) { + this.protocolId = protocolId; + } + + public IPacket getPacket() { + return packet; + } + + public void setPacket(IPacket packet) { + this.packet = packet; + } +} diff --git a/net/src/main/java/com/zfoo/net/handler/codec/json/JsonWebSocketCodecHandler.java b/net/src/main/java/com/zfoo/net/handler/codec/json/JsonWebSocketCodecHandler.java new file mode 100644 index 00000000..68602858 --- /dev/null +++ b/net/src/main/java/com/zfoo/net/handler/codec/json/JsonWebSocketCodecHandler.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.net.handler.codec.json; + +import com.zfoo.net.packet.model.DecodedPacketInfo; +import com.zfoo.net.packet.model.EncodedPacketInfo; +import com.zfoo.protocol.IPacket; +import com.zfoo.protocol.ProtocolManager; +import com.zfoo.protocol.buffer.ByteBufUtils; +import com.zfoo.protocol.util.JsonUtils; +import com.zfoo.protocol.util.StringUtils; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; +import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; + +import java.util.List; + +/** + * @author godotg + * @version 3.0 + */ +public class JsonWebSocketCodecHandler extends MessageToMessageCodec { + + @Override + protected void decode(ChannelHandlerContext channelHandlerContext, WebSocketFrame webSocketFrame, List list) { + var byteBuf = webSocketFrame.content(); + var bytes = ByteBufUtils.readAllBytes(byteBuf); + var jsonStr = StringUtils.bytesToString(bytes); + var jsonMap = JsonUtils.getJsonMap(jsonStr); + var protocolId = Short.parseShort(jsonMap.get("protocolId")); + var packetStr = jsonMap.get("packet"); + var protocolClass = ProtocolManager.getProtocol(protocolId).protocolConstructor().getDeclaringClass(); + var packet = JsonUtils.string2Object(packetStr, protocolClass); + list.add(DecodedPacketInfo.valueOf((IPacket) packet, null)); + } + + @Override + protected void encode(ChannelHandlerContext channelHandlerContext, EncodedPacketInfo out, List list) { + var byteBuf = channelHandlerContext.alloc().ioBuffer(); + + var packet = out.getPacket(); + var jsonPacket = JsonPacket.valueOf(packet.protocolId(), packet); + var bytes = StringUtils.bytes(JsonUtils.object2String(jsonPacket)); + byteBuf.writeBytes(bytes); + + list.add(new BinaryWebSocketFrame(byteBuf)); + } + +} diff --git a/net/src/test/java/com/zfoo/net/core/json/client/JsonWebsocketClientTest.java b/net/src/test/java/com/zfoo/net/core/json/client/JsonWebsocketClientTest.java new file mode 100644 index 00000000..53698ab8 --- /dev/null +++ b/net/src/test/java/com/zfoo/net/core/json/client/JsonWebsocketClientTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.net.core.json.client; + +import com.zfoo.net.NetContext; +import com.zfoo.net.core.json.JsonWebsocketClient; +import com.zfoo.net.core.websocket.WebsocketClient; +import com.zfoo.net.packet.websocket.WebsocketHelloRequest; +import com.zfoo.util.ThreadUtils; +import com.zfoo.util.net.HostAndPort; +import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolConfig; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author godotg + * @version 3.0 + */ +@Ignore +public class JsonWebsocketClientTest { + + @Test + public void startClient() { + var context = new ClassPathXmlApplicationContext("config.xml"); + + var webSocketClientProtocolConfig = WebSocketClientProtocolConfig.newBuilder() + .webSocketUri("http://127.0.0.1:9000/websocket") + .build(); + + var client = new JsonWebsocketClient(HostAndPort.valueOf("127.0.0.1:9000"), webSocketClientProtocolConfig); + var session = client.start(); + + var request = new WebsocketHelloRequest(); + request.setMessage("Hello, this is the websocket client!"); + + for (int i = 0; i < 1000; i++) { + ThreadUtils.sleep(2000); + NetContext.getRouter().send(session, request); + } + + ThreadUtils.sleep(Long.MAX_VALUE); + } + + +} diff --git a/net/src/test/java/com/zfoo/net/core/json/client/JsonWsClientController.java b/net/src/test/java/com/zfoo/net/core/json/client/JsonWsClientController.java new file mode 100644 index 00000000..d1d922d1 --- /dev/null +++ b/net/src/test/java/com/zfoo/net/core/json/client/JsonWsClientController.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + * + */ + +package com.zfoo.net.core.json.client; + +import com.zfoo.net.packet.websocket.WebsocketHelloResponse; +import com.zfoo.net.router.receiver.PacketReceiver; +import com.zfoo.net.session.model.Session; +import com.zfoo.protocol.util.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * @author godotg + * @version 3.0 + */ +@Component +public class JsonWsClientController { + + private static final Logger logger = LoggerFactory.getLogger(JsonWsClientController.class); + + @PacketReceiver + public void atWebsocketHelloResponse(Session session, WebsocketHelloResponse response) { + logger.info("websocket client receive [packet:{}] from server", JsonUtils.object2String(response)); + } + +} diff --git a/net/src/test/java/com/zfoo/net/core/json/server/JsonWebsocketServerTest.java b/net/src/test/java/com/zfoo/net/core/json/server/JsonWebsocketServerTest.java new file mode 100644 index 00000000..b5feadc7 --- /dev/null +++ b/net/src/test/java/com/zfoo/net/core/json/server/JsonWebsocketServerTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.net.core.json.server; + +import com.zfoo.net.core.json.JsonWebsocketServer; +import com.zfoo.util.ThreadUtils; +import com.zfoo.util.net.HostAndPort; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author godotg + * @version 3.0 + */ +@Ignore +public class JsonWebsocketServerTest { + + @Test + public void startServer() { + var context = new ClassPathXmlApplicationContext("config.xml"); + + var server = new JsonWebsocketServer(HostAndPort.valueOf("127.0.0.1:9000")); + server.start(); + + ThreadUtils.sleep(Long.MAX_VALUE); + } + +} diff --git a/net/src/test/java/com/zfoo/net/core/json/server/JsonWsServerController.java b/net/src/test/java/com/zfoo/net/core/json/server/JsonWsServerController.java new file mode 100644 index 00000000..752ed3f0 --- /dev/null +++ b/net/src/test/java/com/zfoo/net/core/json/server/JsonWsServerController.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + * + */ + +package com.zfoo.net.core.json.server; + +import com.zfoo.net.NetContext; +import com.zfoo.net.packet.websocket.WebsocketHelloRequest; +import com.zfoo.net.packet.websocket.WebsocketHelloResponse; +import com.zfoo.net.router.receiver.PacketReceiver; +import com.zfoo.net.session.model.Session; +import com.zfoo.protocol.util.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * @author godotg + * @version 3.0 + */ +@Component +public class JsonWsServerController { + + private static final Logger logger = LoggerFactory.getLogger(JsonWsServerController.class); + + @PacketReceiver + public void atWebsocketHelloRequest(Session session, WebsocketHelloRequest request) { + logger.info("receive [packet:{}] from browser", JsonUtils.object2String(request)); + + var response = new WebsocketHelloResponse(); + response.setMessage("Hello, this is the websocket server!"); + + NetContext.getRouter().send(session, response); + } + +}