feat: ASW-52 device novnc websocket 代理接口开发
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
package net.geedge.asw.common.config.websocket;
|
||||
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.log.Log;
|
||||
import net.geedge.asw.common.util.Constants;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import net.geedge.asw.module.device.entity.DeviceEntity;
|
||||
import net.geedge.asw.module.device.service.IDeviceService;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.*;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.WebSocket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
@Component
|
||||
public class DeviceWebSocketHandler extends TextWebSocketHandler {
|
||||
private static final Log log = Log.get();
|
||||
|
||||
/**
|
||||
* device id
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* device token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
|
||||
private IDeviceService deviceService;
|
||||
|
||||
public DeviceWebSocketHandler(IDeviceService deviceService) {
|
||||
this.deviceService = deviceService;
|
||||
}
|
||||
|
||||
private void initFieldVal(WebSocketSession session) {
|
||||
this.id = (String) session.getAttributes().get("id");
|
||||
this.token = (String) session.getAttributes().get("token");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
super.afterConnectionEstablished(session);
|
||||
|
||||
this.initFieldVal(session);
|
||||
log.info("WebSocket connectioned. after connection established open device begin... device id: {}", id);
|
||||
|
||||
|
||||
DeviceEntity deviceEntity = deviceService.queryInfo(id);
|
||||
JSONObject paramJSONObject = deviceEntity.getParamJSONObject();
|
||||
|
||||
if (T.StrUtil.equals(token, paramJSONObject.getStr("token"))) {
|
||||
log.warn("WebSocket connectioned error. device token exception. device id: {}, token: {}", id, token);
|
||||
session.sendMessage(new TextMessage("Token error, Please config device token"));
|
||||
session.close();
|
||||
return;
|
||||
}
|
||||
|
||||
String urlStr = String.format("ws://%s:%s%s", paramJSONObject.getStr("host"), paramJSONObject.getStr("port"), Constants.DEVICE_API_WEBSOCKET_PATH);
|
||||
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
WebSocket webSocket = client.newWebSocketBuilder()
|
||||
.buildAsync(URI.create(urlStr), new WebSocketListener(session))
|
||||
.get();
|
||||
|
||||
log.info("[afterConnectionEstablished] [device server: {}]", T.JSONUtil.toJsonStr(paramJSONObject));
|
||||
session.getAttributes().put("deviceWebsocket", webSocket);
|
||||
|
||||
}
|
||||
|
||||
// WebSocket 监听器实现
|
||||
private static class WebSocketListener implements WebSocket.Listener {
|
||||
private WebSocketSession session;
|
||||
|
||||
public WebSocketListener(WebSocketSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onBinary(WebSocket webSocket, ByteBuffer data, boolean last) {
|
||||
|
||||
try {
|
||||
// device -> asw
|
||||
session.sendMessage(new BinaryMessage(data, true));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return WebSocket.Listener.super.onBinary(webSocket, data, last);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
|
||||
log.info("Device webSocket connection closed, Status: " + statusCode + ", Reason: " + reason);
|
||||
return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
|
||||
try {
|
||||
// asw -> device api
|
||||
WebSocket vncSocket = (WebSocket) session.getAttributes().get("deviceWebsocket");
|
||||
if (vncSocket != null) {
|
||||
vncSocket.sendBinary(message.getPayload(), true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e, "[handleBinaryMessage] [error]");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||
log.info("[afterConnectionClosed] [WebSocket connection closed] [websocket uri: {}]", session.getUri());
|
||||
WebSocket deviceWebsocket = (WebSocket) session.getAttributes().get("deviceWebsocket");
|
||||
if (deviceWebsocket != null) {
|
||||
deviceWebsocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
||||
}
|
||||
super.afterConnectionClosed(session, status);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.geedge.asw.common.config.websocket;
|
||||
|
||||
import net.geedge.asw.module.device.service.IDeviceService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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 {
|
||||
|
||||
@Autowired
|
||||
private IDeviceService deviceService;
|
||||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
registry.addHandler(new DeviceWebSocketHandler(deviceService), "/api/v1/device/{id}/novnc")
|
||||
.addInterceptors(new WebSocketInterceptor())
|
||||
.setAllowedOrigins("*");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package net.geedge.asw.common.config.websocket;
|
||||
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor {
|
||||
|
||||
@Override
|
||||
public synchronized boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
|
||||
if (request instanceof ServletServerHttpRequest) {
|
||||
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
|
||||
String servletPath = servletRequest.getServletRequest().getServletPath();
|
||||
UriTemplate template = new UriTemplate("/api/v1/device/{id}/novnc");
|
||||
Map<String, String> variables = template.match(servletPath);
|
||||
attributes.put("id", variables.get("id"));
|
||||
attributes.put("token", servletRequest.getServletRequest().getParameter("token"));
|
||||
}
|
||||
return super.beforeHandshake(request, response, wsHandler, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
|
||||
super.afterHandshake(request, response, wsHandler, exception);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -69,4 +69,8 @@ public class Constants {
|
||||
.put("Access-Control-Max-Age", "18000").put("Access-Control-Allow-Origin", "*").build();
|
||||
|
||||
|
||||
/**
|
||||
* device api websocket path
|
||||
*/
|
||||
public static final String DEVICE_API_WEBSOCKET_PATH = "/api/v1/device/websocket";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user