mirror of
https://github.com/keven1024/015.git
synced 2026-05-26 07:08:02 +00:00
refactor(backend): enhance file upload handling by improving error management and restructuring CreateFileSlice and MergeFileSlices functions for better clarity
This commit is contained in:
@@ -5,10 +5,9 @@ import (
|
|||||||
"backend/internal/utils"
|
"backend/internal/utils"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"math"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"pkg/models"
|
"pkg/models"
|
||||||
u "pkg/utils"
|
u "pkg/utils"
|
||||||
"time"
|
"time"
|
||||||
@@ -28,9 +27,20 @@ func CreateUploadTask(c echo.Context) error {
|
|||||||
return utils.HTTPErrorHandler(c, errors.New("调用接口参数错误"))
|
return utils.HTTPErrorHandler(c, errors.New("调用接口参数错误"))
|
||||||
}
|
}
|
||||||
fileId := utils.GetFileId(r.FileHash, r.FileSize)
|
fileId := utils.GetFileId(r.FileHash, r.FileSize)
|
||||||
fileInfo, _ := models.GetRedisFileInfo(fileId)
|
fileInfo, err := models.GetRedisFileInfo(fileId)
|
||||||
|
if err != nil {
|
||||||
|
return utils.HTTPErrorHandler(c, err)
|
||||||
|
}
|
||||||
|
|
||||||
if fileInfo != nil {
|
if fileInfo != nil {
|
||||||
|
uploadPath, err := utils.GetUploadDirPath()
|
||||||
|
if err != nil {
|
||||||
|
return utils.HTTPErrorHandler(c, err)
|
||||||
|
}
|
||||||
|
sliceList, err := services.GetFileSliceList(fileId, uploadPath)
|
||||||
|
if err != nil {
|
||||||
|
return utils.HTTPErrorHandler(c, err)
|
||||||
|
}
|
||||||
return utils.HTTPSuccessHandler(c, map[string]any{
|
return utils.HTTPSuccessHandler(c, map[string]any{
|
||||||
"size": fileInfo.FileSize,
|
"size": fileInfo.FileSize,
|
||||||
"mime_type": fileInfo.MimeType,
|
"mime_type": fileInfo.MimeType,
|
||||||
@@ -39,6 +49,7 @@ func CreateUploadTask(c echo.Context) error {
|
|||||||
"expire": fileInfo.Expire,
|
"expire": fileInfo.Expire,
|
||||||
"id": fileId,
|
"id": fileId,
|
||||||
"chunk_size": fileInfo.ChunkSize,
|
"chunk_size": fileInfo.ChunkSize,
|
||||||
|
"chunks": sliceList,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
maxStorageSize, err := utils.GetFileSize(u.GetEnv("upload.maximum"))
|
maxStorageSize, err := utils.GetFileSize(u.GetEnv("upload.maximum"))
|
||||||
@@ -155,7 +166,7 @@ func UploadFileSlice(c echo.Context) error {
|
|||||||
return utils.HTTPErrorHandler(c, err)
|
return utils.HTTPErrorHandler(c, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := services.CreateFileSlice(file, uploadPath, r.FileId, r.FileIndex); err != nil {
|
if _, err := services.CreateFileSlice(r.FileId, uploadPath, file, r.FileIndex); err != nil {
|
||||||
return utils.HTTPErrorHandler(c, err)
|
return utils.HTTPErrorHandler(c, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,13 +203,23 @@ func FinishUploadTask(c echo.Context) error {
|
|||||||
return utils.HTTPErrorHandler(c, errors.New("上传任务已过期"))
|
return utils.HTTPErrorHandler(c, errors.New("上传任务已过期"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合并文件切片
|
uploadPath, err := utils.GetUploadDirPath()
|
||||||
uploadPath, _ := utils.GetUploadDirPath()
|
if err != nil {
|
||||||
slicesPath := filepath.Join(uploadPath, fmt.Sprintf("%s_%s", r.FileId, "tmp"))
|
return utils.HTTPErrorHandler(c, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSliceList, err := services.GetFileSliceList(r.FileId, uploadPath)
|
||||||
|
if err != nil {
|
||||||
|
return utils.HTTPErrorHandler(c, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fileSliceList) != int(math.Ceil(float64(fileInfo.FileSize)/float64(fileInfo.ChunkSize))) {
|
||||||
|
return utils.HTTPErrorHandler(c, errors.New("文件切片不完整"))
|
||||||
|
}
|
||||||
|
|
||||||
// 最终合并后的文件路径
|
// 最终合并后的文件路径
|
||||||
mergeFilePath := filepath.Join(uploadPath, r.FileId)
|
mergeFilePath, err := services.MergeFileSlices(r.FileId, uploadPath)
|
||||||
if err := services.MergeFileSlices(slicesPath, mergeFilePath); err != nil {
|
if err != nil {
|
||||||
return utils.HTTPErrorHandler(c, err)
|
return utils.HTTPErrorHandler(c, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,59 +5,71 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateFileSlice(fileSlice io.Reader, uploadPath string, fileId string, fileIndex int64) error {
|
func CreateFileSlice(fileId string, uploadPath string, fileSlice io.Reader, fileIndex int64) (string, error) {
|
||||||
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 {
|
if err := os.MkdirAll(filePath, 0755); err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
dst, err := os.Create(filepath.Join(filePath, fmt.Sprintf("%d", fileIndex)))
|
dst, err := os.Create(filepath.Join(filePath, fmt.Sprintf("%d", fileIndex)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
defer dst.Close()
|
defer dst.Close()
|
||||||
|
|
||||||
if _, err = io.Copy(dst, fileSlice); err != nil {
|
if _, err = io.Copy(dst, fileSlice); err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return filePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergeFileSlices 合并文件切片
|
func GetFileSliceList(fileId string, uploadPath string) ([]int, error) {
|
||||||
func MergeFileSlices(slicesPath string, mergeFilePath string) error {
|
slicesPath := filepath.Join(uploadPath, fmt.Sprintf("%s_%s", fileId, "tmp"))
|
||||||
// 创建最终文件
|
|
||||||
destFile, err := os.Create(mergeFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("创建合并文件失败: %v", err)
|
|
||||||
}
|
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
// 读取目录下的所有文件
|
|
||||||
files, err := os.ReadDir(slicesPath)
|
files, err := os.ReadDir(slicesPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("读取切片目录失败: %v", err)
|
return nil, fmt.Errorf("读取切片目录失败: %v", err)
|
||||||
}
|
}
|
||||||
|
fileSliceList := []int{}
|
||||||
// 按照索引排序文件切片
|
|
||||||
sliceFiles := make([]string, len(files))
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
index, err := strconv.Atoi(file.Name())
|
index, err := strconv.Atoi(file.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("无效的切片文件名: %v", err)
|
return nil, fmt.Errorf("无效的切片文件名: %v", err)
|
||||||
}
|
}
|
||||||
sliceFiles[index-1] = filepath.Join(slicesPath, file.Name())
|
fileSliceList = append(fileSliceList, index)
|
||||||
|
}
|
||||||
|
sort.Ints(fileSliceList)
|
||||||
|
return fileSliceList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeFileSlices 合并文件切片
|
||||||
|
func MergeFileSlices(fileId string, uploadPath string) (string, error) {
|
||||||
|
mergeFilePath := filepath.Join(uploadPath, fileId)
|
||||||
|
slicesPath := filepath.Join(uploadPath, fmt.Sprintf("%s_%s", fileId, "tmp"))
|
||||||
|
defer os.RemoveAll(slicesPath)
|
||||||
|
// 创建最终文件
|
||||||
|
destFile, err := os.Create(mergeFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("创建合并文件失败: %v", err)
|
||||||
|
}
|
||||||
|
defer destFile.Close()
|
||||||
|
|
||||||
|
fileSliceList, err := GetFileSliceList(fileId, uploadPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合并文件
|
// 合并文件
|
||||||
buffer := make([]byte, 4*1024*1024) // 4MB buffer
|
buffer := make([]byte, 4*1024*1024) // 4MB buffer
|
||||||
for _, sliceFile := range sliceFiles {
|
for _, index := range fileSliceList {
|
||||||
sf, err := os.Open(sliceFile)
|
sliceFilePath := filepath.Join(slicesPath, fmt.Sprintf("%d", index))
|
||||||
|
sf, err := os.Open(sliceFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("打开切片文件失败: %v", err)
|
return "", fmt.Errorf("打开切片文件失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -67,17 +79,15 @@ func MergeFileSlices(slicesPath string, mergeFilePath string) error {
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sf.Close()
|
sf.Close()
|
||||||
return fmt.Errorf("读取切片文件失败: %v", err)
|
return "", fmt.Errorf("读取切片文件失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := destFile.Write(buffer[:n]); err != nil {
|
if _, err := destFile.Write(buffer[:n]); err != nil {
|
||||||
sf.Close()
|
sf.Close()
|
||||||
return fmt.Errorf("写入合并文件失败: %v", err)
|
return "", fmt.Errorf("写入合并文件失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sf.Close()
|
sf.Close()
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(slicesPath)
|
return mergeFilePath, nil
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user