🚧 连接sftp.
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"local": {
|
"local": {
|
||||||
"baseUrl": "http://127.0.0.1:9200/orion-api",
|
"baseUrl": "http://127.0.0.1:9200/orion-api",
|
||||||
"token": "Bearer YQJ3IpwJJv5HujIWY6ZTNDgUxXRY6aDt",
|
"token": "Bearer YQJ3IpwJJv5HujIWY6ZTNDgUxXRY6aDt"
|
||||||
"timestamp": 1689577685914
|
|
||||||
},
|
},
|
||||||
"gateway": {
|
"gateway": {
|
||||||
"baseUrl": "http://127.0.0.1:9200/orion-api",
|
"baseUrl": "http://127.0.0.1:9200/orion-api",
|
||||||
|
|||||||
@@ -35,4 +35,6 @@ public interface ExtraFieldConst extends FieldConst {
|
|||||||
|
|
||||||
String SESSION_ID = "sessionId";
|
String SESSION_ID = "sessionId";
|
||||||
|
|
||||||
|
String CONNECT_TYPE = "connectType";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import lombok.NoArgsConstructor;
|
|||||||
@Schema(name = "HostTerminalConnectDTO", description = "主机终端连接参数")
|
@Schema(name = "HostTerminalConnectDTO", description = "主机终端连接参数")
|
||||||
public class HostTerminalConnectDTO {
|
public class HostTerminalConnectDTO {
|
||||||
|
|
||||||
|
@Schema(description = "连接类型")
|
||||||
|
private String connectType;
|
||||||
|
|
||||||
@Schema(description = "hostId")
|
@Schema(description = "hostId")
|
||||||
private Long hostId;
|
private Long hostId;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ public enum HostConnectTypeEnum {
|
|||||||
*/
|
*/
|
||||||
SSH,
|
SSH,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sftp
|
||||||
|
*/
|
||||||
|
SFTP,
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
public static HostConnectTypeEnum of(String type) {
|
public static HostConnectTypeEnum of(String type) {
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ 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.*;
|
import com.orion.ops.module.asset.handler.host.terminal.handler.*;
|
||||||
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.*;
|
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalCheckRequest;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalConnectRequest;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalInputRequest;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalResizeRequest;
|
||||||
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;
|
||||||
@@ -24,7 +27,7 @@ public enum InputTypeEnum {
|
|||||||
*/
|
*/
|
||||||
CHECK("ck",
|
CHECK("ck",
|
||||||
TerminalCheckHandler.class,
|
TerminalCheckHandler.class,
|
||||||
new String[]{"type", "sessionId", "hostId"},
|
new String[]{"type", "sessionId", "hostId", "connectType"},
|
||||||
TerminalCheckRequest.class),
|
TerminalCheckRequest.class),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,14 +62,6 @@ public enum InputTypeEnum {
|
|||||||
new String[]{"type", "sessionId", "cols", "rows"},
|
new String[]{"type", "sessionId", "cols", "rows"},
|
||||||
TerminalResizeRequest.class),
|
TerminalResizeRequest.class),
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行
|
|
||||||
*/
|
|
||||||
EXEC("e",
|
|
||||||
TerminalExecHandler.class,
|
|
||||||
new String[]{"type", "sessionId", "command"},
|
|
||||||
TerminalExecRequest.class),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入
|
* 输入
|
||||||
*/
|
*/
|
||||||
@@ -76,10 +71,10 @@ public enum InputTypeEnum {
|
|||||||
TerminalInputRequest.class),
|
TerminalInputRequest.class),
|
||||||
|
|
||||||
// LS
|
// LS
|
||||||
// DEL
|
// MK
|
||||||
|
// RM
|
||||||
// MV
|
// MV
|
||||||
// TC
|
// TC
|
||||||
// MK
|
|
||||||
// CD
|
// CD
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
|
|||||||
Long hostId = payload.getHostId();
|
Long hostId = payload.getHostId();
|
||||||
Long userId = this.getAttr(channel, ExtraFieldConst.USER_ID);
|
Long userId = this.getAttr(channel, ExtraFieldConst.USER_ID);
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
HostConnectTypeEnum connectType = HostConnectTypeEnum.of(payload.getConnectType());
|
||||||
String sessionId = payload.getSessionId();
|
String sessionId = payload.getSessionId();
|
||||||
log.info("TerminalCheckHandler-handle start userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId);
|
log.info("TerminalCheckHandler-handle start userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId);
|
||||||
// 检查 session 是否存在
|
// 检查 session 是否存在
|
||||||
@@ -77,7 +78,7 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
|
|||||||
Exception ex = null;
|
Exception ex = null;
|
||||||
try {
|
try {
|
||||||
// 获取连接信息
|
// 获取连接信息
|
||||||
HostTerminalConnectDTO connect = hostTerminalService.getTerminalConnectInfo(userId, host);
|
HostTerminalConnectDTO connect = hostTerminalService.getTerminalConnectInfo(userId, host, connectType);
|
||||||
// 设置到缓存中
|
// 设置到缓存中
|
||||||
channel.getAttributes().put(sessionId, connect);
|
channel.getAttributes().put(sessionId, connect);
|
||||||
log.info("TerminalCheckHandler-handle success userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId);
|
log.info("TerminalCheckHandler-handle success userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId);
|
||||||
@@ -89,7 +90,7 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
|
|||||||
log.error("TerminalCheckHandler-handle exception userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId, e);
|
log.error("TerminalCheckHandler-handle exception userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId, e);
|
||||||
}
|
}
|
||||||
// 记录主机日志
|
// 记录主机日志
|
||||||
this.saveTerminalLog(channel, userId, host, startTime, ex, sessionId);
|
this.saveHostLog(channel, userId, host, startTime, ex, sessionId, connectType);
|
||||||
// 响应检查结果
|
// 响应检查结果
|
||||||
this.send(channel,
|
this.send(channel,
|
||||||
OutputTypeEnum.CHECK,
|
OutputTypeEnum.CHECK,
|
||||||
@@ -108,8 +109,8 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
|
|||||||
* @return 是否存在
|
* @return 是否存在
|
||||||
*/
|
*/
|
||||||
private boolean checkSession(WebSocketSession channel, TerminalCheckRequest payload) {
|
private boolean checkSession(WebSocketSession channel, TerminalCheckRequest payload) {
|
||||||
ITerminalSession terminalSession = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
ITerminalSession session = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
||||||
if (terminalSession != null) {
|
if (session != null) {
|
||||||
this.sendCheckFailedMessage(channel, payload, ErrorMessage.SESSION_PRESENT);
|
this.sendCheckFailedMessage(channel, payload, ErrorMessage.SESSION_PRESENT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -154,19 +155,21 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
|
|||||||
/**
|
/**
|
||||||
* 记录主机日志
|
* 记录主机日志
|
||||||
*
|
*
|
||||||
* @param channel channel
|
* @param channel channel
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @param host host
|
* @param host host
|
||||||
* @param startTime startTime
|
* @param startTime startTime
|
||||||
* @param ex ex
|
* @param ex ex
|
||||||
* @param sessionId sessionId
|
* @param sessionId sessionId
|
||||||
|
* @param connectType connectType
|
||||||
*/
|
*/
|
||||||
private void saveTerminalLog(WebSocketSession channel,
|
private void saveHostLog(WebSocketSession channel,
|
||||||
Long userId,
|
Long userId,
|
||||||
HostDO host,
|
HostDO host,
|
||||||
long startTime,
|
long startTime,
|
||||||
Exception ex,
|
Exception ex,
|
||||||
String sessionId) {
|
String sessionId,
|
||||||
|
HostConnectTypeEnum connectType) {
|
||||||
Long hostId = host.getId();
|
Long hostId = host.getId();
|
||||||
String hostName = host.getName();
|
String hostName = host.getName();
|
||||||
String username = this.getAttr(channel, ExtraFieldConst.USERNAME);
|
String username = this.getAttr(channel, ExtraFieldConst.USERNAME);
|
||||||
@@ -174,6 +177,7 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
|
|||||||
Map<String, Object> extra = Maps.newMap();
|
Map<String, Object> extra = Maps.newMap();
|
||||||
extra.put(OperatorLogs.ID, hostId);
|
extra.put(OperatorLogs.ID, hostId);
|
||||||
extra.put(OperatorLogs.NAME, hostName);
|
extra.put(OperatorLogs.NAME, hostName);
|
||||||
|
extra.put(OperatorLogs.CONNECT_TYPE, connectType.name());
|
||||||
extra.put(OperatorLogs.CHANNEL_ID, channel.getId());
|
extra.put(OperatorLogs.CHANNEL_ID, channel.getId());
|
||||||
extra.put(OperatorLogs.SESSION_ID, sessionId);
|
extra.put(OperatorLogs.SESSION_ID, sessionId);
|
||||||
// 日志参数
|
// 日志参数
|
||||||
@@ -205,7 +209,7 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
|
|||||||
.token(sessionId)
|
.token(sessionId)
|
||||||
.extra(extra)
|
.extra(extra)
|
||||||
.build();
|
.build();
|
||||||
hostConnectLogService.create(HostConnectTypeEnum.SSH, connectLog);
|
hostConnectLogService.create(connectType, connectLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,16 @@ import com.orion.ops.framework.common.constant.ErrorMessage;
|
|||||||
import com.orion.ops.framework.common.enums.BooleanBit;
|
import com.orion.ops.framework.common.enums.BooleanBit;
|
||||||
import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO;
|
import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO;
|
||||||
import com.orion.ops.module.asset.enums.HostConnectStatusEnum;
|
import com.orion.ops.module.asset.enums.HostConnectStatusEnum;
|
||||||
|
import com.orion.ops.module.asset.enums.HostConnectTypeEnum;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.constant.TerminalMessage;
|
import com.orion.ops.module.asset.handler.host.terminal.constant.TerminalMessage;
|
||||||
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.manager.TerminalManager;
|
import com.orion.ops.module.asset.handler.host.terminal.manager.TerminalManager;
|
||||||
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.request.TerminalConnectRequest;
|
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalConnectRequest;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalConnectResponse;
|
import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalConnectResponse;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.session.TerminalSession;
|
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.session.SftpSession;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.session.SshSession;
|
||||||
import com.orion.ops.module.asset.service.HostConnectLogService;
|
import com.orion.ops.module.asset.service.HostConnectLogService;
|
||||||
import com.orion.ops.module.asset.service.HostTerminalService;
|
import com.orion.ops.module.asset.service.HostTerminalService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -68,9 +71,9 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConn
|
|||||||
Exception ex = null;
|
Exception ex = null;
|
||||||
try {
|
try {
|
||||||
// 连接主机
|
// 连接主机
|
||||||
TerminalSession terminalSession = this.connect(sessionId, connect, channel, payload);
|
ITerminalSession session = this.connect(sessionId, connect, channel, payload);
|
||||||
// 添加会话到 manager
|
// 添加会话到 manager
|
||||||
terminalManager.addSession(terminalSession);
|
terminalManager.addSession(session);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ex = e;
|
ex = e;
|
||||||
// 修改连接状态为失败
|
// 修改连接状态为失败
|
||||||
@@ -95,11 +98,12 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConn
|
|||||||
* @param body body
|
* @param body body
|
||||||
* @return channel
|
* @return channel
|
||||||
*/
|
*/
|
||||||
private TerminalSession connect(String sessionId,
|
private ITerminalSession connect(String sessionId,
|
||||||
HostTerminalConnectDTO connect,
|
HostTerminalConnectDTO connect,
|
||||||
WebSocketSession channel,
|
WebSocketSession channel,
|
||||||
TerminalConnectRequest body) {
|
TerminalConnectRequest body) {
|
||||||
TerminalSession terminalSession = null;
|
String connectType = connect.getConnectType();
|
||||||
|
ITerminalSession session = null;
|
||||||
try {
|
try {
|
||||||
// 连接配置
|
// 连接配置
|
||||||
TerminalConfig config = TerminalConfig.builder()
|
TerminalConfig config = TerminalConfig.builder()
|
||||||
@@ -109,12 +113,21 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConn
|
|||||||
.build();
|
.build();
|
||||||
// 建立连接
|
// 建立连接
|
||||||
SessionStore sessionStore = hostTerminalService.openSessionStore(connect);
|
SessionStore sessionStore = hostTerminalService.openSessionStore(connect);
|
||||||
terminalSession = new TerminalSession(sessionId, channel, sessionStore, config);
|
if (HostConnectTypeEnum.SSH.name().equals(connectType)) {
|
||||||
terminalSession.connect(body.getTerminalType(), body.getCols(), body.getRows());
|
// 打开 ssh 会话
|
||||||
|
SshSession sshSession = new SshSession(sessionId, channel, sessionStore, config);
|
||||||
|
sshSession.connect(body.getTerminalType(), body.getCols(), body.getRows());
|
||||||
|
session = sshSession;
|
||||||
|
} else if (HostConnectTypeEnum.SFTP.name().equals(connectType)) {
|
||||||
|
// 打开 sftp 会话
|
||||||
|
SftpSession sftpSession = new SftpSession(sessionId, channel, sessionStore, config);
|
||||||
|
sftpSession.connect();
|
||||||
|
session = sftpSession;
|
||||||
|
}
|
||||||
log.info("TerminalConnectHandler-handle success sessionId: {}", sessionId);
|
log.info("TerminalConnectHandler-handle success sessionId: {}", sessionId);
|
||||||
return terminalSession;
|
return session;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Streams.close(terminalSession);
|
Streams.close(session);
|
||||||
log.error("TerminalConnectHandler-handle error sessionId: {}", sessionId, e);
|
log.error("TerminalConnectHandler-handle error sessionId: {}", sessionId, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
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 channel, TerminalExecRequest payload) {
|
|
||||||
// 获取会话
|
|
||||||
ITerminalSession terminalSession = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
|
||||||
if (terminalSession != null) {
|
|
||||||
// 执行命令
|
|
||||||
terminalSession.write(payload.getCommand());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ 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.manager.TerminalManager;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalInputRequest;
|
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalInputRequest;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.session.ISshSession;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
|
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -26,10 +27,10 @@ public class TerminalInputHandler extends AbstractTerminalHandler<TerminalInputR
|
|||||||
@Override
|
@Override
|
||||||
public void handle(WebSocketSession channel, TerminalInputRequest payload) {
|
public void handle(WebSocketSession channel, TerminalInputRequest payload) {
|
||||||
// 获取会话
|
// 获取会话
|
||||||
ITerminalSession terminalSession = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
ITerminalSession session = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
||||||
if (terminalSession != null) {
|
if (session instanceof ISshSession) {
|
||||||
// 处理输入
|
// 处理输入
|
||||||
terminalSession.write(payload.getCommand());
|
((ISshSession) session).write(payload.getCommand());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ 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.manager.TerminalManager;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalResizeRequest;
|
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalResizeRequest;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.session.ISshSession;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
|
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -26,10 +27,10 @@ public class TerminalResizeHandler extends AbstractTerminalHandler<TerminalResiz
|
|||||||
@Override
|
@Override
|
||||||
public void handle(WebSocketSession channel, TerminalResizeRequest payload) {
|
public void handle(WebSocketSession channel, TerminalResizeRequest payload) {
|
||||||
// 获取会话
|
// 获取会话
|
||||||
ITerminalSession terminalSession = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
ITerminalSession session = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
||||||
if (terminalSession != null) {
|
if (session instanceof ISshSession) {
|
||||||
// 修改大小
|
// 修改大小
|
||||||
terminalSession.resize(payload.getCols(), payload.getRows());
|
((ISshSession) session).resize(payload.getCols(), payload.getRows());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import com.orion.lang.define.collect.MultiConcurrentHashMap;
|
|||||||
import com.orion.lang.utils.collect.Maps;
|
import com.orion.lang.utils.collect.Maps;
|
||||||
import com.orion.lang.utils.io.Streams;
|
import com.orion.lang.utils.io.Streams;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
|
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.session.TerminalSession;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -30,8 +29,8 @@ public class TerminalManager {
|
|||||||
*
|
*
|
||||||
* @param session session
|
* @param session session
|
||||||
*/
|
*/
|
||||||
public void addSession(TerminalSession session) {
|
public void addSession(ITerminalSession session) {
|
||||||
channelSessions.put(session.getChannel().getId(), session.getSessionId(), session);
|
channelSessions.put(session.getChannelId(), session.getSessionId(), session);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,4 +28,7 @@ public class TerminalCheckRequest extends TerminalBasePayload {
|
|||||||
@Schema(description = "主机id")
|
@Schema(description = "主机id")
|
||||||
private Long hostId;
|
private Long hostId;
|
||||||
|
|
||||||
|
@Schema(description = "连接类型")
|
||||||
|
private String connectType;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.orion.ops.module.asset.handler.host.terminal.session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sftp 会话定义
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/2/4 16:48
|
||||||
|
*/
|
||||||
|
public interface ISftpSession extends ITerminalSession {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 建立连接
|
||||||
|
*/
|
||||||
|
void connect();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.orion.ops.module.asset.handler.host.terminal.session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ssh 会话定义
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/2/4 16:47
|
||||||
|
*/
|
||||||
|
public interface ISshSession extends ITerminalSession {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接
|
||||||
|
*
|
||||||
|
* @param terminalType terminalType
|
||||||
|
* @param cols cols
|
||||||
|
* @param rows rows
|
||||||
|
*/
|
||||||
|
void connect(String terminalType, int cols, int rows);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置大小
|
||||||
|
*
|
||||||
|
* @param cols cols
|
||||||
|
* @param rows rows
|
||||||
|
*/
|
||||||
|
void resize(int cols, int rows);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入内容
|
||||||
|
*
|
||||||
|
* @param b b
|
||||||
|
*/
|
||||||
|
void write(String b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入内容
|
||||||
|
*
|
||||||
|
* @param b b
|
||||||
|
*/
|
||||||
|
void write(byte[] b);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,38 +12,21 @@ import com.orion.lang.able.SafeCloseable;
|
|||||||
public interface ITerminalSession extends SafeCloseable {
|
public interface ITerminalSession extends SafeCloseable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接
|
* 获取 sessionId
|
||||||
*
|
*
|
||||||
* @param terminalType terminalType
|
* @return sessionId
|
||||||
* @param cols cols
|
|
||||||
* @param rows rows
|
|
||||||
*/
|
*/
|
||||||
void connect(String terminalType, int cols, int rows);
|
String getSessionId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置大小
|
* 获取 channelId
|
||||||
*
|
*
|
||||||
* @param cols cols
|
* @return channelId
|
||||||
* @param rows rows
|
|
||||||
*/
|
*/
|
||||||
void resize(int cols, int rows);
|
String getChannelId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写入内容
|
* 活跃会话
|
||||||
*
|
|
||||||
* @param b b
|
|
||||||
*/
|
|
||||||
void write(String b);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 写入内容
|
|
||||||
*
|
|
||||||
* @param b b
|
|
||||||
*/
|
|
||||||
void write(byte[] b);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 活跃回话
|
|
||||||
*/
|
*/
|
||||||
void keepAlive();
|
void keepAlive();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.orion.ops.module.asset.handler.host.terminal.session;
|
||||||
|
|
||||||
|
import com.orion.lang.utils.io.Streams;
|
||||||
|
import com.orion.net.host.SessionStore;
|
||||||
|
import com.orion.net.host.sftp.SftpExecutor;
|
||||||
|
import com.orion.ops.framework.common.constant.Const;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.model.TerminalConfig;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端 ssh 会话
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/1/2 17:28
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SftpSession extends TerminalSession implements ISftpSession {
|
||||||
|
|
||||||
|
private final TerminalConfig config;
|
||||||
|
|
||||||
|
private final SessionStore sessionStore;
|
||||||
|
|
||||||
|
private SftpExecutor executor;
|
||||||
|
|
||||||
|
public SftpSession(String sessionId,
|
||||||
|
WebSocketSession channel,
|
||||||
|
SessionStore sessionStore,
|
||||||
|
TerminalConfig config) {
|
||||||
|
super(sessionId, channel);
|
||||||
|
this.sessionStore = sessionStore;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect() {
|
||||||
|
// 打开 shell
|
||||||
|
this.executor = sessionStore.getSftpExecutor(config.getFileNameCharset());
|
||||||
|
executor.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keepAlive() {
|
||||||
|
try {
|
||||||
|
// 发送个信号 保证 socket 不自动关闭
|
||||||
|
executor.sendSignal(Const.EMPTY);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("sftp keep-alive error {}", sessionId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void releaseResource() {
|
||||||
|
Streams.close(executor);
|
||||||
|
Streams.close(sessionStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
package com.orion.ops.module.asset.handler.host.terminal.session;
|
||||||
|
|
||||||
|
import com.orion.lang.utils.io.Streams;
|
||||||
|
import com.orion.net.host.SessionStore;
|
||||||
|
import com.orion.net.host.ssh.shell.ShellExecutor;
|
||||||
|
import com.orion.ops.framework.common.constant.Const;
|
||||||
|
import com.orion.ops.framework.websocket.core.utils.WebSockets;
|
||||||
|
import com.orion.ops.module.asset.define.AssetThreadPools;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.constant.TerminalMessage;
|
||||||
|
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.response.TerminalCloseResponse;
|
||||||
|
import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalOutputResponse;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端 ssh 会话
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/1/2 17:28
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SshSession extends TerminalSession implements ISshSession {
|
||||||
|
|
||||||
|
private final TerminalConfig config;
|
||||||
|
|
||||||
|
private final SessionStore sessionStore;
|
||||||
|
|
||||||
|
private ShellExecutor executor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String lastLine;
|
||||||
|
|
||||||
|
public SshSession(String sessionId,
|
||||||
|
WebSocketSession channel,
|
||||||
|
SessionStore sessionStore,
|
||||||
|
TerminalConfig config) {
|
||||||
|
super(sessionId, channel);
|
||||||
|
this.sessionStore = sessionStore;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(String terminalType, int cols, int rows) {
|
||||||
|
config.setCols(cols);
|
||||||
|
config.setRows(rows);
|
||||||
|
// 打开 shell
|
||||||
|
this.executor = sessionStore.getShellExecutor();
|
||||||
|
executor.size(cols, rows);
|
||||||
|
executor.terminalType(terminalType);
|
||||||
|
executor.streamHandler(this::streamHandler);
|
||||||
|
executor.callback(this::eofCallback);
|
||||||
|
executor.connect();
|
||||||
|
// 开始监听输出
|
||||||
|
AssetThreadPools.TERMINAL_SCHEDULER.execute(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resize(int cols, int rows) {
|
||||||
|
// FIXME 没啥用就删了
|
||||||
|
// if (!executor.isConnected()) {
|
||||||
|
// executor.connect();
|
||||||
|
// }
|
||||||
|
// 大小发生变化 则修改大小
|
||||||
|
if (cols != config.getCols() ||
|
||||||
|
rows != config.getRows()) {
|
||||||
|
config.setCols(cols);
|
||||||
|
config.setRows(rows);
|
||||||
|
executor.size(cols, rows);
|
||||||
|
executor.resize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String b) {
|
||||||
|
executor.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b) {
|
||||||
|
executor.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keepAlive() {
|
||||||
|
try {
|
||||||
|
// 发送个信号 保证 socket 不自动关闭
|
||||||
|
executor.sendSignal(Const.EMPTY);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("ssh keep-alive error {}", sessionId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void releaseResource() {
|
||||||
|
Streams.close(executor);
|
||||||
|
Streams.close(sessionStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准输出处理
|
||||||
|
*
|
||||||
|
* @param inputStream stream
|
||||||
|
*/
|
||||||
|
private void streamHandler(InputStream inputStream) {
|
||||||
|
byte[] bs = new byte[Const.BUFFER_KB_4];
|
||||||
|
BufferedInputStream in = new BufferedInputStream(inputStream, Const.BUFFER_KB_4);
|
||||||
|
int read;
|
||||||
|
try {
|
||||||
|
while (channel.isOpen() && (read = in.read(bs)) != -1) {
|
||||||
|
String body = lastLine = new String(bs, 0, read, config.getCharset());
|
||||||
|
// 响应
|
||||||
|
TerminalOutputResponse resp = TerminalOutputResponse.builder()
|
||||||
|
.type(OutputTypeEnum.OUTPUT.getType())
|
||||||
|
.sessionId(sessionId)
|
||||||
|
.body(body)
|
||||||
|
.build();
|
||||||
|
WebSockets.sendText(channel, OutputTypeEnum.OUTPUT.format(resp));
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
log.error("terminal 读取流失败", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eof 回调
|
||||||
|
*/
|
||||||
|
private void eofCallback() {
|
||||||
|
log.info("terminal eof回调 {}, forClose: {}", sessionId, this.close);
|
||||||
|
// 发送关闭信息
|
||||||
|
TerminalCloseResponse resp = TerminalCloseResponse.builder()
|
||||||
|
.type(OutputTypeEnum.CLOSE.getType())
|
||||||
|
.sessionId(this.sessionId)
|
||||||
|
.msg(TerminalMessage.CLOSED_CONNECTION)
|
||||||
|
.build();
|
||||||
|
WebSockets.sendText(channel, OutputTypeEnum.CLOSE.format(resp));
|
||||||
|
// 需要调用关闭 - 可能是 logout 需要手动触发
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,114 +1,38 @@
|
|||||||
package com.orion.ops.module.asset.handler.host.terminal.session;
|
package com.orion.ops.module.asset.handler.host.terminal.session;
|
||||||
|
|
||||||
import com.orion.lang.utils.io.Streams;
|
|
||||||
import com.orion.net.host.SessionStore;
|
|
||||||
import com.orion.net.host.ssh.TerminalType;
|
|
||||||
import com.orion.net.host.ssh.shell.ShellExecutor;
|
|
||||||
import com.orion.ops.framework.common.constant.Const;
|
|
||||||
import com.orion.ops.framework.websocket.core.utils.WebSockets;
|
|
||||||
import com.orion.ops.module.asset.define.AssetThreadPools;
|
|
||||||
import com.orion.ops.module.asset.enums.HostConnectStatusEnum;
|
import com.orion.ops.module.asset.enums.HostConnectStatusEnum;
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.constant.TerminalMessage;
|
|
||||||
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.response.TerminalCloseResponse;
|
|
||||||
import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalOutputResponse;
|
|
||||||
import com.orion.ops.module.asset.service.HostConnectLogService;
|
import com.orion.ops.module.asset.service.HostConnectLogService;
|
||||||
import com.orion.spring.SpringHolder;
|
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;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 终端会话
|
* 终端会话基类
|
||||||
*
|
*
|
||||||
* @author Jiahang Li
|
* @author Jiahang Li
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
* @since 2024/1/2 17:28
|
* @since 2024/2/4 16:51
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TerminalSession implements ITerminalSession {
|
public abstract class TerminalSession implements ITerminalSession {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final String sessionId;
|
protected final String sessionId;
|
||||||
|
|
||||||
@Getter
|
protected final WebSocketSession channel;
|
||||||
private final WebSocketSession channel;
|
|
||||||
|
|
||||||
private final TerminalConfig config;
|
protected volatile boolean close;
|
||||||
|
|
||||||
private final SessionStore sessionStore;
|
public TerminalSession(String sessionId, WebSocketSession channel) {
|
||||||
|
|
||||||
private ShellExecutor executor;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private String lastLine;
|
|
||||||
|
|
||||||
private volatile boolean close;
|
|
||||||
|
|
||||||
public TerminalSession(String sessionId,
|
|
||||||
WebSocketSession channel,
|
|
||||||
SessionStore sessionStore,
|
|
||||||
TerminalConfig config) {
|
|
||||||
this.sessionId = sessionId;
|
this.sessionId = sessionId;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
this.sessionStore = sessionStore;
|
|
||||||
this.config = config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void connect(String terminalType, int cols, int rows) {
|
* 释放资源
|
||||||
config.setCols(cols);
|
*/
|
||||||
config.setRows(rows);
|
protected abstract void releaseResource();
|
||||||
// 打开 shell
|
|
||||||
this.executor = sessionStore.getShellExecutor();
|
|
||||||
executor.size(cols, rows);
|
|
||||||
executor.terminalType(terminalType);
|
|
||||||
executor.streamHandler(this::streamHandler);
|
|
||||||
executor.callback(this::eofCallback);
|
|
||||||
executor.connect();
|
|
||||||
// 开始监听输出
|
|
||||||
AssetThreadPools.TERMINAL_SCHEDULER.execute(executor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resize(int cols, int rows) {
|
|
||||||
if (!executor.isConnected()) {
|
|
||||||
executor.connect();
|
|
||||||
}
|
|
||||||
// 大小发生变化 则修改大小
|
|
||||||
if (cols != config.getCols() ||
|
|
||||||
rows != config.getRows()) {
|
|
||||||
config.setCols(cols);
|
|
||||||
config.setRows(rows);
|
|
||||||
executor.size(cols, rows);
|
|
||||||
executor.resize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(String b) {
|
|
||||||
executor.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(byte[] b) {
|
|
||||||
executor.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void keepAlive() {
|
|
||||||
try {
|
|
||||||
// 发送个信号 保证 socket 不自动关闭
|
|
||||||
executor.sendSignal(Const.EMPTY);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("terminal keep-alive error {}", sessionId, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
@@ -117,56 +41,19 @@ public class TerminalSession implements ITerminalSession {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.close = true;
|
this.close = true;
|
||||||
// 关闭流
|
// 释放资源
|
||||||
try {
|
try {
|
||||||
Streams.close(executor);
|
this.releaseResource();
|
||||||
Streams.close(sessionStore);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("terminal 断开连接失败 {}", sessionId, e);
|
log.error("terminal release error {}", sessionId, e);
|
||||||
}
|
}
|
||||||
// 修改状态
|
// 修改状态
|
||||||
SpringHolder.getBean(HostConnectLogService.class).updateStatusByToken(sessionId, HostConnectStatusEnum.COMPLETE);
|
SpringHolder.getBean(HostConnectLogService.class).updateStatusByToken(sessionId, HostConnectStatusEnum.COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 标准输出处理
|
public String getChannelId() {
|
||||||
*
|
return channel.getId();
|
||||||
* @param inputStream stream
|
|
||||||
*/
|
|
||||||
private void streamHandler(InputStream inputStream) {
|
|
||||||
byte[] bs = new byte[Const.BUFFER_KB_4];
|
|
||||||
BufferedInputStream in = new BufferedInputStream(inputStream, Const.BUFFER_KB_4);
|
|
||||||
int read;
|
|
||||||
try {
|
|
||||||
while (channel.isOpen() && (read = in.read(bs)) != -1) {
|
|
||||||
String body = lastLine = new String(bs, 0, read, config.getCharset());
|
|
||||||
// 响应
|
|
||||||
TerminalOutputResponse resp = TerminalOutputResponse.builder()
|
|
||||||
.type(OutputTypeEnum.OUTPUT.getType())
|
|
||||||
.sessionId(sessionId)
|
|
||||||
.body(body)
|
|
||||||
.build();
|
|
||||||
WebSockets.sendText(channel, OutputTypeEnum.OUTPUT.format(resp));
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
|
||||||
log.error("terminal 读取流失败", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* eof 回调
|
|
||||||
*/
|
|
||||||
private void eofCallback() {
|
|
||||||
log.info("terminal eof回调 {}, forClose: {}", sessionId, this.close);
|
|
||||||
// 发送关闭信息
|
|
||||||
TerminalCloseResponse resp = TerminalCloseResponse.builder()
|
|
||||||
.type(OutputTypeEnum.CLOSE.getType())
|
|
||||||
.sessionId(this.sessionId)
|
|
||||||
.msg(TerminalMessage.CLOSED_CONNECTION)
|
|
||||||
.build();
|
|
||||||
WebSockets.sendText(channel, OutputTypeEnum.CLOSE.format(resp));
|
|
||||||
// 需要调用关闭 - 可能是 logout 需要手动触发
|
|
||||||
this.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.orion.net.host.SessionStore;
|
|||||||
import com.orion.ops.module.asset.entity.domain.HostDO;
|
import com.orion.ops.module.asset.entity.domain.HostDO;
|
||||||
import com.orion.ops.module.asset.entity.dto.HostTerminalAccessDTO;
|
import com.orion.ops.module.asset.entity.dto.HostTerminalAccessDTO;
|
||||||
import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO;
|
import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO;
|
||||||
|
import com.orion.ops.module.asset.enums.HostConnectTypeEnum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主机终端服务
|
* 主机终端服务
|
||||||
@@ -42,18 +43,20 @@ public interface HostTerminalService {
|
|||||||
*
|
*
|
||||||
* @param hostId hostId
|
* @param hostId hostId
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
|
* @param type type
|
||||||
* @return session
|
* @return session
|
||||||
*/
|
*/
|
||||||
HostTerminalConnectDTO getTerminalConnectInfo(Long userId, Long hostId);
|
HostTerminalConnectDTO getTerminalConnectInfo(Long userId, Long hostId, HostConnectTypeEnum type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用用户配置获取连接信息
|
* 使用用户配置获取连接信息
|
||||||
*
|
*
|
||||||
* @param host host
|
* @param host host
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
|
* @param type type
|
||||||
* @return session
|
* @return session
|
||||||
*/
|
*/
|
||||||
HostTerminalConnectDTO getTerminalConnectInfo(Long userId, HostDO host);
|
HostTerminalConnectDTO getTerminalConnectInfo(Long userId, HostDO host, HostConnectTypeEnum type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用默认配置打开主机会话
|
* 使用默认配置打开主机会话
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ import com.orion.ops.module.asset.entity.domain.HostIdentityDO;
|
|||||||
import com.orion.ops.module.asset.entity.domain.HostKeyDO;
|
import com.orion.ops.module.asset.entity.domain.HostKeyDO;
|
||||||
import com.orion.ops.module.asset.entity.dto.HostTerminalAccessDTO;
|
import com.orion.ops.module.asset.entity.dto.HostTerminalAccessDTO;
|
||||||
import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO;
|
import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO;
|
||||||
import com.orion.ops.module.asset.enums.HostConfigTypeEnum;
|
import com.orion.ops.module.asset.enums.*;
|
||||||
import com.orion.ops.module.asset.enums.HostExtraItemEnum;
|
|
||||||
import com.orion.ops.module.asset.enums.HostExtraSshAuthTypeEnum;
|
|
||||||
import com.orion.ops.module.asset.enums.HostSshAuthTypeEnum;
|
|
||||||
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
|
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
|
||||||
import com.orion.ops.module.asset.handler.host.extra.model.HostSshExtraModel;
|
import com.orion.ops.module.asset.handler.host.extra.model.HostSshExtraModel;
|
||||||
import com.orion.ops.module.asset.service.HostConfigService;
|
import com.orion.ops.module.asset.service.HostConfigService;
|
||||||
@@ -121,15 +118,15 @@ public class HostTerminalServiceImpl implements HostTerminalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HostTerminalConnectDTO getTerminalConnectInfo(Long userId, Long hostId) {
|
public HostTerminalConnectDTO getTerminalConnectInfo(Long userId, Long hostId, HostConnectTypeEnum type) {
|
||||||
// 查询主机
|
// 查询主机
|
||||||
HostDO host = hostDAO.selectById(hostId);
|
HostDO host = hostDAO.selectById(hostId);
|
||||||
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
|
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
|
||||||
return this.getTerminalConnectInfo(userId, host);
|
return this.getTerminalConnectInfo(userId, host, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HostTerminalConnectDTO getTerminalConnectInfo(Long userId, HostDO host) {
|
public HostTerminalConnectDTO getTerminalConnectInfo(Long userId, HostDO host, HostConnectTypeEnum type) {
|
||||||
Long hostId = host.getId();
|
Long hostId = host.getId();
|
||||||
log.info("HostConnectService.getTerminalConnectInfo hostId: {}, userId: {}", hostId, userId);
|
log.info("HostConnectService.getTerminalConnectInfo hostId: {}, userId: {}", hostId, userId);
|
||||||
// 查询用户
|
// 查询用户
|
||||||
@@ -164,7 +161,9 @@ public class HostTerminalServiceImpl implements HostTerminalService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 获取连接配置
|
// 获取连接配置
|
||||||
return this.getHostConnectInfo(host, config, extra);
|
HostTerminalConnectDTO connectInfo = this.getHostConnectInfo(host, config, extra);
|
||||||
|
connectInfo.setConnectType(type.name());
|
||||||
|
return connectInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ public class TerminalPreferenceStrategy implements IPreferenceStrategy<TerminalP
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TerminalPreferenceModel getDefault() {
|
public TerminalPreferenceModel getDefault() {
|
||||||
// ...快捷键 ...背景
|
|
||||||
// 默认显示设置
|
// 默认显示设置
|
||||||
String defaultDisplaySetting = TerminalPreferenceModel.DisplaySettingModel
|
String defaultDisplaySetting = TerminalPreferenceModel.DisplaySettingModel
|
||||||
.builder()
|
.builder()
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public interface MineService {
|
|||||||
/**
|
/**
|
||||||
* 获取当前用户会话列表
|
* 获取当前用户会话列表
|
||||||
*
|
*
|
||||||
* @return 回话列表
|
* @return 会话列表
|
||||||
*/
|
*/
|
||||||
List<UserSessionVO> getCurrentUserSessionList();
|
List<UserSessionVO> getCurrentUserSessionList();
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public interface SystemUserManagementService {
|
|||||||
* 获取用户会话列表
|
* 获取用户会话列表
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @return 回话列表
|
* @return 会话列表
|
||||||
*/
|
*/
|
||||||
List<UserSessionVO> getUserSessionList(Long userId);
|
List<UserSessionVO> getUserSessionList(Long userId);
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ export default class TerminalSessionManager implements ITerminalSessionManager {
|
|||||||
// 发送会话初始化请求
|
// 发送会话初始化请求
|
||||||
this.channel.send(InputProtocol.CHECK, {
|
this.channel.send(InputProtocol.CHECK, {
|
||||||
sessionId,
|
sessionId,
|
||||||
hostId
|
hostId,
|
||||||
|
connectType: 'SSH'
|
||||||
});
|
});
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export const InputProtocol = {
|
|||||||
// 主机连接检查
|
// 主机连接检查
|
||||||
CHECK: {
|
CHECK: {
|
||||||
type: 'ck',
|
type: 'ck',
|
||||||
template: ['type', 'sessionId', 'hostId']
|
template: ['type', 'sessionId', 'hostId', 'connectType']
|
||||||
},
|
},
|
||||||
// 连接主机
|
// 连接主机
|
||||||
CONNECT: {
|
CONNECT: {
|
||||||
@@ -25,11 +25,6 @@ export const InputProtocol = {
|
|||||||
type: 'rs',
|
type: 'rs',
|
||||||
template: ['type', 'sessionId', 'cols', 'rows']
|
template: ['type', 'sessionId', 'cols', 'rows']
|
||||||
},
|
},
|
||||||
// 执行
|
|
||||||
EXEC: {
|
|
||||||
type: 'e',
|
|
||||||
template: ['type', 'sessionId', 'command']
|
|
||||||
},
|
|
||||||
// 输入
|
// 输入
|
||||||
INPUT: {
|
INPUT: {
|
||||||
type: 'i',
|
type: 'i',
|
||||||
|
|||||||
Reference in New Issue
Block a user