Files
be.ems/src/modules/common/controller/file.go

234 lines
6.3 KiB
Go

package controller
import (
"encoding/base64"
"fmt"
"net/url"
"path/filepath"
"strings"
"be.ems/src/framework/config"
"be.ems/src/framework/constants/uploadsubpath"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/vo/result"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
// 实例化控制层 FileController 结构体
var NewFile = &FileController{}
// 文件操作处理
//
// PATH /
type FileController struct{}
// 下载文件
//
// GET /download/:filePath
func (s *FileController) Download(c *gin.Context) {
language := ctx.AcceptLanguage(c)
filePath := c.Param("filePath")
if len(filePath) < 8 {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// base64解析出地址
decodedBytes, err := base64.StdEncoding.DecodeString(filePath)
if err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
return
}
routerPath := string(decodedBytes)
// 断点续传
headerRange := c.GetHeader("Range")
resultMap, err := file.ReadUploadFileStream(routerPath, headerRange)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
// 响应头
c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+url.QueryEscape(filepath.Base(routerPath))+`"`)
c.Writer.Header().Set("Accept-Ranges", "bytes")
c.Writer.Header().Set("Content-Type", "application/octet-stream")
if headerRange != "" {
c.Writer.Header().Set("Content-Range", fmt.Sprint(resultMap["range"]))
c.Writer.Header().Set("Content-Length", fmt.Sprint(resultMap["chunkSize"]))
c.Status(206)
} else {
c.Writer.Header().Set("Content-Length", fmt.Sprint(resultMap["fileSize"]))
c.Status(200)
}
c.Writer.Write(resultMap["data"].([]byte))
}
// 上传文件
//
// POST /upload
func (s *FileController) Upload(c *gin.Context) {
language := ctx.AcceptLanguage(c)
// 上传的文件
formFile, err := c.FormFile("file")
if err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 子路径
subPath := c.PostForm("subPath")
if _, ok := uploadsubpath.UploadSubpath[subPath]; !ok {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 上传文件转存
upFilePath, err := file.TransferUploadFile(formFile, subPath, nil)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
newFileName := upFilePath[strings.LastIndex(upFilePath, "/")+1:]
c.JSON(200, result.OkData(map[string]string{
"url": "//" + c.Request.Host + upFilePath,
"fileName": upFilePath,
"newFileName": newFileName,
"originalFileName": formFile.Filename,
}))
}
// 切片文件检查
//
// POST /chunkCheck
func (s *FileController) ChunkCheck(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body struct {
// 唯一标识
Identifier string `json:"identifier" binding:"required"`
// 文件名
FileName string `json:"fileName" binding:"required"`
}
err := c.ShouldBindJSON(&body)
if err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 读取标识目录
chunks, err := file.ChunkCheckFile(body.Identifier, body.FileName)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.JSON(200, result.OkData(chunks))
}
// 切片文件合并
//
// POST /chunkMerge
func (s *FileController) ChunkMerge(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body struct {
// 唯一标识
Identifier string `json:"identifier" binding:"required"`
// 文件名
FileName string `json:"fileName" binding:"required"`
// 子路径类型
SubPath string `json:"subPath" binding:"required"`
}
err := c.ShouldBindJSON(&body)
if err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
if _, ok := uploadsubpath.UploadSubpath[body.SubPath]; !ok {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 切片文件合并
mergeFilePath, err := file.ChunkMergeFile(body.Identifier, body.FileName, body.SubPath)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
newFileName := mergeFilePath[strings.LastIndex(mergeFilePath, "/")+1:]
c.JSON(200, result.OkData(map[string]string{
"url": "//" + c.Request.Host + mergeFilePath,
"fileName": mergeFilePath,
"newFileName": newFileName,
"originalFileName": body.FileName,
}))
}
// 切片文件上传
//
// POST /chunkUpload
func (s *FileController) ChunkUpload(c *gin.Context) {
language := ctx.AcceptLanguage(c)
// 切片编号
index := c.PostForm("index")
// 切片唯一标识
identifier := c.PostForm("identifier")
// 上传的文件
formFile, err := c.FormFile("file")
if index == "" || identifier == "" || err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 上传文件转存
chunkFilePath, err := file.TransferChunkUploadFile(formFile, index, identifier)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.JSON(206, result.OkData(chunkFilePath))
}
// 转存指定对应文件到静态目录
//
// POST /transferStaticFile
func (s *CommontController) TransferStaticFile(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body struct {
UploadPath string `json:"uploadPath" binding:"required"`
StaticPath string `json:"staticPath" binding:"required"`
Language string `json:"language" binding:"required"`
}
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 取语言前缀
lang := strings.SplitN(body.Language, "_", 2)[0]
// 默认静态资源
static := config.Get("staticFile.default").(map[string]any)
dir, err := filepath.Abs(static["dir"].(string))
if err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
return
}
delPrefix := strings.Replace(body.StaticPath, static["prefix"].(string), "", 1)
staticPath := strings.Replace(delPrefix, "{language}", lang, 1)
newFile := filepath.ToSlash(fmt.Sprintf("%s%s", dir, staticPath))
err = file.CopyUploadFile(body.UploadPath, newFile)
if err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
return
}
urlPath := strings.Replace(newFile, dir, static["prefix"].(string), 1)
c.JSON(200, result.OkData(filepath.ToSlash(urlPath)))
}