From e4551dc545468967ded6c1c10a706e57e3dedbae Mon Sep 17 00:00:00 2001 From: gsd Date: Sat, 23 Dec 2023 20:01:44 +0300 Subject: [PATCH] websocket support v1 --- pom.xml | 5 ++ .../app/controllers/debug/WebSocketPage.java | 79 +++++++++++++++++++ .../server/ServerUpdaterController.java | 7 +- .../java/app/websocket/WebSocketConfig.java | 22 ++++++ .../java/app/websocket/WebSocketHandler.java | 64 +++++++++++++++ 5 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/main/java/app/controllers/debug/WebSocketPage.java create mode 100644 src/main/java/app/websocket/WebSocketConfig.java create mode 100644 src/main/java/app/websocket/WebSocketHandler.java diff --git a/pom.xml b/pom.xml index d0aef31..547d619 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,11 @@ spring-boot-starter 3.0.2 + + org.springframework.boot + spring-boot-starter-websocket + 3.0.2 + com.fasterxml.jackson.core jackson-core diff --git a/src/main/java/app/controllers/debug/WebSocketPage.java b/src/main/java/app/controllers/debug/WebSocketPage.java new file mode 100644 index 0000000..ee76c10 --- /dev/null +++ b/src/main/java/app/controllers/debug/WebSocketPage.java @@ -0,0 +1,79 @@ +package app.controllers.debug; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/debug/ws") +public class WebSocketPage { + + @GetMapping + public String getPage(){ + return "\n" + + "\n" + + "\n" + + " \n" + + " Home page\n" + + " \n" + + "\n" + + "\n" + + "\n" + + "
\n" + + "\n" + + "

Debug websocket page

\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + " \n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "\n" + + "\n" + + "\n" + + "\n" + + ""; + } +} diff --git a/src/main/java/app/controllers/server/ServerUpdaterController.java b/src/main/java/app/controllers/server/ServerUpdaterController.java index de16a30..06b0f0c 100644 --- a/src/main/java/app/controllers/server/ServerUpdaterController.java +++ b/src/main/java/app/controllers/server/ServerUpdaterController.java @@ -4,6 +4,7 @@ import app.annotations.enums.AuthMethod; import app.annotations.interfaces.CheckWebAccess; import app.entities.Stats; import app.entities.server.request.ServerRequestBody; +import app.websocket.WebSocketHandler; import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -14,10 +15,12 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("api/server") public class ServerUpdaterController { private Stats stats; + private WebSocketHandler webSocketHandler; @Autowired - ServerUpdaterController(Stats stats) { + public ServerUpdaterController(Stats stats, WebSocketHandler webSocketHandler) { this.stats = stats; + this.webSocketHandler = webSocketHandler; } @PostMapping(value = "/{srv}") @@ -25,6 +28,7 @@ public class ServerUpdaterController { public ResponseEntity updateServer(HttpServletRequest request, @PathVariable String srv, @RequestBody ServerRequestBody serverRequestBody) { if (!stats.getServers().containsKey(srv)) return new ResponseEntity<>(HttpStatus.NOT_FOUND); stats.getServers().get(srv).RefreshServerFromRequest(serverRequestBody); + webSocketHandler.pushServer(srv, stats.getServers().get(srv)); return new ResponseEntity(HttpStatus.OK); } @@ -33,6 +37,7 @@ public class ServerUpdaterController { public ResponseEntity downServer(HttpServletRequest request, @PathVariable String srv) { if (!stats.getServers().containsKey(srv)) return new ResponseEntity<>(HttpStatus.NOT_FOUND); stats.getServers().get(srv).RefreshServerFromRequest(null); + webSocketHandler.pushServer(srv, stats.getServers().get(srv)); return new ResponseEntity(HttpStatus.OK); } } diff --git a/src/main/java/app/websocket/WebSocketConfig.java b/src/main/java/app/websocket/WebSocketConfig.java new file mode 100644 index 0000000..dd5ce5c --- /dev/null +++ b/src/main/java/app/websocket/WebSocketConfig.java @@ -0,0 +1,22 @@ +package app.websocket; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + +@Configuration +@EnableWebSocket +public class WebSocketConfig implements WebSocketConfigurer { + + private WebSocketHandler webSocketHandler; + + public WebSocketConfig(WebSocketHandler webSocketHandler) { + this.webSocketHandler = webSocketHandler; + } + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(webSocketHandler, "/ws"); + } +} diff --git a/src/main/java/app/websocket/WebSocketHandler.java b/src/main/java/app/websocket/WebSocketHandler.java new file mode 100644 index 0000000..7259c1b --- /dev/null +++ b/src/main/java/app/websocket/WebSocketHandler.java @@ -0,0 +1,64 @@ +package app.websocket; + +import app.entities.server.Server; +import app.updates.BaseUpdater; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +@Component +@Scope(value = "singleton") +public class WebSocketHandler extends TextWebSocketHandler { + private final Logger logger = LoggerFactory.getLogger(BaseUpdater.class); + private final Map activeSessions = new HashMap<>(); + private ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + logger.info("Session {} open", session.getId()); + activeSessions.put(session.getId(), session); + super.afterConnectionEstablished(session); + } + + @Override + public void handleTextMessage(WebSocketSession session, TextMessage message) { + //nothing + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { + logger.info("Session {} close", session.getId()); + activeSessions.remove(session.getId()); + super.afterConnectionClosed(session, status); + } + + private void push2All(String msg) throws IOException { + for (Map.Entry otherSession : activeSessions.entrySet()) { + otherSession.getValue().sendMessage(new TextMessage(msg)); + } + } + + public void pushServer(String srv, Server server) { + try { + push2All( + objectMapper.writeValueAsString( + new HashMap() {{ + put("server", new HashMap(){{ + put(srv, server);}}); + }})); + } catch (IOException err) { + logger.error("Cannot send message"); + } + } +}