177 lines
5.9 KiB
Go
177 lines
5.9 KiB
Go
package example
|
|
|
|
import (
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"kra/internal/biz/example"
|
|
"kra/pkg/response"
|
|
"kra/pkg/utils"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// BreakpointContinue
|
|
// @Tags ExaFileUploadAndDownload
|
|
// @Summary 断点续传到服务器
|
|
// @Security ApiKeyAuth
|
|
// @accept multipart/form-data
|
|
// @Produce application/json
|
|
// @Param file formData file true "断点续传示例"
|
|
// @Success 200 {object} response.Response{msg=string} "断点续传到服务器"
|
|
// @Router /fileUploadAndDownload/breakpointContinue [post]
|
|
func (f *FileUploadApi) BreakpointContinue(c *gin.Context) {
|
|
fileMd5 := c.Request.FormValue("fileMd5")
|
|
fileName := c.Request.FormValue("fileName")
|
|
chunkMd5 := c.Request.FormValue("chunkMd5")
|
|
chunkNumber, _ := strconv.Atoi(c.Request.FormValue("chunkNumber"))
|
|
chunkTotal, _ := strconv.Atoi(c.Request.FormValue("chunkTotal"))
|
|
|
|
_, FileHeader, err := c.Request.FormFile("file")
|
|
if err != nil {
|
|
response.FailWithMessage("接收文件失败", c)
|
|
return
|
|
}
|
|
|
|
file, err := FileHeader.Open()
|
|
if err != nil {
|
|
response.FailWithMessage("文件读取失败", c)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
content, _ := io.ReadAll(file)
|
|
if !utils.CheckMd5(content, chunkMd5) {
|
|
response.FailWithMessage("检查md5失败", c)
|
|
return
|
|
}
|
|
|
|
exaFile, err := breakpointContinueUsecase.FindOrCreateFile(c.Request.Context(), fileMd5, fileName, chunkTotal)
|
|
if err != nil {
|
|
response.FailWithMessage("查找或创建记录失败: "+err.Error(), c)
|
|
return
|
|
}
|
|
|
|
pathC, err := utils.BreakPointContinue(content, fileName, chunkNumber, chunkTotal, fileMd5)
|
|
if err != nil {
|
|
response.FailWithMessage("断点续传失败: "+err.Error(), c)
|
|
return
|
|
}
|
|
|
|
if err = breakpointContinueUsecase.CreateFileChunk(c.Request.Context(), exaFile.ID, pathC, chunkNumber); err != nil {
|
|
response.FailWithMessage("创建文件记录失败: "+err.Error(), c)
|
|
return
|
|
}
|
|
|
|
response.OkWithMessage("切片创建成功", c)
|
|
}
|
|
|
|
// FindFile
|
|
// @Tags ExaFileUploadAndDownload
|
|
// @Summary 查找文件
|
|
// @Security ApiKeyAuth
|
|
// @accept multipart/form-data
|
|
// @Produce application/json
|
|
// @Param fileMd5 query string true "文件MD5"
|
|
// @Param fileName query string true "文件名"
|
|
// @Param chunkTotal query int true "切片总数"
|
|
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "查找文件,返回包括文件详情"
|
|
// @Router /fileUploadAndDownload/findFile [get]
|
|
func (f *FileUploadApi) FindFile(c *gin.Context) {
|
|
fileMd5 := c.Query("fileMd5")
|
|
fileName := c.Query("fileName")
|
|
chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal"))
|
|
|
|
file, err := breakpointContinueUsecase.FindOrCreateFile(c.Request.Context(), fileMd5, fileName, chunkTotal)
|
|
if err != nil {
|
|
response.FailWithMessage("查找失败: "+err.Error(), c)
|
|
return
|
|
}
|
|
|
|
response.OkWithDetailed(gin.H{"file": toFileResponse(file)}, "查找成功", c)
|
|
}
|
|
|
|
// BreakpointContinueFinish
|
|
// @Tags ExaFileUploadAndDownload
|
|
// @Summary 创建文件
|
|
// @Security ApiKeyAuth
|
|
// @accept multipart/form-data
|
|
// @Produce application/json
|
|
// @Param fileMd5 query string true "文件MD5"
|
|
// @Param fileName query string true "文件名"
|
|
// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "创建文件,返回包括文件路径"
|
|
// @Router /fileUploadAndDownload/findFile [post]
|
|
func (f *FileUploadApi) BreakpointContinueFinish(c *gin.Context) {
|
|
fileMd5 := c.Query("fileMd5")
|
|
fileName := c.Query("fileName")
|
|
|
|
filePath, err := utils.MakeFile(fileName, fileMd5)
|
|
if err != nil {
|
|
response.FailWithDetailed(gin.H{"filePath": filePath}, "文件创建失败", c)
|
|
return
|
|
}
|
|
|
|
response.OkWithDetailed(gin.H{"filePath": filePath}, "文件创建成功", c)
|
|
}
|
|
|
|
// RemoveChunk
|
|
// @Tags ExaFileUploadAndDownload
|
|
// @Summary 删除切片
|
|
// @Security ApiKeyAuth
|
|
// @accept application/json
|
|
// @Produce application/json
|
|
// @Param data body map[string]string true "删除缓存切片"
|
|
// @Success 200 {object} response.Response{msg=string} "删除切片"
|
|
// @Router /fileUploadAndDownload/removeChunk [post]
|
|
func (f *FileUploadApi) RemoveChunk(c *gin.Context) {
|
|
var req struct {
|
|
FileMd5 string `json:"fileMd5"`
|
|
FilePath string `json:"filePath"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.FailWithMessage(err.Error(), c)
|
|
return
|
|
}
|
|
|
|
// 路径穿越拦截
|
|
if strings.Contains(req.FilePath, "..") || strings.Contains(req.FilePath, "../") ||
|
|
strings.Contains(req.FilePath, "./") || strings.Contains(req.FilePath, ".\\") {
|
|
response.FailWithMessage("非法路径,禁止删除", c)
|
|
return
|
|
}
|
|
|
|
if err := utils.RemoveChunk(req.FileMd5); err != nil {
|
|
response.FailWithMessage("缓存切片删除失败: "+err.Error(), c)
|
|
return
|
|
}
|
|
|
|
if err := breakpointContinueUsecase.DeleteFileChunk(c.Request.Context(), req.FileMd5, req.FilePath); err != nil {
|
|
response.FailWithMessage(err.Error(), c)
|
|
return
|
|
}
|
|
|
|
response.OkWithMessage("缓存切片删除成功", c)
|
|
}
|
|
|
|
func toFileResponse(file *example.ExaFile) map[string]interface{} {
|
|
chunks := make([]map[string]interface{}, len(file.ExaFileChunk))
|
|
for i, chunk := range file.ExaFileChunk {
|
|
chunks[i] = map[string]interface{}{
|
|
"ID": chunk.ID,
|
|
"exaFileID": chunk.ExaFileID,
|
|
"fileChunkNumber": chunk.FileChunkNumber,
|
|
"fileChunkPath": chunk.FileChunkPath,
|
|
}
|
|
}
|
|
return map[string]interface{}{
|
|
"ID": file.ID,
|
|
"fileName": file.FileName,
|
|
"fileMd5": file.FileMd5,
|
|
"filePath": file.FilePath,
|
|
"chunkTotal": file.ChunkTotal,
|
|
"isFinish": file.IsFinish,
|
|
"exaFileChunk": chunks,
|
|
}
|
|
}
|