mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	
		
			
	
	
		
			222 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			222 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								package apis
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								import (
							 | 
						|||
| 
								 | 
							
									"fmt"
							 | 
						|||
| 
								 | 
							
									"io"
							 | 
						|||
| 
								 | 
							
									"io/fs"
							 | 
						|||
| 
								 | 
							
									"io/ioutil"
							 | 
						|||
| 
								 | 
							
									"mayfly-go/base/biz"
							 | 
						|||
| 
								 | 
							
									"mayfly-go/base/ctx"
							 | 
						|||
| 
								 | 
							
									"mayfly-go/base/ginx"
							 | 
						|||
| 
								 | 
							
									"mayfly-go/base/utils"
							 | 
						|||
| 
								 | 
							
									"mayfly-go/devops/apis/form"
							 | 
						|||
| 
								 | 
							
									"mayfly-go/devops/apis/vo"
							 | 
						|||
| 
								 | 
							
									"mayfly-go/devops/application"
							 | 
						|||
| 
								 | 
							
									"mayfly-go/devops/domain/entity"
							 | 
						|||
| 
								 | 
							
									"os"
							 | 
						|||
| 
								 | 
							
									"strconv"
							 | 
						|||
| 
								 | 
							
									"strings"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									"github.com/gin-gonic/gin"
							 | 
						|||
| 
								 | 
							
								)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								type MachineFile struct {
							 | 
						|||
| 
								 | 
							
									MachineFileApp application.IMachineFile
							 | 
						|||
| 
								 | 
							
									MachineApp     application.IMachine
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								const (
							 | 
						|||
| 
								 | 
							
									file          = "-"
							 | 
						|||
| 
								 | 
							
									dir           = "d"
							 | 
						|||
| 
								 | 
							
									link          = "l"
							 | 
						|||
| 
								 | 
							
									max_read_size = 5 * 1024 * 1024
							 | 
						|||
| 
								 | 
							
								)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) MachineFiles(rc *ctx.ReqCtx) {
							 | 
						|||
| 
								 | 
							
									g := rc.GinCtx
							 | 
						|||
| 
								 | 
							
									condition := &entity.MachineFile{MachineId: GetMachineId(g)}
							 | 
						|||
| 
								 | 
							
									rc.ResData = m.MachineFileApp.GetPageList(condition, ginx.GetPageParam(g), new([]vo.MachineFileVO))
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) SaveMachineFiles(rc *ctx.ReqCtx) {
							 | 
						|||
| 
								 | 
							
									g := rc.GinCtx
							 | 
						|||
| 
								 | 
							
									fileForm := new(form.MachineFileForm)
							 | 
						|||
| 
								 | 
							
									ginx.BindJsonAndValid(g, fileForm)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									entity := new(entity.MachineFile)
							 | 
						|||
| 
								 | 
							
									utils.Copy(entity, fileForm)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									biz.NotNil(m.MachineApp.GetById(entity.MachineId, "Id"), "机器不存在")
							 | 
						|||
| 
								 | 
							
									entity.SetBaseInfo(rc.LoginAccount)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									m.MachineFileApp.Save(entity)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) DeleteFile(rc *ctx.ReqCtx) {
							 | 
						|||
| 
								 | 
							
									g := rc.GinCtx
							 | 
						|||
| 
								 | 
							
									fid := GetMachineFileId(g)
							 | 
						|||
| 
								 | 
							
									m.MachineFileApp.Delete(fid)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/***      sftp相关操作      */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) ReadFileContent(rc *ctx.ReqCtx) {
							 | 
						|||
| 
								 | 
							
									g := rc.GinCtx
							 | 
						|||
| 
								 | 
							
									fid := GetMachineFileId(g)
							 | 
						|||
| 
								 | 
							
									machineId := GetMachineId(g)
							 | 
						|||
| 
								 | 
							
									readPath := g.Query("path")
							 | 
						|||
| 
								 | 
							
									readType := g.Query("type")
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									readPath = m.checkAndReturnPath(machineId, fid, readPath)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									sftpCli := m.MachineApp.GetCli(machineId).GetSftpCli()
							 | 
						|||
| 
								 | 
							
									// 读取文件内容
							 | 
						|||
| 
								 | 
							
									fc, err := sftpCli.Open(readPath)
							 | 
						|||
| 
								 | 
							
									biz.ErrIsNilAppendErr(err, "打开文件失败:%s")
							 | 
						|||
| 
								 | 
							
									defer fc.Close()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									fileInfo, _ := fc.Stat()
							 | 
						|||
| 
								 | 
							
									biz.IsTrue(!fileInfo.IsDir(), "该文件为目录")
							 | 
						|||
| 
								 | 
							
									// 如果是读取文件内容,则校验文件大小
							 | 
						|||
| 
								 | 
							
									if readType != "1" {
							 | 
						|||
| 
								 | 
							
										biz.IsTrue(fileInfo.Size() < max_read_size, "文件超过5m,请使用下载查看")
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									dataByte, err := ioutil.ReadAll(fc)
							 | 
						|||
| 
								 | 
							
									if err != nil && err != io.EOF {
							 | 
						|||
| 
								 | 
							
										panic(biz.NewBizErr("读取文件内容失败"))
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									rc.ReqParam = fmt.Sprintf("path: %s", readPath)
							 | 
						|||
| 
								 | 
							
									// 如果读取类型为下载,则下载文件,否则获取文件内容
							 | 
						|||
| 
								 | 
							
									if readType == "1" {
							 | 
						|||
| 
								 | 
							
										// 截取文件名,如/usr/local/test.java -》 test.java
							 | 
						|||
| 
								 | 
							
										path := strings.Split(readPath, "/")
							 | 
						|||
| 
								 | 
							
										rc.Download(dataByte, path[len(path)-1])
							 | 
						|||
| 
								 | 
							
									} else {
							 | 
						|||
| 
								 | 
							
										rc.ResData = string(dataByte)
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) GetDirEntry(rc *ctx.ReqCtx) {
							 | 
						|||
| 
								 | 
							
									g := rc.GinCtx
							 | 
						|||
| 
								 | 
							
									fid := GetMachineFileId(g)
							 | 
						|||
| 
								 | 
							
									machineId := GetMachineId(g)
							 | 
						|||
| 
								 | 
							
									readPath := g.Query("path")
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									readPath = m.checkAndReturnPath(machineId, fid, readPath)
							 | 
						|||
| 
								 | 
							
									if !strings.HasSuffix(readPath, "/") {
							 | 
						|||
| 
								 | 
							
										readPath = readPath + "/"
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									sftpCli := m.MachineApp.GetCli(machineId).GetSftpCli()
							 | 
						|||
| 
								 | 
							
									fis, err := sftpCli.ReadDir(readPath)
							 | 
						|||
| 
								 | 
							
									biz.ErrIsNilAppendErr(err, "读取目录失败: %s")
							 | 
						|||
| 
								 | 
							
									fisVO := make([]vo.MachineFileInfo, 0)
							 | 
						|||
| 
								 | 
							
									for _, fi := range fis {
							 | 
						|||
| 
								 | 
							
										fisVO = append(fisVO, vo.MachineFileInfo{
							 | 
						|||
| 
								 | 
							
											Name: fi.Name(),
							 | 
						|||
| 
								 | 
							
											Size: fi.Size(),
							 | 
						|||
| 
								 | 
							
											Path: readPath + fi.Name(),
							 | 
						|||
| 
								 | 
							
											Type: getFileType(fi.Mode()),
							 | 
						|||
| 
								 | 
							
										})
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									rc.ResData = fisVO
							 | 
						|||
| 
								 | 
							
									rc.ReqParam = fmt.Sprintf("path: %s", readPath)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) WriteFileContent(rc *ctx.ReqCtx) {
							 | 
						|||
| 
								 | 
							
									g := rc.GinCtx
							 | 
						|||
| 
								 | 
							
									fid := GetMachineFileId(g)
							 | 
						|||
| 
								 | 
							
									machineId := GetMachineId(g)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									form := new(form.MachineFileUpdateForm)
							 | 
						|||
| 
								 | 
							
									ginx.BindJsonAndValid(g, form)
							 | 
						|||
| 
								 | 
							
									path := form.Path
							 | 
						|||
| 
								 | 
							
									path = m.checkAndReturnPath(machineId, fid, path)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									sftpCli := m.MachineApp.GetCli(machineId).GetSftpCli()
							 | 
						|||
| 
								 | 
							
									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([]byte(form.Content))
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									rc.ReqParam = fmt.Sprintf("path: %s", path)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) UploadFile(rc *ctx.ReqCtx) {
							 | 
						|||
| 
								 | 
							
									g := rc.GinCtx
							 | 
						|||
| 
								 | 
							
									fid := GetMachineFileId(g)
							 | 
						|||
| 
								 | 
							
									mid := GetMachineId(g)
							 | 
						|||
| 
								 | 
							
									path := g.PostForm("path")
							 | 
						|||
| 
								 | 
							
									fileheader, err := g.FormFile("file")
							 | 
						|||
| 
								 | 
							
									biz.ErrIsNilAppendErr(err, "读取文件失败: %s")
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									path = m.checkAndReturnPath(mid, fid, path)
							 | 
						|||
| 
								 | 
							
									if !strings.HasSuffix(path, "/") {
							 | 
						|||
| 
								 | 
							
										path = path + "/"
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									sftpCli := m.MachineApp.GetCli(mid).GetSftpCli()
							 | 
						|||
| 
								 | 
							
									createfile, err := sftpCli.Create(path + fileheader.Filename)
							 | 
						|||
| 
								 | 
							
									biz.ErrIsNilAppendErr(err, "创建文件失败: %s")
							 | 
						|||
| 
								 | 
							
									defer createfile.Close()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									file, _ := fileheader.Open()
							 | 
						|||
| 
								 | 
							
									bytes, err := ioutil.ReadAll(file)
							 | 
						|||
| 
								 | 
							
									createfile.Write(bytes)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									rc.ReqParam = fmt.Sprintf("path: %s", path)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) RemoveFile(rc *ctx.ReqCtx) {
							 | 
						|||
| 
								 | 
							
									g := rc.GinCtx
							 | 
						|||
| 
								 | 
							
									fid := GetMachineFileId(g)
							 | 
						|||
| 
								 | 
							
									mid := GetMachineId(g)
							 | 
						|||
| 
								 | 
							
									path := g.Query("path")
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									path = m.checkAndReturnPath(mid, fid, path)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									sftpCli := m.MachineApp.GetCli(mid).GetSftpCli()
							 | 
						|||
| 
								 | 
							
									file, err := sftpCli.Open(path)
							 | 
						|||
| 
								 | 
							
									biz.ErrIsNilAppendErr(err, "打开文件失败: %s")
							 | 
						|||
| 
								 | 
							
									fi, err := file.Stat()
							 | 
						|||
| 
								 | 
							
									if fi.IsDir() {
							 | 
						|||
| 
								 | 
							
										err = sftpCli.RemoveDirectory(path)
							 | 
						|||
| 
								 | 
							
									} else {
							 | 
						|||
| 
								 | 
							
										err = sftpCli.Remove(path)
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									biz.ErrIsNilAppendErr(err, "删除文件失败: %s")
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									rc.ReqParam = fmt.Sprintf("path: %s", path)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 校验并返回实际可访问的文件path
							 | 
						|||
| 
								 | 
							
								func (m *MachineFile) checkAndReturnPath(mid, fid uint64, inputPath string) string {
							 | 
						|||
| 
								 | 
							
									biz.IsTrue(fid != 0, "文件id不能为空")
							 | 
						|||
| 
								 | 
							
									mf := m.MachineFileApp.GetById(uint64(fid))
							 | 
						|||
| 
								 | 
							
									biz.NotNil(mf, "文件不存在")
							 | 
						|||
| 
								 | 
							
									biz.IsEquals(mid, mf.MachineId, "机器id与文件id不匹配")
							 | 
						|||
| 
								 | 
							
									if inputPath != "" {
							 | 
						|||
| 
								 | 
							
										biz.IsTrue(strings.HasPrefix(inputPath, mf.Path), "无权访问该目录或文件")
							 | 
						|||
| 
								 | 
							
										return inputPath
							 | 
						|||
| 
								 | 
							
									} else {
							 | 
						|||
| 
								 | 
							
										return mf.Path
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func getFileType(fm fs.FileMode) string {
							 | 
						|||
| 
								 | 
							
									if fm.IsDir() {
							 | 
						|||
| 
								 | 
							
										return dir
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									return file
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								func GetMachineFileId(g *gin.Context) uint64 {
							 | 
						|||
| 
								 | 
							
									fileId, _ := strconv.Atoi(g.Param("fileId"))
							 | 
						|||
| 
								 | 
							
									biz.IsTrue(fileId != 0, "fileId错误")
							 | 
						|||
| 
								 | 
							
									return uint64(fileId)
							 | 
						|||
| 
								 | 
							
								}
							 |