2021-05-08 18:00:33 +08:00
|
|
|
|
package application
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2022-07-04 20:21:24 +08:00
|
|
|
|
"fmt"
|
2021-05-08 20:50:34 +08:00
|
|
|
|
"io"
|
|
|
|
|
|
"io/fs"
|
2022-09-09 18:26:08 +08:00
|
|
|
|
"mayfly-go/internal/machine/domain/entity"
|
|
|
|
|
|
"mayfly-go/internal/machine/domain/repository"
|
2023-03-06 16:59:57 +08:00
|
|
|
|
"mayfly-go/internal/machine/infrastructure/machine"
|
2022-06-02 17:41:11 +08:00
|
|
|
|
"mayfly-go/pkg/biz"
|
2023-09-07 16:33:53 +08:00
|
|
|
|
"mayfly-go/pkg/logx"
|
2022-06-02 17:41:11 +08:00
|
|
|
|
"mayfly-go/pkg/model"
|
2021-05-08 20:50:34 +08:00
|
|
|
|
"os"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/pkg/sftp"
|
2021-05-08 18:00:33 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
type MachineFile interface {
|
2021-05-08 18:00:33 +08:00
|
|
|
|
// 分页获取机器文件信息列表
|
2023-07-01 14:34:42 +08:00
|
|
|
|
GetPageList(condition *entity.MachineFile, pageParam *model.PageParam, toEntity any, orderBy ...string) *model.PageResult[any]
|
2021-05-08 18:00:33 +08:00
|
|
|
|
|
|
|
|
|
|
// 根据条件获取
|
|
|
|
|
|
GetMachineFile(condition *entity.MachineFile, cols ...string) error
|
|
|
|
|
|
|
|
|
|
|
|
// 根据id获取
|
|
|
|
|
|
GetById(id uint64, cols ...string) *entity.MachineFile
|
|
|
|
|
|
|
|
|
|
|
|
Save(entity *entity.MachineFile)
|
|
|
|
|
|
|
|
|
|
|
|
Delete(id uint64)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
|
2022-11-18 17:52:30 +08:00
|
|
|
|
// 获取文件关联的机器信息,主要用于记录日志使用
|
2023-03-06 16:59:57 +08:00
|
|
|
|
GetMachine(fileId uint64) *machine.Info
|
2022-11-18 17:52:30 +08:00
|
|
|
|
|
2021-05-08 20:50:34 +08:00
|
|
|
|
/** sftp 相关操作 **/
|
|
|
|
|
|
|
2022-07-04 20:21:24 +08:00
|
|
|
|
// 创建目录
|
|
|
|
|
|
MkDir(fid uint64, path string)
|
|
|
|
|
|
|
|
|
|
|
|
// 创建文件
|
|
|
|
|
|
CreateFile(fid uint64, path string)
|
|
|
|
|
|
|
2021-05-08 20:50:34 +08:00
|
|
|
|
// 读取目录
|
|
|
|
|
|
ReadDir(fid uint64, path string) []fs.FileInfo
|
|
|
|
|
|
|
2023-07-05 00:26:00 +08:00
|
|
|
|
// 获取指定目录内容大小
|
|
|
|
|
|
GetDirSize(fid uint64, path string) string
|
|
|
|
|
|
|
|
|
|
|
|
// 获取文件stat
|
|
|
|
|
|
FileStat(fid uint64, path string) string
|
|
|
|
|
|
|
2021-05-08 20:50:34 +08:00
|
|
|
|
// 读取文件内容
|
2022-01-28 11:30:11 +08:00
|
|
|
|
ReadFile(fileId uint64, path string) *sftp.File
|
2021-05-08 20:50:34 +08:00
|
|
|
|
|
|
|
|
|
|
// 写文件
|
|
|
|
|
|
WriteFileContent(fileId uint64, path string, content []byte)
|
|
|
|
|
|
|
|
|
|
|
|
// 文件上传
|
2022-01-28 11:30:11 +08:00
|
|
|
|
UploadFile(fileId uint64, path, filename string, reader io.Reader)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
|
|
|
|
|
|
// 移除文件
|
2023-09-07 16:33:53 +08:00
|
|
|
|
RemoveFile(fileId uint64, path ...string)
|
|
|
|
|
|
|
|
|
|
|
|
Copy(fileId uint64, toPath string, paths ...string) *machine.Info
|
|
|
|
|
|
|
|
|
|
|
|
Mv(fileId uint64, toPath string, paths ...string) *machine.Info
|
|
|
|
|
|
|
|
|
|
|
|
Rename(fileId uint64, oldname string, newname string) error
|
2021-05-08 18:00:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-09 18:26:08 +08:00
|
|
|
|
func newMachineFileApp(machineFileRepo repository.MachineFile, machineRepo repository.Machine) MachineFile {
|
|
|
|
|
|
return &machineFileAppImpl{machineRepo: machineRepo, machineFileRepo: machineFileRepo}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
type machineFileAppImpl struct {
|
2021-05-08 18:00:33 +08:00
|
|
|
|
machineFileRepo repository.MachineFile
|
|
|
|
|
|
machineRepo repository.Machine
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 分页获取机器脚本信息列表
|
2023-07-01 14:34:42 +08:00
|
|
|
|
func (m *machineFileAppImpl) GetPageList(condition *entity.MachineFile, pageParam *model.PageParam, toEntity any, orderBy ...string) *model.PageResult[any] {
|
2021-05-08 18:00:33 +08:00
|
|
|
|
return m.machineFileRepo.GetPageList(condition, pageParam, toEntity, orderBy...)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据条件获取
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (m *machineFileAppImpl) GetMachineFile(condition *entity.MachineFile, cols ...string) error {
|
2021-05-08 18:00:33 +08:00
|
|
|
|
return m.machineFileRepo.GetMachineFile(condition, cols...)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据id获取
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (m *machineFileAppImpl) GetById(id uint64, cols ...string) *entity.MachineFile {
|
2021-05-08 18:00:33 +08:00
|
|
|
|
return m.machineFileRepo.GetById(id, cols...)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-08 20:50:34 +08:00
|
|
|
|
// 保存机器文件配置
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (m *machineFileAppImpl) Save(entity *entity.MachineFile) {
|
2021-06-07 17:22:07 +08:00
|
|
|
|
biz.NotNil(m.machineRepo.GetById(entity.MachineId, "Name"), "该机器不存在")
|
2021-05-08 18:00:33 +08:00
|
|
|
|
|
|
|
|
|
|
if entity.Id != 0 {
|
2023-09-02 17:24:18 +08:00
|
|
|
|
m.machineFileRepo.UpdateById(entity)
|
2021-05-08 18:00:33 +08:00
|
|
|
|
} else {
|
2023-09-02 17:24:18 +08:00
|
|
|
|
m.machineFileRepo.Create(entity)
|
2021-05-08 18:00:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据id删除
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (m *machineFileAppImpl) Delete(id uint64) {
|
2021-05-08 18:00:33 +08:00
|
|
|
|
m.machineFileRepo.Delete(id)
|
|
|
|
|
|
}
|
2021-05-08 20:50:34 +08:00
|
|
|
|
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (m *machineFileAppImpl) ReadDir(fid uint64, path string) []fs.FileInfo {
|
2023-09-07 16:33:53 +08:00
|
|
|
|
machineId := m.checkAndReturnMid(fid, path)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
if !strings.HasSuffix(path, "/") {
|
|
|
|
|
|
path = path + "/"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sftpCli := m.getSftpCli(machineId)
|
|
|
|
|
|
fis, err := sftpCli.ReadDir(path)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "读取目录失败: %s")
|
|
|
|
|
|
return fis
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-05 00:26:00 +08:00
|
|
|
|
func (m *machineFileAppImpl) GetDirSize(fid uint64, path string) string {
|
2023-09-07 16:33:53 +08:00
|
|
|
|
machineId := m.checkAndReturnMid(fid, path)
|
2023-07-05 00:26:00 +08:00
|
|
|
|
res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("du -sh %s", path))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
// 若存在目录为空,则可能会返回如下内容。最后一行即为真正目录内容所占磁盘空间大小
|
|
|
|
|
|
//du: cannot access ‘/proc/19087/fd/3’: No such file or directory\n
|
|
|
|
|
|
//du: cannot access ‘/proc/19087/fdinfo/3’: No such file or directory\n
|
|
|
|
|
|
//18G /\n
|
|
|
|
|
|
if res == "" {
|
|
|
|
|
|
panic(biz.NewBizErr(fmt.Sprintf("获取目录大小失败: %s", err.Error())))
|
|
|
|
|
|
}
|
|
|
|
|
|
strs := strings.Split(res, "\n")
|
|
|
|
|
|
res = strs[len(strs)-2]
|
|
|
|
|
|
|
|
|
|
|
|
if !strings.Contains(res, "\t") {
|
|
|
|
|
|
panic(biz.NewBizErr(res))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 返回 32K\t/tmp\n
|
|
|
|
|
|
return strings.Split(res, "\t")[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *machineFileAppImpl) FileStat(fid uint64, path string) string {
|
2023-09-07 16:33:53 +08:00
|
|
|
|
machineId := m.checkAndReturnMid(fid, path)
|
2023-07-05 00:26:00 +08:00
|
|
|
|
res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("stat -L %s", path))
|
|
|
|
|
|
biz.ErrIsNil(err, res)
|
|
|
|
|
|
return res
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-07-04 20:21:24 +08:00
|
|
|
|
func (m *machineFileAppImpl) MkDir(fid uint64, path string) {
|
2023-09-07 16:33:53 +08:00
|
|
|
|
machineId := m.checkAndReturnMid(fid, path)
|
2022-07-04 20:21:24 +08:00
|
|
|
|
if !strings.HasSuffix(path, "/") {
|
|
|
|
|
|
path = path + "/"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sftpCli := m.getSftpCli(machineId)
|
|
|
|
|
|
err := sftpCli.Mkdir(path)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "创建目录失败: %s")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *machineFileAppImpl) CreateFile(fid uint64, path string) {
|
2023-09-07 16:33:53 +08:00
|
|
|
|
machineId := m.checkAndReturnMid(fid, path)
|
2022-07-04 20:21:24 +08:00
|
|
|
|
sftpCli := m.getSftpCli(machineId)
|
|
|
|
|
|
file, err := sftpCli.Create(path)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
|
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-28 11:30:11 +08:00
|
|
|
|
func (m *machineFileAppImpl) ReadFile(fileId uint64, path string) *sftp.File {
|
2023-09-07 16:33:53 +08:00
|
|
|
|
machineId := m.checkAndReturnMid(fileId, path)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
sftpCli := m.getSftpCli(machineId)
|
|
|
|
|
|
// 读取文件内容
|
|
|
|
|
|
fc, err := sftpCli.Open(path)
|
2022-01-28 11:30:11 +08:00
|
|
|
|
biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
|
|
|
|
|
|
return fc
|
2021-05-08 20:50:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 写文件内容
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, content []byte) {
|
2023-09-07 16:33:53 +08:00
|
|
|
|
machineId := m.checkAndReturnMid(fileId, path)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
|
|
|
|
|
|
sftpCli := m.getSftpCli(machineId)
|
|
|
|
|
|
f, err := sftpCli.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE|os.O_RDWR)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
|
|
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
|
|
|
|
fi, _ := f.Stat()
|
|
|
|
|
|
biz.IsTrue(!fi.IsDir(), "该路径不是文件")
|
|
|
|
|
|
f.Write(content)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 上传文件
|
2022-01-28 11:30:11 +08:00
|
|
|
|
func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, reader io.Reader) {
|
2023-09-07 16:33:53 +08:00
|
|
|
|
machineId := m.checkAndReturnMid(fileId, path)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
if !strings.HasSuffix(path, "/") {
|
|
|
|
|
|
path = path + "/"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sftpCli := m.getSftpCli(machineId)
|
|
|
|
|
|
createfile, err := sftpCli.Create(path + filename)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
|
|
|
|
|
|
defer createfile.Close()
|
|
|
|
|
|
|
2022-01-28 11:30:11 +08:00
|
|
|
|
io.Copy(createfile, reader)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除文件
|
2023-09-07 16:33:53 +08:00
|
|
|
|
func (m *machineFileAppImpl) RemoveFile(fileId uint64, path ...string) {
|
|
|
|
|
|
machineId := m.checkAndReturnMid(fileId, path...)
|
|
|
|
|
|
|
|
|
|
|
|
// 优先使用命令删除(速度快),sftp需要递归遍历删除子文件等
|
|
|
|
|
|
mcli := GetMachineApp().GetCli(machineId)
|
|
|
|
|
|
res, err := mcli.Run(fmt.Sprintf("rm -rf %s", strings.Join(path, " ")))
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
logx.Errorf("使用命令rm删除文件失败: %s", res)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
|
|
|
|
|
|
sftpCli := m.getSftpCli(machineId)
|
2023-09-07 16:33:53 +08:00
|
|
|
|
for _, p := range path {
|
|
|
|
|
|
err := sftpCli.RemoveAll(p)
|
|
|
|
|
|
biz.ErrIsNilAppendErr(err, "删除文件失败: %s")
|
2021-05-08 20:50:34 +08:00
|
|
|
|
}
|
2023-09-07 16:33:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *machineFileAppImpl) Copy(fileId uint64, toPath string, paths ...string) *machine.Info {
|
|
|
|
|
|
mid := m.checkAndReturnMid(fileId, paths...)
|
|
|
|
|
|
mcli := GetMachineApp().GetCli(mid)
|
|
|
|
|
|
res, err := mcli.Run(fmt.Sprintf("cp -r %s %s", strings.Join(paths, " "), toPath))
|
|
|
|
|
|
biz.ErrIsNil(err, "文件拷贝失败: %s", res)
|
|
|
|
|
|
return mcli.GetMachine()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *machineFileAppImpl) Mv(fileId uint64, toPath string, paths ...string) *machine.Info {
|
|
|
|
|
|
mid := m.checkAndReturnMid(fileId, paths...)
|
|
|
|
|
|
mcli := GetMachineApp().GetCli(mid)
|
|
|
|
|
|
res, err := mcli.Run(fmt.Sprintf("mv %s %s", strings.Join(paths, " "), toPath))
|
|
|
|
|
|
biz.ErrIsNil(err, "文件移动失败: %s", res)
|
|
|
|
|
|
return mcli.GetMachine()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *machineFileAppImpl) Rename(fileId uint64, oldname string, newname string) error {
|
|
|
|
|
|
mid := m.checkAndReturnMid(fileId, newname)
|
|
|
|
|
|
sftpCli := m.getSftpCli(mid)
|
|
|
|
|
|
return sftpCli.Rename(oldname, newname)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取sftp client
|
2021-07-28 18:03:19 +08:00
|
|
|
|
func (m *machineFileAppImpl) getSftpCli(machineId uint64) *sftp.Client {
|
2022-09-09 18:26:08 +08:00
|
|
|
|
return GetMachineApp().GetCli(machineId).GetSftpCli()
|
2021-05-08 20:50:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-06 16:59:57 +08:00
|
|
|
|
func (m *machineFileAppImpl) GetMachine(fileId uint64) *machine.Info {
|
2022-11-18 17:52:30 +08:00
|
|
|
|
return GetMachineApp().GetCli(m.GetById(fileId).MachineId).GetMachine()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-08 20:50:34 +08:00
|
|
|
|
// 校验并返回实际可访问的文件path
|
2023-09-07 16:33:53 +08:00
|
|
|
|
func (m *machineFileAppImpl) checkAndReturnMid(fid uint64, inputPath ...string) uint64 {
|
2021-05-08 20:50:34 +08:00
|
|
|
|
biz.IsTrue(fid != 0, "文件id不能为空")
|
2022-11-18 17:52:30 +08:00
|
|
|
|
mf := m.GetById(fid)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
biz.NotNil(mf, "文件不存在")
|
2023-09-07 16:33:53 +08:00
|
|
|
|
for _, path := range inputPath {
|
2021-05-08 20:50:34 +08:00
|
|
|
|
// 接口传入的地址需为配置路径的子路径
|
2023-09-07 16:33:53 +08:00
|
|
|
|
biz.IsTrue(strings.HasPrefix(path, mf.Path), "无权访问该目录或文件: %s", path)
|
2021-05-08 20:50:34 +08:00
|
|
|
|
}
|
2023-09-07 16:33:53 +08:00
|
|
|
|
return mf.MachineId
|
2021-05-08 20:50:34 +08:00
|
|
|
|
}
|