From 9f863819d8d1cec94a90f91b6c3fe2de4f334f96 Mon Sep 17 00:00:00 2001 From: keven1024 <99848979+keven1024@users.noreply.github.com> Date: Wed, 30 Apr 2025 12:29:06 +0800 Subject: [PATCH] refactor(backend): enhance file upload logic by merging file slices and improving Redis file info handling --- backend/go.mod | 1 + backend/go.sum | 3 +++ backend/internal/controllers/file.go | 19 ++++++++++++----- backend/internal/models/file.go | 14 +++++++++++++ backend/internal/services/file.go | 31 ++++++---------------------- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/backend/go.mod b/backend/go.mod index 107926b..52bcab9 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -3,6 +3,7 @@ module backend go 1.23.1 require ( + dario.cat/mergo v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gofrs/uuid v4.0.0+incompatible // indirect diff --git a/backend/go.sum b/backend/go.sum index 1b4f7a2..fa55471 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -69,3 +71,4 @@ golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/internal/controllers/file.go b/backend/internal/controllers/file.go index d6c6b17..d3276ec 100644 --- a/backend/internal/controllers/file.go +++ b/backend/internal/controllers/file.go @@ -4,9 +4,11 @@ import ( "backend/internal/models" "backend/internal/services" "backend/internal/utils" - "encoding/json" "errors" + "fmt" "mime/multipart" + "os" + "path/filepath" "time" "github.com/labstack/echo/v4" @@ -22,7 +24,6 @@ func CreateUploadTask(c echo.Context) error { if r.FileSize == 0 || r.MimeType == "" || r.FileHash == "" { return utils.HTTPErrorHandler(c, errors.New("上传文件信息不完整")) } - rdb, ctx := utils.GetRedisClient() fileId := utils.GetFileId(r.FileHash, r.FileSize) fileInfo, _ := models.GetRedisFileInfo(fileId) @@ -47,8 +48,10 @@ func CreateUploadTask(c echo.Context) error { CreatedAt: time.Now().Unix(), Expire: 3600, } - jsonData, _ := json.Marshal(newFileInfo) - rdb.HSet(ctx, "015:fileInfoMap", fileId, string(jsonData)).Result() + err := models.SetRedisFileInfo(fileId, newFileInfo) + if err != nil { + return utils.HTTPErrorHandler(c, err) + } return utils.HTTPSuccessHandler(c, map[string]any{ "size": newFileInfo.FileSize, @@ -119,8 +122,14 @@ func FinishUploadTask(c echo.Context) error { if fileInfo.FileType != models.FileTypeInit { return utils.HTTPErrorHandler(c, errors.New("上传任务状态错误")) } + // 合并文件切片 - if err := services.MergeFileSlices(r.FileId); err != nil { + uploadPath, _ := services.GetUploadDirPath() + slicesPath := filepath.Join(uploadPath, fmt.Sprintf("%s_%s", r.FileId, "tmp")) + + // 最终合并后的文件路径 + mergeFilePath := filepath.Join(uploadPath, r.FileId) + if err := services.MergeFileSlices(slicesPath, mergeFilePath); err != nil { return utils.HTTPErrorHandler(c, err) } diff --git a/backend/internal/models/file.go b/backend/internal/models/file.go index b917437..aae3b67 100644 --- a/backend/internal/models/file.go +++ b/backend/internal/models/file.go @@ -4,6 +4,8 @@ import ( "backend/internal/utils" "encoding/json" "errors" + + "dario.cat/mergo" ) type FileInfo struct { @@ -46,3 +48,15 @@ func GetRedisFileInfo(fileId string) (RedisFileInfo, error) { } return RedisFileInfo{}, errors.New("db不存在该文件信息") } + +func SetRedisFileInfo(fileId string, fileInfo RedisFileInfo) error { + rdb, ctx := utils.GetRedisClient() + old_fileInfo, err := GetRedisFileInfo(fileId) + if err != nil { + return err + } + mergo.Merge(&fileInfo, old_fileInfo) + jsonData, _ := json.Marshal(fileInfo) + _, err = rdb.HSet(ctx, "015:fileInfoMap", fileId, string(jsonData)).Result() + return err +} diff --git a/backend/internal/services/file.go b/backend/internal/services/file.go index 3dc4ea5..3c7aca7 100644 --- a/backend/internal/services/file.go +++ b/backend/internal/services/file.go @@ -26,7 +26,7 @@ func CreateFileSlice(fileSlice io.Reader, fileId string, fileIndex int64) error return err } - filePath := filepath.Join(uploadPath, fmt.Sprintf("%s_%s", fileId, "_tmp")) + filePath := filepath.Join(uploadPath, fmt.Sprintf("%s_%s", fileId, "tmp")) if err := os.MkdirAll(filePath, 0755); err != nil { return err } @@ -45,28 +45,16 @@ func CreateFileSlice(fileSlice io.Reader, fileId string, fileIndex int64) error } // MergeFileSlices 合并文件切片 -func MergeFileSlices(fileId string) error { - // 获取上传目录路径 - uploadPath, err := GetUploadDirPath() - if err != nil { - return err - } - - // 切片所在目录 - slicePath := filepath.Join(uploadPath, fileId) - - // 最终合并后的文件路径 - finalPath := filepath.Join(uploadPath, fileId+".tmp") - +func MergeFileSlices(slicesPath string, mergeFilePath string) error { // 创建最终文件 - destFile, err := os.Create(finalPath) + destFile, err := os.Create(mergeFilePath) if err != nil { return fmt.Errorf("创建合并文件失败: %v", err) } defer destFile.Close() // 读取目录下的所有文件 - files, err := os.ReadDir(slicePath) + files, err := os.ReadDir(slicesPath) if err != nil { return fmt.Errorf("读取切片目录失败: %v", err) } @@ -78,7 +66,7 @@ func MergeFileSlices(fileId string) error { if err != nil { return fmt.Errorf("无效的切片文件名: %v", err) } - sliceFiles[index-1] = filepath.Join(slicePath, file.Name()) + sliceFiles[index-1] = filepath.Join(slicesPath, file.Name()) } // 合并文件 @@ -107,13 +95,6 @@ func MergeFileSlices(fileId string) error { sf.Close() } - - // 清理切片文件夹 - defer os.RemoveAll(slicePath) - - // 重命名临时文件 - finalFilePath := filepath.Join(uploadPath, fileId) - defer os.Rename(finalPath, finalFilePath) - + defer os.RemoveAll(slicesPath) return nil }