!112 feat: 机器管理支持ssh+rdp连接win服务器

* feat: rdp 文件管理
* feat: 机器管理支持ssh+rdp连接win服务器
This commit is contained in:
zongyangleo
2024-04-06 04:03:38 +00:00
committed by Coder慌
parent 38ff5152e0
commit 582d879a77
47 changed files with 17604 additions and 196 deletions

View File

@@ -6,6 +6,9 @@ import (
"fmt"
"io"
"io/fs"
"io/ioutil"
"mayfly-go/internal/machine/api/form"
"mayfly-go/internal/machine/config"
"mayfly-go/internal/machine/domain/entity"
"mayfly-go/internal/machine/domain/repository"
"mayfly-go/internal/machine/mcm"
@@ -13,7 +16,10 @@ import (
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/logx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/utils/bytex"
"mime/multipart"
"os"
"path/filepath"
"strings"
"github.com/pkg/sftp"
@@ -36,40 +42,44 @@ type MachineFile interface {
// 检查文件路径并返回机器id
GetMachineCli(fileId uint64, path ...string) (*mcm.Cli, error)
GetRdpFilePath(MachineId uint64, path string) string
/** sftp 相关操作 **/
// 创建目录
MkDir(fid uint64, path string) (*mcm.MachineInfo, error)
MkDir(fid uint64, path string, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error)
// 创建文件
CreateFile(fid uint64, path string) (*mcm.MachineInfo, error)
CreateFile(fid uint64, path string, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error)
// 读取目录
ReadDir(fid uint64, path string) ([]fs.FileInfo, error)
ReadDir(fid uint64, opForm *form.ServerFileOptionForm) ([]fs.FileInfo, error)
// 获取指定目录内容大小
GetDirSize(fid uint64, path string) (string, error)
GetDirSize(fid uint64, opForm *form.ServerFileOptionForm) (string, error)
// 获取文件stat
FileStat(fid uint64, path string) (string, error)
FileStat(opForm *form.ServerFileOptionForm) (string, error)
// 读取文件内容
ReadFile(fileId uint64, path string) (*sftp.File, *mcm.MachineInfo, error)
// 写文件
WriteFileContent(fileId uint64, path string, content []byte) (*mcm.MachineInfo, error)
WriteFileContent(fileId uint64, path string, content []byte, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error)
// 文件上传
UploadFile(fileId uint64, path, filename string, reader io.Reader) (*mcm.MachineInfo, error)
UploadFile(fileId uint64, path, filename string, reader io.Reader, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error)
UploadFiles(basePath string, fileHeaders []*multipart.FileHeader, paths []string, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error)
// 移除文件
RemoveFile(fileId uint64, path ...string) (*mcm.MachineInfo, error)
RemoveFile(opForm *form.MachineFileOpForm) (*mcm.MachineInfo, error)
Copy(fileId uint64, toPath string, paths ...string) (*mcm.MachineInfo, error)
Copy(opForm *form.MachineFileOpForm) (*mcm.MachineInfo, error)
Mv(fileId uint64, toPath string, paths ...string) (*mcm.MachineInfo, error)
Mv(opForm *form.MachineFileOpForm) (*mcm.MachineInfo, error)
Rename(fileId uint64, oldname string, newname string) (*mcm.MachineInfo, error)
Rename(renameForm *form.MachineFileRename) (*mcm.MachineInfo, error)
}
type machineFileAppImpl struct {
@@ -107,19 +117,49 @@ func (m *machineFileAppImpl) Save(ctx context.Context, mf *entity.MachineFile) e
return m.Insert(ctx, mf)
}
func (m *machineFileAppImpl) ReadDir(fid uint64, path string) ([]fs.FileInfo, error) {
if !strings.HasSuffix(path, "/") {
path = path + "/"
func (m *machineFileAppImpl) ReadDir(fid uint64, opForm *form.ServerFileOptionForm) ([]fs.FileInfo, error) {
if !strings.HasSuffix(opForm.Path, "/") {
opForm.Path = opForm.Path + "/"
}
_, sftpCli, err := m.GetMachineSftpCli(fid, path)
// 如果是rdp则直接读取本地文件
if opForm.Protocol == entity.MachineProtocolRdp {
opForm.Path = m.GetRdpFilePath(opForm.MachineId, opForm.Path)
return ioutil.ReadDir(opForm.Path)
}
_, sftpCli, err := m.GetMachineSftpCli(fid, opForm.Path)
if err != nil {
return nil, err
}
return sftpCli.ReadDir(path)
return sftpCli.ReadDir(opForm.Path)
}
func (m *machineFileAppImpl) GetDirSize(fid uint64, path string) (string, error) {
func (m *machineFileAppImpl) GetDirSize(fid uint64, opForm *form.ServerFileOptionForm) (string, error) {
path := opForm.Path
if opForm.Protocol == entity.MachineProtocolRdp {
dirPath := m.GetRdpFilePath(opForm.MachineId, path)
// 递归计算目录下文件大小
var totalSize int64
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
// 忽略目录本身
if path != dirPath {
totalSize += info.Size()
}
return nil
})
if err != nil {
return "", err
}
return bytex.FormatSize(totalSize), nil
}
mcli, err := m.GetMachineCli(fid, path)
if err != nil {
return "", err
@@ -144,19 +184,31 @@ func (m *machineFileAppImpl) GetDirSize(fid uint64, path string) (string, error)
return strings.Split(res, "\t")[0], nil
}
func (m *machineFileAppImpl) FileStat(fid uint64, path string) (string, error) {
mcli, err := m.GetMachineCli(fid, path)
func (m *machineFileAppImpl) FileStat(opForm *form.ServerFileOptionForm) (string, error) {
if opForm.Protocol == entity.MachineProtocolRdp {
path := m.GetRdpFilePath(opForm.MachineId, opForm.Path)
stat, err := os.Stat(path)
return fmt.Sprintf("%v", stat), err
}
mcli, err := m.GetMachineCli(opForm.FileId, opForm.Path)
if err != nil {
return "", err
}
return mcli.Run(fmt.Sprintf("stat -L %s", path))
return mcli.Run(fmt.Sprintf("stat -L %s", opForm.Path))
}
func (m *machineFileAppImpl) MkDir(fid uint64, path string) (*mcm.MachineInfo, error) {
func (m *machineFileAppImpl) MkDir(fid uint64, path string, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error) {
if !strings.HasSuffix(path, "/") {
path = path + "/"
}
if opForm.Protocol == entity.MachineProtocolRdp {
path = m.GetRdpFilePath(opForm.MachineId, path)
os.MkdirAll(path, os.ModePerm)
return nil, nil
}
mi, sftpCli, err := m.GetMachineSftpCli(fid, path)
if err != nil {
return nil, err
@@ -166,12 +218,19 @@ func (m *machineFileAppImpl) MkDir(fid uint64, path string) (*mcm.MachineInfo, e
return mi, err
}
func (m *machineFileAppImpl) CreateFile(fid uint64, path string) (*mcm.MachineInfo, error) {
func (m *machineFileAppImpl) CreateFile(fid uint64, path string, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error) {
mi, sftpCli, err := m.GetMachineSftpCli(fid, path)
if err != nil {
return nil, err
}
if opForm.Protocol == entity.MachineProtocolRdp {
path = m.GetRdpFilePath(opForm.MachineId, path)
file, err := os.Create(path)
defer file.Close()
return nil, err
}
file, err := sftpCli.Create(path)
if err != nil {
return nil, errorx.NewBiz("创建文件失败: %s", err.Error())
@@ -192,7 +251,19 @@ func (m *machineFileAppImpl) ReadFile(fileId uint64, path string) (*sftp.File, *
}
// 写文件内容
func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, content []byte) (*mcm.MachineInfo, error) {
func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, content []byte, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error) {
if opForm.Protocol == entity.MachineProtocolRdp {
path = m.GetRdpFilePath(opForm.MachineId, path)
file, err := os.Create(path)
defer file.Close()
if err != nil {
return nil, err
}
file.Write(content)
return nil, err
}
mi, sftpCli, err := m.GetMachineSftpCli(fileId, path)
if err != nil {
return nil, err
@@ -208,11 +279,22 @@ func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, conten
}
// 上传文件
func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, reader io.Reader) (*mcm.MachineInfo, error) {
func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, reader io.Reader, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error) {
if !strings.HasSuffix(path, "/") {
path = path + "/"
}
if opForm.Protocol == entity.MachineProtocolRdp {
path = m.GetRdpFilePath(opForm.MachineId, path)
file, err := os.Create(path + filename)
defer file.Close()
if err != nil {
return nil, err
}
io.Copy(file, reader)
return nil, nil
}
mi, sftpCli, err := m.GetMachineSftpCli(fileId, path)
if err != nil {
return nil, err
@@ -227,16 +309,63 @@ func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, re
return mi, err
}
func (m *machineFileAppImpl) UploadFiles(basePath string, fileHeaders []*multipart.FileHeader, paths []string, opForm *form.ServerFileOptionForm) (*mcm.MachineInfo, error) {
if opForm.Protocol == entity.MachineProtocolRdp {
baseFolder := m.GetRdpFilePath(opForm.MachineId, basePath)
for i, fileHeader := range fileHeaders {
file, err := fileHeader.Open()
if err != nil {
return nil, err
}
defer file.Close()
// 创建文件夹
rdpBaseDir := basePath
if !strings.HasSuffix(rdpBaseDir, "/") {
rdpBaseDir = rdpBaseDir + "/"
}
rdpDir := filepath.Dir(rdpBaseDir + paths[i])
m.MkDir(0, rdpDir, opForm)
// 创建文件
if !strings.HasSuffix(baseFolder, "/") {
baseFolder = baseFolder + "/"
}
fileAbsPath := baseFolder + paths[i]
createFile, err := os.Create(fileAbsPath)
if err != nil {
return nil, err
}
defer createFile.Close()
// 复制文件内容
io.Copy(createFile, file)
}
}
return nil, nil
}
// 删除文件
func (m *machineFileAppImpl) RemoveFile(fileId uint64, path ...string) (*mcm.MachineInfo, error) {
mcli, err := m.GetMachineCli(fileId, path...)
func (m *machineFileAppImpl) RemoveFile(opForm *form.MachineFileOpForm) (*mcm.MachineInfo, error) {
if opForm.Protocol == entity.MachineProtocolRdp {
for _, pt := range opForm.Path {
pt = m.GetRdpFilePath(opForm.MachineId, pt)
os.RemoveAll(pt)
}
return nil, nil
}
mcli, err := m.GetMachineCli(opForm.FileId, opForm.Path...)
if err != nil {
return nil, err
}
minfo := mcli.Info
// 优先使用命令删除速度快sftp需要递归遍历删除子文件等
res, err := mcli.Run(fmt.Sprintf("rm -rf %s", strings.Join(path, " ")))
res, err := mcli.Run(fmt.Sprintf("rm -rf %s", strings.Join(opForm.Path, " ")))
if err == nil {
return minfo, nil
}
@@ -247,7 +376,7 @@ func (m *machineFileAppImpl) RemoveFile(fileId uint64, path ...string) (*mcm.Mac
return minfo, err
}
for _, p := range path {
for _, p := range opForm.Path {
err = sftpCli.RemoveAll(p)
if err != nil {
break
@@ -256,36 +385,82 @@ func (m *machineFileAppImpl) RemoveFile(fileId uint64, path ...string) (*mcm.Mac
return minfo, err
}
func (m *machineFileAppImpl) Copy(fileId uint64, toPath string, paths ...string) (*mcm.MachineInfo, error) {
mcli, err := m.GetMachineCli(fileId, paths...)
func (m *machineFileAppImpl) Copy(opForm *form.MachineFileOpForm) (*mcm.MachineInfo, error) {
if opForm.Protocol == entity.MachineProtocolRdp {
for _, pt := range opForm.Path {
srcPath := m.GetRdpFilePath(opForm.MachineId, pt)
targetPath := m.GetRdpFilePath(opForm.MachineId, opForm.ToPath+pt)
// 打开源文件
srcFile, err := os.Open(srcPath)
if err != nil {
fmt.Println("Error opening source file:", err)
return nil, err
}
// 创建目标文件
destFile, err := os.Create(targetPath)
if err != nil {
fmt.Println("Error creating destination file:", err)
return nil, err
}
io.Copy(destFile, srcFile)
}
return nil, nil
}
mcli, err := m.GetMachineCli(opForm.FileId, opForm.Path...)
if err != nil {
return nil, err
}
mi := mcli.Info
res, err := mcli.Run(fmt.Sprintf("cp -r %s %s", strings.Join(paths, " "), toPath))
res, err := mcli.Run(fmt.Sprintf("cp -r %s %s", strings.Join(opForm.Path, " "), opForm.ToPath))
if err != nil {
return mi, errors.New(res)
}
return mi, err
}
func (m *machineFileAppImpl) Mv(fileId uint64, toPath string, paths ...string) (*mcm.MachineInfo, error) {
mcli, err := m.GetMachineCli(fileId, paths...)
func (m *machineFileAppImpl) Mv(opForm *form.MachineFileOpForm) (*mcm.MachineInfo, error) {
if opForm.Protocol == entity.MachineProtocolRdp {
for _, pt := range opForm.Path {
// 获取文件名
filename := filepath.Base(pt)
topath := opForm.ToPath
if !strings.HasSuffix(topath, "/") {
topath += "/"
}
srcPath := m.GetRdpFilePath(opForm.MachineId, pt)
targetPath := m.GetRdpFilePath(opForm.MachineId, topath+filename)
os.Rename(srcPath, targetPath)
}
return nil, nil
}
mcli, err := m.GetMachineCli(opForm.FileId, opForm.Path...)
if err != nil {
return nil, err
}
mi := mcli.Info
res, err := mcli.Run(fmt.Sprintf("mv %s %s", strings.Join(paths, " "), toPath))
res, err := mcli.Run(fmt.Sprintf("mv %s %s", strings.Join(opForm.Path, " "), opForm.ToPath))
if err != nil {
return mi, errorx.NewBiz(res)
}
return mi, err
}
func (m *machineFileAppImpl) Rename(fileId uint64, oldname string, newname string) (*mcm.MachineInfo, error) {
mi, sftpCli, err := m.GetMachineSftpCli(fileId, newname)
func (m *machineFileAppImpl) Rename(renameForm *form.MachineFileRename) (*mcm.MachineInfo, error) {
oldname := renameForm.Oldname
newname := renameForm.Newname
if renameForm.Protocol == entity.MachineProtocolRdp {
oldname = m.GetRdpFilePath(renameForm.MachineId, renameForm.Oldname)
newname = m.GetRdpFilePath(renameForm.MachineId, renameForm.Newname)
return nil, os.Rename(oldname, newname)
}
mi, sftpCli, err := m.GetMachineSftpCli(renameForm.FileId, newname)
if err != nil {
return nil, err
}
@@ -322,3 +497,7 @@ func (m *machineFileAppImpl) GetMachineSftpCli(fid uint64, inputPath ...string)
return mcli.Info, sftpCli, nil
}
func (m *machineFileAppImpl) GetRdpFilePath(MachineId uint64, path string) string {
return fmt.Sprintf("%s/%d%s", config.GetMachine().GuacdFilePath, MachineId, path)
}