Browse Source

websocket support v1

master
gsd 1 year ago
parent
commit
e4551dc545
  1. 5
      pom.xml
  2. 79
      src/main/java/app/controllers/debug/WebSocketPage.java
  3. 7
      src/main/java/app/controllers/server/ServerUpdaterController.java
  4. 22
      src/main/java/app/websocket/WebSocketConfig.java
  5. 64
      src/main/java/app/websocket/WebSocketHandler.java

5
pom.xml

@ -26,6 +26,11 @@
<artifactId>spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>

79
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 "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Home page</title>\n" +
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.1/semantic.min.css\"\n" +
" rel=\"stylesheet\">\n" +
"</head>\n" +
"<body>\n" +
"\n" +
"<div class=\"ui container\">\n" +
"\n" +
" <h1>Debug websocket page</h1>\n" +
"\n" +
" <div class=\"two column grid\">\n" +
" <div class=\"row\">\n" +
" <div class=\"column\">\n" +
" <label for=\"myMessage\">Message</label>\n" +
" </div>\n" +
"\n" +
" <div class=\"column\">\n" +
" <div class=\"ui input\">\n" +
" <input type=\"text\" id=\"myMessage\">\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
"\n" +
" <div class=\"row\">\n" +
" <div class=\"column\">\n" +
" <label for=\"output\">Response from Server</label>\n" +
" </div>\n" +
"\n" +
" <div class=\"column\">\n" +
" <textarea rows=\"8\" cols=\"50\" id=\"output\" readonly=\"readonly\"></textarea>\n" +
" </div>\n" +
" </div>\n" +
"\n" +
" <div class=\"row\">\n" +
" <button class=\"ui button\" onclick=\"send()\">Send</button>\n" +
" </div>\n" +
"\n" +
" </div>\n" +
"</div>\n" +
"\n" +
"\n" +
"<script>\n" +
" const socketConn = new WebSocket('ws://localhost:8080/ws');\n" +
"\n" +
" function send() {\n" +
" const clientMsg = document.getElementById('myMessage');\n" +
"\n" +
" if (clientMsg.value) {\n" +
" socketConn.send(clientMsg.value);\n" +
" }\n" +
" }\n" +
"\n" +
" socketConn.onmessage = (e) => {\n" +
"\n" +
" const output = document.getElementById('output');\n" +
"\n" +
" output.value += `${e.data}\\n`;\n" +
" }\n" +
"</script>\n" +
"</body>\n" +
"</html>";
}
}

7
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);
}
}

22
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");
}
}

64
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<String, WebSocketSession> 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<String, WebSocketSession> otherSession : activeSessions.entrySet()) {
otherSession.getValue().sendMessage(new TextMessage(msg));
}
}
public void pushServer(String srv, Server server) {
try {
push2All(
objectMapper.writeValueAsString(
new HashMap<String, HashMap>() {{
put("server", new HashMap<String, Server>(){{
put(srv, server);}});
}}));
} catch (IOException err) {
logger.error("Cannot send message");
}
}
}
Loading…
Cancel
Save