Uploading file to storage asynchronously.

This commit is contained in:
2025-05-13 09:41:19 +08:00
parent 7be2d10472
commit 9ad96ec24d
2 changed files with 59 additions and 21 deletions

View File

@@ -3,6 +3,7 @@ package dao
import ( import (
"errors" "errors"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause"
"nysoure/server/model" "nysoure/server/model"
"time" "time"
) )
@@ -35,15 +36,22 @@ func GetUploadingFile(id uint) (*model.UploadingFile, error) {
} }
func UpdateUploadingBlock(id uint, blockIndex int) error { func UpdateUploadingBlock(id uint, blockIndex int) error {
return db.Transaction(func(tx *gorm.DB) error {
// 使用 FOR UPDATE 锁获取记录
uf := &model.UploadingFile{} uf := &model.UploadingFile{}
if err := db.Where("id = ?", id).First(uf).Error; err != nil { if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("id = ?", id).First(uf).Error; err != nil {
return err return err
} }
if blockIndex < 0 || blockIndex >= uf.BlocksCount() { if blockIndex < 0 || blockIndex >= uf.BlocksCount() {
return nil return nil
} }
uf.Blocks[blockIndex] = true uf.Blocks[blockIndex] = true
return db.Save(uf).Error
// 在事务中立即保存更改
return tx.Save(uf).Error
})
} }
func DeleteUploadingFile(id uint) error { func DeleteUploadingFile(id uint) error {
@@ -135,3 +143,18 @@ func UpdateFile(id uint, filename string, description string) (*model.File, erro
} }
return f, nil return f, nil
} }
func SetFileStorageKey(id uint, storageKey string) error {
f := &model.File{}
if err := db.Where("id = ?", id).First(f).Error; err != nil {
return err
}
f.StorageKey = storageKey
if err := db.Save(f).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return model.NewNotFoundError("file not found")
}
return err
}
return nil
}

View File

@@ -179,21 +179,19 @@ func FinishUploadingFile(uid uint, fid uint) (*model.FileView, error) {
return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload") return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload")
} }
defer func() {
_ = os.Remove(resultFilePath)
}()
for i := 0; i < uploadingFile.BlocksCount(); i++ { for i := 0; i < uploadingFile.BlocksCount(); i++ {
blockPath := filepath.Join(uploadingFile.TempPath, strconv.Itoa(i)) blockPath := filepath.Join(uploadingFile.TempPath, strconv.Itoa(i))
data, err := os.ReadFile(blockPath) data, err := os.ReadFile(blockPath)
if err != nil { if err != nil {
log.Error("failed to read block file: ", err) log.Error("failed to read block file: ", err)
_ = file.Close() _ = file.Close()
_ = os.Remove(resultFilePath)
return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload") return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload")
} }
if _, err := file.Write(data); err != nil { if _, err := file.Write(data); err != nil {
log.Error("failed to write result file: ", err) log.Error("failed to write result file: ", err)
_ = file.Close() _ = file.Close()
_ = os.Remove(resultFilePath)
return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload") return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload")
} }
} }
@@ -205,28 +203,41 @@ func FinishUploadingFile(uid uint, fid uint) (*model.FileView, error) {
s, err := dao.GetStorage(uploadingFile.TargetStorageID) s, err := dao.GetStorage(uploadingFile.TargetStorageID)
if err != nil { if err != nil {
log.Error("failed to get storage: ", err) log.Error("failed to get storage: ", err)
_ = os.Remove(resultFilePath)
return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload") return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload")
} }
iStorage := storage.NewStorage(s) iStorage := storage.NewStorage(s)
if iStorage == nil { if iStorage == nil {
log.Error("failed to find storage: ", err) log.Error("failed to find storage: ", err)
_ = os.Remove(resultFilePath)
return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload") return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload")
} }
storageKey, err := iStorage.Upload(resultFilePath) dbFile, err := dao.CreateFile(uploadingFile.Filename, uploadingFile.Description, uploadingFile.TargetResourceID, &uploadingFile.TargetStorageID, "", "")
if err != nil {
log.Error("failed to upload file: ", err)
return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload")
}
dbFile, err := dao.CreateFile(uploadingFile.Filename, uploadingFile.Description, uploadingFile.TargetResourceID, &uploadingFile.TargetStorageID, storageKey, "")
if err != nil { if err != nil {
log.Error("failed to create file in db: ", err) log.Error("failed to create file in db: ", err)
_ = iStorage.Delete(storageKey) _ = os.Remove(resultFilePath)
return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload") return nil, model.NewInternalServerError("failed to finish uploading file. please re-upload")
} }
go func() {
defer func() {
_ = os.Remove(resultFilePath)
}()
storageKey, err := iStorage.Upload(resultFilePath)
if err != nil {
log.Error("failed to upload file to storage: ", err)
} else {
err = dao.SetFileStorageKey(dbFile.ID, storageKey)
if err != nil {
_ = iStorage.Delete(storageKey)
_ = dao.DeleteFile(dbFile.ID)
log.Error("failed to set file storage key: ", err)
}
}
}()
return dbFile.ToView(), nil return dbFile.ToView(), nil
} }
@@ -367,6 +378,10 @@ func DownloadFile(fid uint) (string, string, error) {
return "", "", model.NewInternalServerError("failed to find storage") return "", "", model.NewInternalServerError("failed to find storage")
} }
if file.StorageKey == "" {
return "", "", model.NewRequestError("file is not available, please try again later")
}
path, err := iStorage.Download(file.StorageKey) path, err := iStorage.Download(file.StorageKey)
return path, file.Filename, err return path, file.Filename, err