Files
mayfly-go/server/internal/machine/application/machine_file.go

247 lines
7.2 KiB
Go
Raw Normal View History

package application
import (
"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"
"mayfly-go/internal/machine/infrastructure/machine"
"mayfly-go/pkg/biz"
"mayfly-go/pkg/model"
2021-05-08 20:50:34 +08:00
"os"
"strings"
"github.com/pkg/sftp"
)
type MachineFile interface {
// 分页获取机器文件信息列表
GetPageList(condition *entity.MachineFile, pageParam *model.PageParam, toEntity any, orderBy ...string) *model.PageResult[any]
// 根据条件获取
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
// 获取文件关联的机器信息,主要用于记录日志使用
GetMachine(fileId uint64) *machine.Info
2022-11-18 17:52:30 +08:00
2021-05-08 20:50:34 +08:00
/** sftp 相关操作 **/
// 创建目录
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
// 读取文件内容
ReadFile(fileId uint64, path string) *sftp.File
2021-05-08 20:50:34 +08:00
// 写文件
WriteFileContent(fileId uint64, path string, content []byte)
// 文件上传
UploadFile(fileId uint64, path, filename string, reader io.Reader)
2021-05-08 20:50:34 +08:00
// 移除文件
RemoveFile(fileId uint64, path string)
}
2022-09-09 18:26:08 +08:00
func newMachineFileApp(machineFileRepo repository.MachineFile, machineRepo repository.Machine) MachineFile {
return &machineFileAppImpl{machineRepo: machineRepo, machineFileRepo: machineFileRepo}
}
type machineFileAppImpl struct {
machineFileRepo repository.MachineFile
machineRepo repository.Machine
}
// 分页获取机器脚本信息列表
func (m *machineFileAppImpl) GetPageList(condition *entity.MachineFile, pageParam *model.PageParam, toEntity any, orderBy ...string) *model.PageResult[any] {
return m.machineFileRepo.GetPageList(condition, pageParam, toEntity, orderBy...)
}
// 根据条件获取
func (m *machineFileAppImpl) GetMachineFile(condition *entity.MachineFile, cols ...string) error {
return m.machineFileRepo.GetMachineFile(condition, cols...)
}
// 根据id获取
func (m *machineFileAppImpl) GetById(id uint64, cols ...string) *entity.MachineFile {
return m.machineFileRepo.GetById(id, cols...)
}
2021-05-08 20:50:34 +08:00
// 保存机器文件配置
func (m *machineFileAppImpl) Save(entity *entity.MachineFile) {
biz.NotNil(m.machineRepo.GetById(entity.MachineId, "Name"), "该机器不存在")
if entity.Id != 0 {
m.machineFileRepo.UpdateById(entity)
} else {
m.machineFileRepo.Create(entity)
}
}
// 根据id删除
func (m *machineFileAppImpl) Delete(id uint64) {
m.machineFileRepo.Delete(id)
}
2021-05-08 20:50:34 +08:00
func (m *machineFileAppImpl) ReadDir(fid uint64, path string) []fs.FileInfo {
2021-05-08 20:50:34 +08:00
path, machineId := m.checkAndReturnPathMid(fid, path)
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 {
_, machineId := m.checkAndReturnPathMid(fid, path)
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 {
_, machineId := m.checkAndReturnPathMid(fid, path)
res, err := GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("stat -L %s", path))
biz.ErrIsNil(err, res)
return res
}
func (m *machineFileAppImpl) MkDir(fid uint64, path string) {
path, machineId := m.checkAndReturnPathMid(fid, path)
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) {
path, machineId := m.checkAndReturnPathMid(fid, path)
sftpCli := m.getSftpCli(machineId)
file, err := sftpCli.Create(path)
biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
defer file.Close()
}
func (m *machineFileAppImpl) ReadFile(fileId uint64, path string) *sftp.File {
2021-05-08 20:50:34 +08:00
path, machineId := m.checkAndReturnPathMid(fileId, path)
sftpCli := m.getSftpCli(machineId)
// 读取文件内容
fc, err := sftpCli.Open(path)
biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
return fc
2021-05-08 20:50:34 +08:00
}
// 写文件内容
func (m *machineFileAppImpl) WriteFileContent(fileId uint64, path string, content []byte) {
2021-05-08 20:50:34 +08:00
_, machineId := m.checkAndReturnPathMid(fileId, path)
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)
}
// 上传文件
func (m *machineFileAppImpl) UploadFile(fileId uint64, path, filename string, reader io.Reader) {
2021-05-08 20:50:34 +08:00
path, machineId := m.checkAndReturnPathMid(fileId, path)
if !strings.HasSuffix(path, "/") {
path = path + "/"
}
sftpCli := m.getSftpCli(machineId)
createfile, err := sftpCli.Create(path + filename)
biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
defer createfile.Close()
io.Copy(createfile, reader)
2021-05-08 20:50:34 +08:00
}
// 删除文件
func (m *machineFileAppImpl) RemoveFile(fileId uint64, path string) {
2021-05-08 20:50:34 +08:00
path, machineId := m.checkAndReturnPathMid(fileId, path)
sftpCli := m.getSftpCli(machineId)
file, err := sftpCli.Open(path)
biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
2021-09-08 17:55:57 +08:00
fi, _ := file.Stat()
2021-05-08 20:50:34 +08:00
if fi.IsDir() {
err = sftpCli.RemoveDirectory(path)
// 如果文件夹有内容会删除失败则使用rm -rf命令删除
if err != nil {
2022-09-09 18:26:08 +08:00
GetMachineApp().GetCli(machineId).Run(fmt.Sprintf("rm -rf %s", path))
err = nil
}
2021-05-08 20:50:34 +08:00
} else {
err = sftpCli.Remove(path)
}
biz.ErrIsNilAppendErr(err, "删除文件失败: %s")
}
// 获取sftp client
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
}
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
func (m *machineFileAppImpl) checkAndReturnPathMid(fid uint64, inputPath string) (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, "文件不存在")
if inputPath != "" {
// 接口传入的地址需为配置路径的子路径
biz.IsTrue(strings.HasPrefix(inputPath, mf.Path), "无权访问该目录或文件")
return inputPath, mf.MachineId
} else {
return mf.Path, mf.MachineId
}
}