From 81ad455de083f0103f9ef3645b23ea149cfae5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lkd9125=28=EC=9D=B4=EA=B2=BD=EB=8F=84=29?= Date: Tue, 3 Sep 2024 19:03:40 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20WebSocket=20=EC=8B=A4=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=EA=B8=B0=EB=8A=A5=EC=B6=94=EA=B0=80,=20WebSocket=20?= =?UTF-8?q?=EC=A0=91=EC=86=8D=20=EC=9C=A0=EC=A0=80=20=EA=B7=B8=EB=A3=B9=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- http/server/server.http | 8 ++++- .../server/collection/ChannelCollection.java | 23 ++++++++++++- .../controller/SocketReceiverController.java | 23 +++++++++++++ .../com/palnet/server/handler/WebHandler.java | 5 ++- .../palnet/server/handler/WebPathHandler.java | 34 +++++++++++++++++++ .../server/initializer/WebInitializer.java | 28 +++++++++------ .../com/palnet/server/model/DosUpdateRQ.java | 11 ++++++ .../palnet/server/task/ctr/CtrCntrlTask.java | 2 +- 8 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 pav-websocket/src/main/java/com/palnet/server/handler/WebPathHandler.java create mode 100644 pav-websocket/src/main/java/com/palnet/server/model/DosUpdateRQ.java diff --git a/http/server/server.http b/http/server/server.http index ce7a735a..8f2193fa 100644 --- a/http/server/server.http +++ b/http/server/server.http @@ -265,4 +265,10 @@ Authorization: {{accessToken}} ### 비행 관제 사용자 권한 정보 GET {{appHost}}/api/ctr/cntrl/group -Authorization: {{accessToken}} \ No newline at end of file +Authorization: {{accessToken}} + +### WS +WEBSOCKET ws://localhost:8081/ws + +### DOS +WEBSOCKET ws://localhost:8081/ws/dos \ No newline at end of file diff --git a/pav-websocket/src/main/java/com/palnet/server/collection/ChannelCollection.java b/pav-websocket/src/main/java/com/palnet/server/collection/ChannelCollection.java index 65246901..5180aff7 100644 --- a/pav-websocket/src/main/java/com/palnet/server/collection/ChannelCollection.java +++ b/pav-websocket/src/main/java/com/palnet/server/collection/ChannelCollection.java @@ -12,15 +12,36 @@ public class ChannelCollection { //접속 되어있는 모든 Channel private static final ChannelGroup allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + + private static final ChannelGroup wsChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + private static final ChannelGroup dosChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); public void setAllChannels(Channel ch) { allChannels.add(ch); } + + public static void setChannels(Channel ch, String uri) { + switch (uri){ + case "/ws": + wsChannels.add(ch); + break; + case "/dos": + dosChannels.add(ch); + break; + } + } - public ChannelGroup getAllChannels() { + public static ChannelGroup getAllChannels() { return allChannels; } + + public static ChannelGroup getWsChannels() { + return wsChannels; + } + public static ChannelGroup getDosChannels() { + return dosChannels; + } } diff --git a/pav-websocket/src/main/java/com/palnet/server/controller/SocketReceiverController.java b/pav-websocket/src/main/java/com/palnet/server/controller/SocketReceiverController.java index af22a5e3..17dd7d35 100644 --- a/pav-websocket/src/main/java/com/palnet/server/controller/SocketReceiverController.java +++ b/pav-websocket/src/main/java/com/palnet/server/controller/SocketReceiverController.java @@ -5,7 +5,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.palnet.comn.model.CtrCntrlModel; import com.palnet.comn.model.CtrHistoryShareContext; import com.palnet.comn.model.GPModel; +import com.palnet.server.collection.ChannelCollection; +import com.palnet.server.model.DosUpdateRQ; import com.palnet.server.task.ctr.service.CtrCntrlTaskService; +import io.netty.channel.group.ChannelGroup; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -64,4 +68,23 @@ public class SocketReceiverController { return "OK"; }; } + + @PostMapping("/dos/flush") + public void dataFlush(@RequestBody DosUpdateRQ rq){ + log.warn("rq => {}", rq); + + if(rq.getPlanAreaSnoList() != null){ + try { + String json = objectMapper.writeValueAsString(rq); + + ChannelGroup dosChannel = ChannelCollection.getDosChannels(); + dosChannel.writeAndFlush(new TextWebSocketFrame(json)); + } catch (JsonProcessingException e) { + log.error("", e); + } + } else { + log.error("RQ IS NULL :: {}", rq); + } + } + } diff --git a/pav-websocket/src/main/java/com/palnet/server/handler/WebHandler.java b/pav-websocket/src/main/java/com/palnet/server/handler/WebHandler.java index 3106d486..d9fdec2b 100644 --- a/pav-websocket/src/main/java/com/palnet/server/handler/WebHandler.java +++ b/pav-websocket/src/main/java/com/palnet/server/handler/WebHandler.java @@ -119,5 +119,8 @@ public class WebHandler extends SimpleChannelInboundHandler { logger.info("==================== [ channelRegistered ] ==================== "); } - + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error("", cause); + } } diff --git a/pav-websocket/src/main/java/com/palnet/server/handler/WebPathHandler.java b/pav-websocket/src/main/java/com/palnet/server/handler/WebPathHandler.java new file mode 100644 index 00000000..c0bde102 --- /dev/null +++ b/pav-websocket/src/main/java/com/palnet/server/handler/WebPathHandler.java @@ -0,0 +1,34 @@ +package com.palnet.server.handler; + +import com.palnet.server.collection.ChannelCollection; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.*; +import lombok.extern.slf4j.Slf4j; + +import java.net.URI; + +@Slf4j +public class WebPathHandler extends SimpleChannelInboundHandler { + + + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { + if(msg != null){ + URI url = new URI(msg.uri()); + String uri = url.getPath(); + + switch (uri) { + case "/dos": + case "/ws": + ChannelCollection.setChannels(ctx.channel(), uri); + break; + default: + throw new RuntimeException("Path Not Found"); + } + + msg.setUri("/ws"); + ctx.fireChannelRead(msg.retain()); + } + } +} diff --git a/pav-websocket/src/main/java/com/palnet/server/initializer/WebInitializer.java b/pav-websocket/src/main/java/com/palnet/server/initializer/WebInitializer.java index 2167dafd..ecc94296 100644 --- a/pav-websocket/src/main/java/com/palnet/server/initializer/WebInitializer.java +++ b/pav-websocket/src/main/java/com/palnet/server/initializer/WebInitializer.java @@ -3,31 +3,39 @@ package com.palnet.server.initializer; import com.palnet.server.codec.WebPayLoadDecoder; import com.palnet.server.codec.WebPayLoadEncorder; import com.palnet.server.handler.WebHandler; +import com.palnet.server.handler.WebPathHandler; +import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; 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.HttpServerExpectContinueHandler; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler; -import io.netty.handler.codec.json.JsonObjectDecoder; import io.netty.handler.timeout.IdleStateHandler; -import org.springframework.stereotype.Component; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class WebInitializer extends ChannelInitializer{ @Override protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); pipeline - .addLast(new HttpServerCodec()) - .addLast(new HttpObjectAggregator(65536)) - .addLast(new WebSocketServerCompressionHandler()) - .addLast(new WebSocketServerProtocolHandler("/ws", null, true)) - .addLast(new IdleStateHandler(0, 0, 180)) // [5] - .addLast(new WebPayLoadDecoder() , new WebPayLoadEncorder()) - .addLast(new WebHandler()); + .addLast(new HttpServerCodec()) + .addLast(new HttpObjectAggregator(65536)) + .addLast(new WebSocketServerCompressionHandler()) + .addLast(new HttpServerExpectContinueHandler()) + .addLast(new WebPathHandler()) // 분기처리 핸들러 + .addLast(new WebSocketServerProtocolHandler("/ws")) // 핸드쉐이크를 위한 핸들러 [핸드쉐이크가 성공해야 연결] + .addLast(new WebHandler()) // 웹소켓 연결 후 핸들러 + .addLast(new IdleStateHandler(0, 0, 180)) // [5] + .addLast(new WebPayLoadDecoder() , new WebPayLoadEncorder()) + ; } - + + } diff --git a/pav-websocket/src/main/java/com/palnet/server/model/DosUpdateRQ.java b/pav-websocket/src/main/java/com/palnet/server/model/DosUpdateRQ.java new file mode 100644 index 00000000..f8377bbd --- /dev/null +++ b/pav-websocket/src/main/java/com/palnet/server/model/DosUpdateRQ.java @@ -0,0 +1,11 @@ +package com.palnet.server.model; + +import lombok.Data; + +import java.util.List; + +@Data +public class DosUpdateRQ { + + private List planAreaSnoList; +} diff --git a/pav-websocket/src/main/java/com/palnet/server/task/ctr/CtrCntrlTask.java b/pav-websocket/src/main/java/com/palnet/server/task/ctr/CtrCntrlTask.java index 24502bd5..14870824 100644 --- a/pav-websocket/src/main/java/com/palnet/server/task/ctr/CtrCntrlTask.java +++ b/pav-websocket/src/main/java/com/palnet/server/task/ctr/CtrCntrlTask.java @@ -26,7 +26,7 @@ public class CtrCntrlTask implements Runnable{ public void run() { try { // logger.info(">>> run : {}", cc.getAllChannels()); - cc.getAllChannels().stream().forEach(c -> { // 접속되어 있는 모든 사용자에게 전달 처리 + cc.getWsChannels().stream().forEach(c -> { // 접속되어 있는 모든 사용자에게 전달 처리 c.writeAndFlush(new TextWebSocketFrame(JsonUtils.toJson(service.getList()))); }); }catch(Exception e) {