feat: 关闭终端连接.

This commit is contained in:
lijiahangmax
2024-01-04 00:38:40 +08:00
parent e60570069c
commit 71299801c5
11 changed files with 257 additions and 34 deletions

View File

@@ -1,12 +1,9 @@
package com.orion.ops.module.asset.handler.host.terminal.enums; package com.orion.ops.module.asset.handler.host.terminal.enums;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.orion.ops.module.asset.handler.host.terminal.handler.ITerminalHandler; import com.orion.ops.module.asset.handler.host.terminal.handler.*;
import com.orion.ops.module.asset.handler.host.terminal.handler.TerminalCheckHandler;
import com.orion.ops.module.asset.handler.host.terminal.handler.TerminalConnectHandler;
import com.orion.ops.module.asset.handler.host.terminal.model.TerminalBasePayload; import com.orion.ops.module.asset.handler.host.terminal.model.TerminalBasePayload;
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalCheckRequest; import com.orion.ops.module.asset.handler.host.terminal.model.request.*;
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalConnectRequest;
import com.orion.spring.SpringHolder; import com.orion.spring.SpringHolder;
import lombok.Getter; import lombok.Getter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -42,41 +39,41 @@ public enum InputTypeEnum {
* 关闭连接 * 关闭连接
*/ */
CLOSE("cl", CLOSE("cl",
TerminalConnectHandler.class, TerminalCloseHandler.class,
new String[]{"type", "session"}, new String[]{"type", "session"},
TerminalConnectRequest.class), TerminalBasePayload.class),
/** /**
* ping * ping
*/ */
PING("p", PING("p",
TerminalConnectHandler.class, TerminalPingHandler.class,
new String[]{"type", "session"}, new String[]{"type"},
TerminalConnectRequest.class), TerminalBasePayload.class),
/** /**
* 修改大小 * 修改大小
*/ */
RESIZE("rs", RESIZE("rs",
TerminalConnectHandler.class, TerminalResizeHandler.class,
new String[]{"type", "session", "cols", "rows"}, new String[]{"type", "session", "cols", "rows"},
TerminalConnectRequest.class), TerminalResizeRequest.class),
/** /**
* 执行 * 执行
*/ */
EXEC("e", EXEC("e",
TerminalConnectHandler.class, TerminalExecHandler.class,
new String[]{"type", "session", "command"}, new String[]{"type", "session", "command"},
TerminalConnectRequest.class), TerminalExecRequest.class),
/** /**
* 输入 * 输入
*/ */
INPUT("i", INPUT("i",
TerminalConnectHandler.class, TerminalInputHandler.class,
new String[]{"type", "session", "command"}, new String[]{"type", "session", "command"},
TerminalConnectRequest.class), TerminalInputRequest.class),
; ;
@@ -109,7 +106,7 @@ public enum InputTypeEnum {
return null; return null;
} }
for (InputTypeEnum value : values()) { for (InputTypeEnum value : values()) {
if (payload.startsWith(value.type + SEPARATOR)) { if (payload.startsWith(value.type + SEPARATOR) || value.type.equals(payload)) {
return value; return value;
} }
} }

View File

@@ -28,22 +28,15 @@ public enum OutputTypeEnum {
/** /**
* pong * pong
*/ */
PONG("p", "${type}|${session}"), PONG("p", "${type}"),
/** /**
* 输出 * 输出
*/ */
OUTPUT("o", "${type}|${session}|${body}"), OUTPUT("o", "${type}|${session}|${body}"),
/**
* 发生错误
*/
ERROR("e", "${type}|${session}"),
; ;
private static final char SEPARATOR = '|';
private final String type; private final String type;
private final String template; private final String template;

View File

@@ -0,0 +1,31 @@
package com.orion.ops.module.asset.handler.host.terminal.handler;
import com.orion.ops.module.asset.handler.host.terminal.manager.TerminalManager;
import com.orion.ops.module.asset.handler.host.terminal.model.TerminalBasePayload;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import javax.annotation.Resource;
/**
* 关闭处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 15:32
*/
@Slf4j
@Component
public class TerminalCloseHandler extends AbstractTerminalHandler<TerminalBasePayload> {
@Resource
private TerminalManager terminalManager;
@Override
public void handle(WebSocketSession session, TerminalBasePayload payload) {
// 关闭会话
terminalManager.closeSession(session.getId(), payload.getSession());
}
}

View File

@@ -0,0 +1,36 @@
package com.orion.ops.module.asset.handler.host.terminal.handler;
import com.orion.ops.module.asset.handler.host.terminal.manager.TerminalManager;
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalExecRequest;
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import javax.annotation.Resource;
/**
* 执行命令处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 15:32
*/
@Slf4j
@Component
public class TerminalExecHandler extends AbstractTerminalHandler<TerminalExecRequest> {
@Resource
private TerminalManager terminalManager;
@Override
public void handle(WebSocketSession session, TerminalExecRequest payload) {
// 获取会话
ITerminalSession terminalSession = terminalManager.getSession(session.getId(), payload.getSession());
if (terminalSession != null) {
// 执行命令
terminalSession.write(payload.getCommand());
}
}
}

View File

@@ -0,0 +1,36 @@
package com.orion.ops.module.asset.handler.host.terminal.handler;
import com.orion.ops.module.asset.handler.host.terminal.manager.TerminalManager;
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalInputRequest;
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import javax.annotation.Resource;
/**
* 处理输入处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 15:32
*/
@Slf4j
@Component
public class TerminalInputHandler extends AbstractTerminalHandler<TerminalInputRequest> {
@Resource
private TerminalManager terminalManager;
@Override
public void handle(WebSocketSession session, TerminalInputRequest payload) {
// 获取会话
ITerminalSession terminalSession = terminalManager.getSession(session.getId(), payload.getSession());
if (terminalSession != null) {
// 处理输入
terminalSession.write(payload.getCommand());
}
}
}

View File

@@ -0,0 +1,26 @@
package com.orion.ops.module.asset.handler.host.terminal.handler;
import com.orion.ops.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import com.orion.ops.module.asset.handler.host.terminal.model.TerminalBasePayload;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
/**
* ping 处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 15:32
*/
@Slf4j
@Component
public class TerminalPingHandler extends AbstractTerminalHandler<TerminalBasePayload> {
@Override
public void handle(WebSocketSession session, TerminalBasePayload payload) {
// 发送 pong
this.send(session, OutputTypeEnum.PONG.getType());
}
}

View File

@@ -0,0 +1,36 @@
package com.orion.ops.module.asset.handler.host.terminal.handler;
import com.orion.ops.module.asset.handler.host.terminal.manager.TerminalManager;
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalResizeRequest;
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import javax.annotation.Resource;
/**
* 修改大小处理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 15:32
*/
@Slf4j
@Component
public class TerminalResizeHandler extends AbstractTerminalHandler<TerminalResizeRequest> {
@Resource
private TerminalManager terminalManager;
@Override
public void handle(WebSocketSession session, TerminalResizeRequest payload) {
// 获取会话
ITerminalSession terminalSession = terminalManager.getSession(session.getId(), payload.getSession());
if (terminalSession != null) {
// 修改大小
terminalSession.resize(payload.getCols(), payload.getRows());
}
}
}

View File

@@ -51,9 +51,11 @@ public class TerminalManager {
* @param token token * @param token token
*/ */
public void closeSession(String id, String token) { public void closeSession(String id, String token) {
ITerminalSession session = sessions.get(id, token); // 获取并移除
Streams.close(session); ITerminalSession session = sessions.removeElement(id, token);
sessions.removeElement(id, token); if (session != null) {
Streams.close(session);
}
} }
/** /**
@@ -62,12 +64,11 @@ public class TerminalManager {
* @param id id * @param id id
*/ */
public void closeAll(String id) { public void closeAll(String id) {
ConcurrentHashMap<String, ITerminalSession> session = sessions.get(id); // 获取并移除
ConcurrentHashMap<String, ITerminalSession> session = sessions.remove(id);
if (Maps.isEmpty(session)) { if (Maps.isEmpty(session)) {
return; session.values().forEach(Streams::close);
} }
session.values().forEach(Streams::close);
sessions.remove(id);
} }
} }

View File

@@ -0,0 +1,31 @@
package com.orion.ops.module.asset.handler.host.terminal.model.request;
import com.orion.ops.module.asset.handler.host.terminal.model.TerminalBasePayload;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* 执行命令请求 实体对象
* <p>
* e|eff00a1|command
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 16:20
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Schema(name = "TerminalExecRequest", description = "执行命令请求 实体对象")
public class TerminalExecRequest extends TerminalBasePayload {
@Schema(description = "command")
private String command;
}

View File

@@ -0,0 +1,31 @@
package com.orion.ops.module.asset.handler.host.terminal.model.request;
import com.orion.ops.module.asset.handler.host.terminal.model.TerminalBasePayload;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* 输入请求 实体对象
* <p>
* i|eff00a1|command
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/29 16:20
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Schema(name = "TerminalInputRequest", description = "输入请求 实体对象")
public class TerminalInputRequest extends TerminalBasePayload {
@Schema(description = "command")
private String command;
}

View File

@@ -7,9 +7,12 @@ import com.orion.net.host.ssh.shell.ShellExecutor;
import com.orion.ops.framework.common.constant.Const; import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.framework.websocket.core.utils.WebSockets; import com.orion.ops.framework.websocket.core.utils.WebSockets;
import com.orion.ops.module.asset.define.AssetThreadPools; import com.orion.ops.module.asset.define.AssetThreadPools;
import com.orion.ops.module.asset.enums.HostConnectStatusEnum;
import com.orion.ops.module.asset.handler.host.terminal.enums.OutputTypeEnum; import com.orion.ops.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import com.orion.ops.module.asset.handler.host.terminal.model.TerminalConfig; import com.orion.ops.module.asset.handler.host.terminal.model.TerminalConfig;
import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalOutputResponse; import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalOutputResponse;
import com.orion.ops.module.asset.service.HostConnectLogService;
import com.orion.spring.SpringHolder;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
@@ -96,12 +99,15 @@ public class TerminalSession implements ITerminalSession {
return; return;
} }
this.close = true; this.close = true;
// 关闭流
try { try {
Streams.close(executor); Streams.close(executor);
Streams.close(sessionStore); Streams.close(sessionStore);
} catch (Exception e) { } catch (Exception e) {
log.error("terminal 断开连接 失败 token: {}", token, e); log.error("terminal 断开连接 失败 token: {}", token, e);
} }
// 修改状态
SpringHolder.getBean(HostConnectLogService.class).updateStatusByToken(token, HostConnectStatusEnum.COMPLETE);
} }
/** /**
@@ -129,9 +135,8 @@ public class TerminalSession implements ITerminalSession {
} }
// eof // eof
if (close) { if (close) {
return; log.info("terminal eof回调 {}", token);
} }
log.info("terminal eof回调 {}", token);
} }
} }