🔨 优化 sftp 代码逻辑.
This commit is contained in:
@@ -77,4 +77,6 @@ public interface ErrorMessage {
|
||||
|
||||
String CONNECT_ERROR = "连接失败";
|
||||
|
||||
String PATH_NOT_NORMALIZE = "路径不合法";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.orion.ops.framework.common.utils;
|
||||
|
||||
import com.orion.lang.utils.Arrays1;
|
||||
import com.orion.lang.utils.io.Files1;
|
||||
import com.orion.ops.framework.common.constant.ErrorMessage;
|
||||
import com.orion.spring.SpringHolder;
|
||||
|
||||
@@ -116,4 +117,15 @@ public class Valid extends com.orion.lang.utils.Valid {
|
||||
return effect;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查路径是否合法化 即不包含 ./ ../
|
||||
*
|
||||
* @param path path
|
||||
*/
|
||||
public static String checkNormalize(String path) {
|
||||
Valid.notBlank(path);
|
||||
Valid.isTrue(Files1.isNormalize(path), ErrorMessage.PATH_NOT_NORMALIZE);
|
||||
return Files1.getPath(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@ package com.orion.ops.module.asset.handler.host.terminal.handler;
|
||||
|
||||
import com.orion.ops.framework.websocket.core.utils.WebSockets;
|
||||
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.model.TerminalBasePayload;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 终端消息处理器 基类
|
||||
*
|
||||
@@ -14,6 +17,9 @@ import org.springframework.web.socket.WebSocketSession;
|
||||
*/
|
||||
public abstract class AbstractTerminalHandler<T extends TerminalBasePayload> implements ITerminalHandler<T> {
|
||||
|
||||
@Resource
|
||||
protected TerminalManager terminalManager;
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
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.SshInputRequest;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.session.ISshSession;
|
||||
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;
|
||||
|
||||
/**
|
||||
* ssh 处理输入处理器
|
||||
*
|
||||
@@ -21,17 +17,12 @@ import javax.annotation.Resource;
|
||||
@Component
|
||||
public class SshInputHandler extends AbstractTerminalHandler<SshInputRequest> {
|
||||
|
||||
@Resource
|
||||
private TerminalManager terminalManager;
|
||||
|
||||
@Override
|
||||
public void handle(WebSocketSession channel, SshInputRequest payload) {
|
||||
// 获取会话
|
||||
ITerminalSession session = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
||||
if (session instanceof ISshSession) {
|
||||
// 处理输入
|
||||
((ISshSession) session).write(payload.getCommand());
|
||||
}
|
||||
ISshSession session = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
||||
// 处理输入
|
||||
session.write(payload.getCommand());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
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.SshResizeRequest;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.session.ISshSession;
|
||||
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;
|
||||
|
||||
/**
|
||||
* ssh 修改大小处理器
|
||||
*
|
||||
@@ -21,17 +17,12 @@ import javax.annotation.Resource;
|
||||
@Component
|
||||
public class SshResizeHandler extends AbstractTerminalHandler<SshResizeRequest> {
|
||||
|
||||
@Resource
|
||||
private TerminalManager terminalManager;
|
||||
|
||||
@Override
|
||||
public void handle(WebSocketSession channel, SshResizeRequest payload) {
|
||||
// 获取会话
|
||||
ITerminalSession session = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
||||
if (session instanceof ISshSession) {
|
||||
// 修改大小
|
||||
((ISshSession) session).resize(payload.getCols(), payload.getRows());
|
||||
}
|
||||
ISshSession session = terminalManager.getSession(channel.getId(), payload.getSessionId());
|
||||
// 修改大小
|
||||
session.resize(payload.getCols(), payload.getRows());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.orion.ops.module.asset.entity.request.host.HostConnectLogCreateReques
|
||||
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.enums.OutputTypeEnum;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.manager.TerminalManager;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.model.request.TerminalCheckRequest;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalCheckResponse;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.session.ITerminalSession;
|
||||
@@ -53,9 +52,6 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
|
||||
@Resource
|
||||
private OperatorLogFrameworkService operatorLogFrameworkService;
|
||||
|
||||
@Resource
|
||||
private TerminalManager terminalManager;
|
||||
|
||||
@Override
|
||||
public void handle(WebSocketSession channel, TerminalCheckRequest payload) {
|
||||
Long hostId = payload.getHostId();
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 关闭处理器
|
||||
*
|
||||
@@ -19,9 +16,6 @@ import javax.annotation.Resource;
|
||||
@Component
|
||||
public class TerminalCloseHandler extends AbstractTerminalHandler<TerminalBasePayload> {
|
||||
|
||||
@Resource
|
||||
private TerminalManager terminalManager;
|
||||
|
||||
@Override
|
||||
public void handle(WebSocketSession channel, TerminalBasePayload payload) {
|
||||
log.info("TerminalCloseHandler-handle start session: {}", payload.getSessionId());
|
||||
|
||||
@@ -14,7 +14,6 @@ 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.enums.OutputTypeEnum;
|
||||
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.request.TerminalConnectRequest;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.model.response.TerminalConnectResponse;
|
||||
@@ -46,9 +45,6 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConn
|
||||
@Resource
|
||||
private HostConnectLogService hostConnectLogService;
|
||||
|
||||
@Resource
|
||||
private TerminalManager terminalManager;
|
||||
|
||||
@Override
|
||||
public void handle(WebSocketSession channel, TerminalConnectRequest payload) {
|
||||
String sessionId = payload.getSessionId();
|
||||
|
||||
@@ -2,14 +2,12 @@ package com.orion.ops.module.asset.handler.host.terminal.handler;
|
||||
|
||||
import com.orion.lang.utils.collect.Maps;
|
||||
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.model.TerminalBasePayload;
|
||||
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;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -23,9 +21,6 @@ import java.util.Map;
|
||||
@Component
|
||||
public class TerminalPingHandler extends AbstractTerminalHandler<TerminalBasePayload> {
|
||||
|
||||
@Resource
|
||||
private TerminalManager terminalManager;
|
||||
|
||||
@Override
|
||||
public void handle(WebSocketSession channel, TerminalBasePayload payload) {
|
||||
// 发送 pong
|
||||
|
||||
@@ -52,10 +52,12 @@ public class TerminalManager {
|
||||
*
|
||||
* @param channelId channelId
|
||||
* @param sessionId sessionId
|
||||
* @param T T
|
||||
* @return session
|
||||
*/
|
||||
public ITerminalSession getSession(String channelId, String sessionId) {
|
||||
return channelSessions.get(channelId, sessionId);
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ITerminalSession> T getSession(String channelId, String sessionId) {
|
||||
return (T) channelSessions.get(channelId, sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,7 @@ public class SftpChangeModRequest extends TerminalBasePayload {
|
||||
@Schema(description = "path")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "权限")
|
||||
private String mod;
|
||||
@Schema(description = "10进制的8进制 权限")
|
||||
private Integer mod;
|
||||
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* sftp 删除文件 实体对象
|
||||
* <p>
|
||||
* i|eff00a1|path
|
||||
* i|eff00a1|paths
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -25,7 +27,7 @@ import lombok.experimental.SuperBuilder;
|
||||
@Schema(name = "SftpRemoveRequest", description = "sftp 删除文件 实体对象")
|
||||
public class SftpRemoveRequest extends TerminalBasePayload {
|
||||
|
||||
@Schema(description = "path")
|
||||
private String path;
|
||||
@Schema(description = "paths 多个用|分割")
|
||||
private List<String> paths;
|
||||
|
||||
}
|
||||
|
||||
@@ -23,12 +23,12 @@ import lombok.experimental.SuperBuilder;
|
||||
@Schema(name = "SftpListResponse", description = "sftp 列表响应 实体对象")
|
||||
public class SftpListResponse extends TerminalBasePayload {
|
||||
|
||||
@Schema(description = "检查结果")
|
||||
private Integer result;
|
||||
|
||||
@Schema(description = "path")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "结果")
|
||||
private Integer result;
|
||||
|
||||
@Schema(description = "body")
|
||||
private String body;
|
||||
|
||||
|
||||
@@ -34,4 +34,64 @@ public interface ISftpSession extends ITerminalSession {
|
||||
*/
|
||||
List<SftpFileResponse> list(String path, boolean showHiddenFile);
|
||||
|
||||
/**
|
||||
* 创建文件夹
|
||||
*
|
||||
* @param path path
|
||||
*/
|
||||
void mkdir(String path);
|
||||
|
||||
/**
|
||||
* 创建文件
|
||||
*
|
||||
* @param path path
|
||||
*/
|
||||
void touch(String path);
|
||||
|
||||
/**
|
||||
* 移动文件
|
||||
*
|
||||
* @param source source
|
||||
* @param target target
|
||||
*/
|
||||
void move(String source, String target);
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param paths paths
|
||||
*/
|
||||
void remove(List<String> paths);
|
||||
|
||||
/**
|
||||
* 截断文件
|
||||
*
|
||||
* @param path path
|
||||
*/
|
||||
void truncate(String path);
|
||||
|
||||
/**
|
||||
* 修改权限
|
||||
*
|
||||
* @param path path
|
||||
* @param mod mod
|
||||
*/
|
||||
void chmod(String path, int mod);
|
||||
|
||||
/**
|
||||
* 获取内容
|
||||
*
|
||||
* @param path path
|
||||
* @return content
|
||||
*/
|
||||
String getContent(String path);
|
||||
|
||||
/**
|
||||
* 设置内容
|
||||
*
|
||||
* @param path path
|
||||
* @param content content
|
||||
*/
|
||||
void setContent(String path, String content);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.orion.ops.module.asset.handler.host.terminal.session;
|
||||
|
||||
import com.orion.lang.utils.Exceptions;
|
||||
import com.orion.lang.utils.Strings;
|
||||
import com.orion.lang.utils.io.FileType;
|
||||
import com.orion.lang.utils.io.Files1;
|
||||
import com.orion.lang.utils.io.Streams;
|
||||
@@ -7,17 +9,19 @@ import com.orion.net.host.SessionStore;
|
||||
import com.orion.net.host.sftp.SftpExecutor;
|
||||
import com.orion.net.host.sftp.SftpFile;
|
||||
import com.orion.ops.framework.common.constant.Const;
|
||||
import com.orion.ops.framework.common.utils.Valid;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.model.TerminalConfig;
|
||||
import com.orion.ops.module.asset.handler.host.terminal.model.response.SftpFileResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 终端 ssh 会话
|
||||
* 终端 sftp 会话
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
@@ -55,6 +59,7 @@ public class SftpSession extends TerminalSession implements ISftpSession {
|
||||
|
||||
@Override
|
||||
public List<SftpFileResponse> list(String path, boolean showHiddenFile) {
|
||||
path = Files1.getPath(path);
|
||||
// 查询文件
|
||||
List<SftpFile> files = executor.listFilesFilter(path,
|
||||
s -> showHiddenFile || !s.getName().startsWith(Const.DOT),
|
||||
@@ -65,6 +70,63 @@ public class SftpSession extends TerminalSession implements ISftpSession {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mkdir(String path) {
|
||||
path = Valid.checkNormalize(path);
|
||||
executor.makeDirectories(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touch(String path) {
|
||||
path = Valid.checkNormalize(path);
|
||||
executor.touch(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(String source, String target) {
|
||||
source = Valid.checkNormalize(source);
|
||||
executor.move(source, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(List<String> paths) {
|
||||
paths.stream()
|
||||
.map(Valid::checkNormalize)
|
||||
.forEach(executor::remove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void truncate(String path) {
|
||||
path = Valid.checkNormalize(path);
|
||||
executor.truncate(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chmod(String path, int mod) {
|
||||
path = Valid.checkNormalize(path);
|
||||
executor.changeMode(path, mod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent(String path) {
|
||||
path = Valid.checkNormalize(path);
|
||||
try (InputStream in = executor.openInputStream(path)) {
|
||||
return Streams.toString(in, config.getFileContentCharset());
|
||||
} catch (Exception e) {
|
||||
throw Exceptions.ioRuntime(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContent(String path, String content) {
|
||||
path = Valid.checkNormalize(path);
|
||||
try {
|
||||
executor.write(path, Strings.bytes(content, config.getFileContentCharset()));
|
||||
} catch (Exception e) {
|
||||
throw Exceptions.ioRuntime(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keepAlive() {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user