feat:ASW-80 Environment terminal ws代理接口开发
This commit is contained in:
@@ -56,7 +56,7 @@ public class EnvironmentNovncWebSocketHandler extends TextWebSocketHandler {
|
|||||||
this.envId = (String) session.getAttributes().get("envId");
|
this.envId = (String) session.getAttributes().get("envId");
|
||||||
this.sessionId = (String) session.getAttributes().get("sessionId");
|
this.sessionId = (String) session.getAttributes().get("sessionId");
|
||||||
this.userId = (String) session.getAttributes().get("userId");
|
this.userId = (String) session.getAttributes().get("userId");
|
||||||
Constants.ENV_WEBSOCKET_SESSION.put(sessionId, session);
|
Constants.ENV_NOVNC_WEBSOCKET_SESSION.put(sessionId, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -81,7 +81,7 @@ public class EnvironmentNovncWebSocketHandler extends TextWebSocketHandler {
|
|||||||
EnvironmentEntity deviceEntity = environmentService.queryInfo(envId);
|
EnvironmentEntity deviceEntity = environmentService.queryInfo(envId);
|
||||||
JSONObject paramJSONObject = deviceEntity.getParamJSONObject();
|
JSONObject paramJSONObject = deviceEntity.getParamJSONObject();
|
||||||
|
|
||||||
String urlStr = String.format("%s%s", paramJSONObject.getStr("url"), Constants.ENV_API_WEBSOCKET_PATH);
|
String urlStr = String.format("%s%s", paramJSONObject.getStr("url"), Constants.ENV_NOVNC_WEBSOCKET_PATH);
|
||||||
urlStr = urlStr.replace("http", "ws");
|
urlStr = urlStr.replace("http", "ws");
|
||||||
WebSocket webSocket = null;
|
WebSocket webSocket = null;
|
||||||
try {
|
try {
|
||||||
@@ -97,7 +97,7 @@ public class EnvironmentNovncWebSocketHandler extends TextWebSocketHandler {
|
|||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.close(CloseStatus.NORMAL.withReason("Environment WebSocket connectioned. after connection established open environment error!"));
|
session.close(CloseStatus.NORMAL.withReason("Environment WebSocket connectioned. after connection established open environment error!"));
|
||||||
IoUtil.close(session);
|
IoUtil.close(session);
|
||||||
Constants.ENV_WEBSOCKET_SESSION.remove(session);
|
Constants.ENV_NOVNC_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.info("[afterConnectionEstablished] [environment server: {}]", T.JSONUtil.toJsonStr(paramJSONObject));
|
log.info("[afterConnectionEstablished] [environment server: {}]", T.JSONUtil.toJsonStr(paramJSONObject));
|
||||||
@@ -152,6 +152,7 @@ public class EnvironmentNovncWebSocketHandler extends TextWebSocketHandler {
|
|||||||
if (envWebsocket != null) {
|
if (envWebsocket != null) {
|
||||||
envWebsocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
envWebsocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
||||||
}
|
}
|
||||||
|
Constants.ENV_NOVNC_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
super.afterConnectionClosed(session, status);
|
super.afterConnectionClosed(session, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package net.geedge.asw.common.config.websocket;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import net.geedge.asw.common.util.Constants;
|
||||||
|
import net.geedge.asw.common.util.T;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentEntity;
|
||||||
|
import net.geedge.asw.module.environment.entity.EnvironmentSessionEntity;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentService;
|
||||||
|
import net.geedge.asw.module.environment.service.IEnvironmentSessionService;
|
||||||
|
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.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.WebSocket;
|
||||||
|
import java.util.concurrent.CompletionStage;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class EnvironmentTerminalWebSocketHandler extends TextWebSocketHandler {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* env id
|
||||||
|
*/
|
||||||
|
private String envId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* session
|
||||||
|
*/
|
||||||
|
private String sessionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* user id
|
||||||
|
*/
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
|
||||||
|
private IEnvironmentService environmentService;
|
||||||
|
|
||||||
|
private IEnvironmentSessionService environmentSessionService;
|
||||||
|
|
||||||
|
public EnvironmentTerminalWebSocketHandler(IEnvironmentService environmentService, IEnvironmentSessionService environmentSessionService) {
|
||||||
|
this.environmentService = environmentService;
|
||||||
|
this.environmentSessionService = environmentSessionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFieldVal(WebSocketSession session) {
|
||||||
|
this.envId = (String) session.getAttributes().get("envId");
|
||||||
|
this.sessionId = (String) session.getAttributes().get("sessionId");
|
||||||
|
this.userId = (String) session.getAttributes().get("userId");
|
||||||
|
Constants.ENV_TERMINAL_WEBSOCKET_SESSION.put(sessionId, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
|
super.afterConnectionEstablished(session);
|
||||||
|
|
||||||
|
this.initFieldVal(session);
|
||||||
|
// token
|
||||||
|
if (T.StrUtil.isEmpty(userId)) {
|
||||||
|
log.warn("Websocket token authentication failed");
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Websocket token authentication failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// env session
|
||||||
|
EnvironmentSessionEntity environmentSession = environmentSessionService.getOne(new LambdaQueryWrapper<EnvironmentSessionEntity>().eq(EnvironmentSessionEntity::getId, sessionId).eq(EnvironmentSessionEntity::getStatus, 1));
|
||||||
|
if (environmentSession == null) {
|
||||||
|
log.warn("environment session does not exist. session id: {}", sessionId);
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Environment session does not exist"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("WebSocket connectioned. after connection established open environment terminal begin... environment id: {}", envId);
|
||||||
|
EnvironmentEntity deviceEntity = environmentService.queryInfo(envId);
|
||||||
|
JSONObject paramJSONObject = deviceEntity.getParamJSONObject();
|
||||||
|
|
||||||
|
String urlStr = String.format("%s%s", paramJSONObject.getStr("url"), Constants.ENV_TERMINAL_WEBSOCKET_PATH);
|
||||||
|
urlStr = urlStr.replace("http", "ws");
|
||||||
|
WebSocket webSocket = null;
|
||||||
|
try {
|
||||||
|
HttpClient client = HttpClient.newHttpClient();
|
||||||
|
webSocket = client.newWebSocketBuilder()
|
||||||
|
.buildAsync(URI.create(urlStr), new WebSocketListener(session))
|
||||||
|
.get();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "Environment terminal webSocket connectioned. after connection established open environment terminal error. session id: {}", sessionId);
|
||||||
|
if (ObjectUtil.isNotNull(webSocket)) {
|
||||||
|
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
||||||
|
}
|
||||||
|
if (ObjectUtil.isNotNull(session)) {
|
||||||
|
session.close(CloseStatus.NORMAL.withReason("Environment terminal webSocket connectioned. after connection established open environment terminal error!"));
|
||||||
|
IoUtil.close(session);
|
||||||
|
Constants.ENV_TERMINAL_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("[afterConnectionEstablished] [environment terminal url: {}]", urlStr);
|
||||||
|
session.getAttributes().put("terminalWebsocket", webSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// WebSocket 监听器实现
|
||||||
|
private static class WebSocketListener implements WebSocket.Listener {
|
||||||
|
private WebSocketSession session;
|
||||||
|
|
||||||
|
public WebSocketListener(WebSocketSession session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletionStage<?> onText(WebSocket webSocket, CharSequence message, boolean last) {
|
||||||
|
try {
|
||||||
|
// env -> asw
|
||||||
|
session.sendMessage(new TextMessage(message));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return WebSocket.Listener.super.onText(webSocket, message, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
|
||||||
|
log.info("Environment terminal webSocket connection closed, Status: " + statusCode + ", Reason: " + reason);
|
||||||
|
return WebSocket.Listener.super.onClose(webSocket, statusCode, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
|
||||||
|
WebSocket terminalWebsocket = (WebSocket) session.getAttributes().get("terminalWebsocket");
|
||||||
|
try {
|
||||||
|
if (terminalWebsocket != null) {
|
||||||
|
terminalWebsocket.sendText(message.getPayload(), true);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||||
|
log.info("[afterConnectionClosed] [Terminal webSocket connection closed] [uri: {}]", session.getUri());
|
||||||
|
WebSocket envWebsocket = (WebSocket) session.getAttributes().get("terminalWebsocket");
|
||||||
|
if (envWebsocket != null) {
|
||||||
|
envWebsocket.sendClose(WebSocket.NORMAL_CLOSURE, "Normal closure");
|
||||||
|
}
|
||||||
|
|
||||||
|
Constants.ENV_TERMINAL_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
super.afterConnectionClosed(session, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,25 +9,29 @@ import org.springframework.http.server.ServletServerHttpRequest;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.socket.WebSocketHandler;
|
import org.springframework.web.socket.WebSocketHandler;
|
||||||
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
|
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
|
||||||
import org.springframework.web.util.UriTemplate;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class EnvironmentNovncWebSocketInterceptor extends HttpSessionHandshakeInterceptor {
|
public class EnvironmentWebSocketInterceptor extends HttpSessionHandshakeInterceptor {
|
||||||
private static final Log log = Log.get();
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
private String regex = "^/api/v1/env/([^/]+)/session/([^/]+)/(novnc|terminal)$";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
|
public synchronized boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
|
||||||
if (request instanceof ServletServerHttpRequest) {
|
if (request instanceof ServletServerHttpRequest) {
|
||||||
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
|
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
|
||||||
String servletPath = servletRequest.getServletRequest().getServletPath();
|
String servletPath = servletRequest.getServletRequest().getServletPath();
|
||||||
UriTemplate template = new UriTemplate("/api/v1/env/{envId}/session/{sessionId}/novnc");
|
Pattern pattern = Pattern.compile(regex);
|
||||||
Map<String, String> variables = template.match(servletPath);
|
Matcher matcher = pattern.matcher(servletPath);
|
||||||
attributes.put("envId", variables.get("envId"));
|
if (matcher.find()) {
|
||||||
attributes.put("sessionId", variables.get("sessionId"));
|
attributes.put("envId", matcher.group(1));
|
||||||
|
attributes.put("sessionId", matcher.group(2));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
String token = servletRequest.getServletRequest().getParameter("token");
|
String token = servletRequest.getServletRequest().getParameter("token");
|
||||||
StpUtil.setTokenValue(token);
|
StpUtil.setTokenValue(token);
|
||||||
@@ -21,7 +21,11 @@ public class WebSocketConfig implements WebSocketConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||||
registry.addHandler(new EnvironmentNovncWebSocketHandler(deviceService, environmentSessionService), "/api/v1/env/{envId}/session/{sessionId}/novnc")
|
registry.addHandler(new EnvironmentNovncWebSocketHandler(deviceService, environmentSessionService), "/api/v1/env/{envId}/session/{sessionId}/novnc")
|
||||||
.addInterceptors(new EnvironmentNovncWebSocketInterceptor())
|
.addInterceptors(new EnvironmentWebSocketInterceptor())
|
||||||
|
.setAllowedOrigins("*");
|
||||||
|
|
||||||
|
registry.addHandler(new EnvironmentTerminalWebSocketHandler(deviceService, environmentSessionService), "/api/v1/env/{envId}/session/{sessionId}/terminal")
|
||||||
|
.addInterceptors(new EnvironmentWebSocketInterceptor())
|
||||||
.setAllowedOrigins("*");
|
.setAllowedOrigins("*");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,9 @@ public class Constants {
|
|||||||
/**
|
/**
|
||||||
* env api novnc websocket path
|
* env api novnc websocket path
|
||||||
*/
|
*/
|
||||||
public static final String ENV_API_WEBSOCKET_PATH = "/api/v1/env/novnc";
|
public static final String ENV_NOVNC_WEBSOCKET_PATH = "/api/v1/env/novnc";
|
||||||
|
|
||||||
|
public static final String ENV_TERMINAL_WEBSOCKET_PATH = "/api/v1/env/terminal";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* env api stop tcpdump path
|
* env api stop tcpdump path
|
||||||
@@ -89,7 +91,13 @@ public class Constants {
|
|||||||
/**
|
/**
|
||||||
* novnc websocket 连接信息对应的 env session id 用以进行主动断开服务器连接功能
|
* novnc websocket 连接信息对应的 env session id 用以进行主动断开服务器连接功能
|
||||||
*/
|
*/
|
||||||
public static final Map<String, WebSocketSession> ENV_WEBSOCKET_SESSION = T.MapUtil.newHashMap();
|
public static final Map<String, WebSocketSession> ENV_NOVNC_WEBSOCKET_SESSION = T.MapUtil.newHashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* terminal websocket 连接信息对应的 env session id 用以进行主动断开服务器连接功能
|
||||||
|
*/
|
||||||
|
public static final Map<String, WebSocketSession> ENV_TERMINAL_WEBSOCKET_SESSION = T.MapUtil.newHashMap();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -170,19 +170,24 @@ public class EnvironmentController {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public R removeSession(@PathVariable("envId") String envId, @PathVariable("sessionId") String sessionId, @RequestParam String workspaceId) {
|
public R removeSession(@PathVariable("envId") String envId, @PathVariable("sessionId") String sessionId, @RequestParam String workspaceId) {
|
||||||
EnvironmentSessionEntity session = environmentSessionService.getById(sessionId);
|
EnvironmentSessionEntity session = environmentSessionService.getById(sessionId);
|
||||||
WebSocketSession webSocketSession = Constants.ENV_WEBSOCKET_SESSION.get(sessionId);
|
WebSocketSession novncSession = Constants.ENV_NOVNC_WEBSOCKET_SESSION.get(sessionId);
|
||||||
// 根据 session 找到 webSocketSession,更新状态,设置结束时间
|
WebSocketSession terminalSession = Constants.ENV_TERMINAL_WEBSOCKET_SESSION.get(sessionId);
|
||||||
|
// 根据 session 找到 novncSession&terminalSession ,更新状态,设置结束时间
|
||||||
session.setEndTimestamp(System.currentTimeMillis());
|
session.setEndTimestamp(System.currentTimeMillis());
|
||||||
session.setStatus(2);
|
session.setStatus(2);
|
||||||
environmentSessionService.updateById(session);
|
environmentSessionService.updateById(session);
|
||||||
if (T.ObjectUtil.isNotEmpty(webSocketSession)) {
|
|
||||||
try {
|
try {
|
||||||
Constants.ENV_WEBSOCKET_SESSION.remove(sessionId);
|
if (T.ObjectUtil.isNotEmpty(novncSession)) {
|
||||||
webSocketSession.close(CloseStatus.NORMAL.withReason("Administrator disconnected."));
|
Constants.ENV_NOVNC_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
novncSession.close(CloseStatus.NORMAL.withReason("Administrator disconnected."));
|
||||||
|
}
|
||||||
|
if (T.ObjectUtil.isNotEmpty(terminalSession)) {
|
||||||
|
Constants.ENV_TERMINAL_WEBSOCKET_SESSION.remove(sessionId);
|
||||||
|
terminalSession.close(CloseStatus.NORMAL.withReason("Administrator disconnected."));
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(e, "RemoveSession send exit prompt error sessionId: {}", sessionId);
|
log.error(e, "RemoveSession send exit prompt error sessionId: {}", sessionId);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user