fix(files): refactor upload mgr as upload info store
This commit is contained in:
parent
4e63a57cf9
commit
044cdea1d4
5 changed files with 131 additions and 10 deletions
|
@ -54,6 +54,12 @@ type IFileInfoStore interface {
|
||||||
SetSha1(itemPath, sign string) error
|
SetSha1(itemPath, sign string) error
|
||||||
GetInfos(itemPaths []string) (map[string]*FileInfo, error)
|
GetInfos(itemPaths []string) (map[string]*FileInfo, error)
|
||||||
GetSharingDir(hashID string) (string, error)
|
GetSharingDir(hashID string) (string, error)
|
||||||
|
// upload info
|
||||||
|
AddUploadInfo(user, filePath, tmpPath string, fileSize int64) error
|
||||||
|
SetUploadInfo(user, filePath string, newUploaded int64) error
|
||||||
|
GetUploadInfo(user, filePath string) (string, int64, int64, error)
|
||||||
|
DelUploadInfo(user, filePath string) error
|
||||||
|
ListUploadInfo(user string) ([]*UploadInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileInfoStore struct {
|
type FileInfoStore struct {
|
||||||
|
|
114
src/db/fileinfostore/upload_info_store.go
Normal file
114
src/db/fileinfostore/upload_info_store.go
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package fileinfostore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrCreateExisting = errors.New("create upload info which already exists")
|
||||||
|
ErrGreaterThanSize = errors.New("uploaded is greater than file size")
|
||||||
|
ErrUploadNotFound = errors.New("upload info not found")
|
||||||
|
|
||||||
|
uploadsPrefix = "uploads"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploadInfo struct {
|
||||||
|
RealFilePath string `json:"realFilePath"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Uploaded int64 `json:"uploaded"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func UploadNS(user string) string {
|
||||||
|
return fmt.Sprintf("%s/%s", uploadsPrefix, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *FileInfoStore) AddUploadInfo(user, filePath, tmpPath string, fileSize int64) error {
|
||||||
|
ns := UploadNS(user)
|
||||||
|
err := fi.store.AddNamespace(ns)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := fi.store.GetStringIn(ns, tmpPath)
|
||||||
|
if ok {
|
||||||
|
return ErrCreateExisting
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &UploadInfo{
|
||||||
|
RealFilePath: filePath,
|
||||||
|
Size: fileSize,
|
||||||
|
Uploaded: 0,
|
||||||
|
}
|
||||||
|
infoBytes, err := json.Marshal(info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fi.store.SetStringIn(ns, tmpPath, string(infoBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *FileInfoStore) SetUploadInfo(user, filePath string, newUploaded int64) error {
|
||||||
|
realFilePath, fileSize, _, err := fi.GetUploadInfo(user, filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if newUploaded > fileSize {
|
||||||
|
return ErrGreaterThanSize
|
||||||
|
}
|
||||||
|
|
||||||
|
newInfo := &UploadInfo{
|
||||||
|
RealFilePath: realFilePath,
|
||||||
|
Size: fileSize,
|
||||||
|
Uploaded: newUploaded,
|
||||||
|
}
|
||||||
|
newInfoBytes, err := json.Marshal(newInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fi.store.SetStringIn(UploadNS(user), filePath, string(newInfoBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *FileInfoStore) GetUploadInfo(user, filePath string) (string, int64, int64, error) {
|
||||||
|
ns := UploadNS(user)
|
||||||
|
infoBytes, ok := fi.store.GetStringIn(ns, filePath)
|
||||||
|
if !ok {
|
||||||
|
return "", 0, 0, ErrUploadNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
info := &UploadInfo{}
|
||||||
|
err := json.Unmarshal([]byte(infoBytes), info)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return info.RealFilePath, info.Size, info.Uploaded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *FileInfoStore) DelUploadInfo(user, filePath string) error {
|
||||||
|
return fi.store.DelInt64In(UploadNS(user), filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi *FileInfoStore) ListUploadInfo(user string) ([]*UploadInfo, error) {
|
||||||
|
ns := UploadNS(user)
|
||||||
|
if !fi.store.HasNamespace(ns) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
infoMap, err := fi.store.ListStringsIn(ns)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
infos := []*UploadInfo{}
|
||||||
|
for _, infoStr := range infoMap {
|
||||||
|
info := &UploadInfo{}
|
||||||
|
err = json.Unmarshal([]byte(infoStr), info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
infos = append(infos, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
return infos, nil
|
||||||
|
}
|
|
@ -434,7 +434,7 @@ func (h *FileHandlers) UploadChunk(c *gin.Context) {
|
||||||
locker.Exec(func() {
|
locker.Exec(func() {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
_, fileSize, uploaded, err := h.uploadMgr.GetInfo(userID, tmpFilePath)
|
_, fileSize, uploaded, err := h.deps.FileInfos().GetUploadInfo(userID, tmpFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -455,7 +455,7 @@ func (h *FileHandlers) UploadChunk(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.uploadMgr.SetInfo(userID, tmpFilePath, req.Offset+int64(wrote))
|
err = h.deps.FileInfos().SetUploadInfo(userID, tmpFilePath, req.Offset+int64(wrote))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -474,7 +474,7 @@ func (h *FileHandlers) UploadChunk(c *gin.Context) {
|
||||||
c.JSON(q.ErrResp(c, 500, fmt.Errorf("%s error: %w", req.Path, err)))
|
c.JSON(q.ErrResp(c, 500, fmt.Errorf("%s error: %w", req.Path, err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = h.uploadMgr.DelInfo(userID, tmpFilePath)
|
err = h.deps.FileInfos().DelUploadInfo(userID, tmpFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -594,7 +594,7 @@ func (h *FileHandlers) UploadStatus(c *gin.Context) {
|
||||||
tmpFilePath := q.UploadPath(userName, filePath)
|
tmpFilePath := q.UploadPath(userName, filePath)
|
||||||
locker := h.NewAutoLocker(c, lockName(tmpFilePath))
|
locker := h.NewAutoLocker(c, lockName(tmpFilePath))
|
||||||
locker.Exec(func() {
|
locker.Exec(func() {
|
||||||
_, fileSize, uploaded, err := h.uploadMgr.GetInfo(userID, tmpFilePath)
|
_, fileSize, uploaded, err := h.deps.FileInfos().GetUploadInfo(userID, tmpFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
c.JSON(q.ErrResp(c, 404, err))
|
c.JSON(q.ErrResp(c, 404, err))
|
||||||
|
@ -842,19 +842,19 @@ func lockName(filePath string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListUploadingsResp struct {
|
type ListUploadingsResp struct {
|
||||||
UploadInfos []*UploadInfo `json:"uploadInfos"`
|
UploadInfos []*fileinfostore.UploadInfo `json:"uploadInfos"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *FileHandlers) ListUploadings(c *gin.Context) {
|
func (h *FileHandlers) ListUploadings(c *gin.Context) {
|
||||||
userID := c.MustGet(q.UserIDParam).(string)
|
userID := c.MustGet(q.UserIDParam).(string)
|
||||||
|
|
||||||
infos, err := h.uploadMgr.ListInfo(userID)
|
infos, err := h.deps.FileInfos().ListUploadInfo(userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if infos == nil {
|
if infos == nil {
|
||||||
infos = []*UploadInfo{}
|
infos = []*fileinfostore.UploadInfo{}
|
||||||
}
|
}
|
||||||
c.JSON(200, &ListUploadingsResp{UploadInfos: infos})
|
c.JSON(200, &ListUploadingsResp{UploadInfos: infos})
|
||||||
}
|
}
|
||||||
|
@ -884,7 +884,7 @@ func (h *FileHandlers) DelUploading(c *gin.Context) {
|
||||||
tmpFilePath := q.UploadPath(userName, filePath)
|
tmpFilePath := q.UploadPath(userName, filePath)
|
||||||
locker := h.NewAutoLocker(c, lockName(tmpFilePath))
|
locker := h.NewAutoLocker(c, lockName(tmpFilePath))
|
||||||
locker.Exec(func() {
|
locker.Exec(func() {
|
||||||
_, size, _, err := h.uploadMgr.GetInfo(userID, tmpFilePath)
|
_, size, _, err := h.deps.FileInfos().GetUploadInfo(userID, tmpFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
@ -906,7 +906,7 @@ func (h *FileHandlers) DelUploading(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.uploadMgr.DelInfo(userID, tmpFilePath)
|
err = h.deps.FileInfos().DelUploadInfo(userID, tmpFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(q.ErrResp(c, 500, err))
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
return
|
return
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ihexxa/quickshare/src/client"
|
"github.com/ihexxa/quickshare/src/client"
|
||||||
|
"github.com/ihexxa/quickshare/src/db/fileinfostore"
|
||||||
q "github.com/ihexxa/quickshare/src/handlers"
|
q "github.com/ihexxa/quickshare/src/handlers"
|
||||||
"github.com/ihexxa/quickshare/src/handlers/fileshdr"
|
"github.com/ihexxa/quickshare/src/handlers/fileshdr"
|
||||||
)
|
)
|
||||||
|
@ -630,7 +631,7 @@ func TestFileHandlers(t *testing.T) {
|
||||||
t.Fatal(res.StatusCode)
|
t.Fatal(res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
gotInfos := map[string]*fileshdr.UploadInfo{}
|
gotInfos := map[string]*fileinfostore.UploadInfo{}
|
||||||
for _, info := range lResp.UploadInfos {
|
for _, info := range lResp.UploadInfos {
|
||||||
gotInfos[info.RealFilePath] = info
|
gotInfos[info.RealFilePath] = info
|
||||||
}
|
}
|
||||||
|
|
BIN
src/server/testdata/test_quickshare.db
vendored
BIN
src/server/testdata/test_quickshare.db
vendored
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue