feat: optimize file operation interface (#2757)

* feat: optimize file operation interface

* chore: fix typo

Co-authored-by: Noah Hsu <i@nn.ci>
pull/2771/head
foxxorcat 2022-12-20 15:02:40 +08:00 committed by GitHub
parent e2bcca2fbd
commit 62a06fa0f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 330 additions and 121 deletions

View File

@ -9,7 +9,7 @@ import (
type Driver interface { type Driver interface {
Meta Meta
Reader Reader
Writer //Writer
//Other //Other
} }
@ -42,19 +42,66 @@ type Getter interface {
GetRoot(ctx context.Context) (model.Obj, error) GetRoot(ctx context.Context) (model.Obj, error)
} }
type Writer interface { //type Writer interface {
// MakeDir make a folder named `dirName` in `parentDir` // Mkdir
// Move
// Rename
// Copy
// Remove
// Put
//}
type Mkdir interface {
MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error
// Move `srcObject` to `dstDir` }
type Move interface {
Move(ctx context.Context, srcObj, dstDir model.Obj) error Move(ctx context.Context, srcObj, dstDir model.Obj) error
// Rename rename `srcObject` to `newName` }
type Rename interface {
Rename(ctx context.Context, srcObj model.Obj, newName string) error Rename(ctx context.Context, srcObj model.Obj, newName string) error
// Copy `srcObject` to `dstDir` }
type Copy interface {
Copy(ctx context.Context, srcObj, dstDir model.Obj) error Copy(ctx context.Context, srcObj, dstDir model.Obj) error
// Remove remove `object` }
type Remove interface {
Remove(ctx context.Context, obj model.Obj) error Remove(ctx context.Context, obj model.Obj) error
// Put upload `stream` to `parentDir` }
type Put interface {
Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up UpdateProgress) error Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up UpdateProgress) error
} }
//type WriteResult interface {
// MkdirResult
// MoveResult
// RenameResult
// CopyResult
// PutResult
// Remove
//}
type MkdirResult interface {
MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error)
}
type MoveResult interface {
Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error)
}
type RenameResult interface {
Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error)
}
type CopyResult interface {
Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error)
}
type PutResult interface {
Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up UpdateProgress) (model.Obj, error)
}
type UpdateProgress func(percentage int) type UpdateProgress func(percentage int)

View File

@ -21,7 +21,7 @@ var CopyTaskManager = task.NewTaskManager(3, func(tid *uint64) {
// Copy if in the same storage, call move method // Copy if in the same storage, call move method
// if not, add copy task // if not, add copy task
func _copy(ctx context.Context, srcObjPath, dstDirPath string) (bool, error) { func _copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (bool, error) {
srcStorage, srcObjActualPath, err := op.GetStorageAndActualPath(srcObjPath) srcStorage, srcObjActualPath, err := op.GetStorageAndActualPath(srcObjPath)
if err != nil { if err != nil {
return false, errors.WithMessage(err, "failed get src storage") return false, errors.WithMessage(err, "failed get src storage")
@ -32,7 +32,7 @@ func _copy(ctx context.Context, srcObjPath, dstDirPath string) (bool, error) {
} }
// copy if in the same storage, just call driver.Copy // copy if in the same storage, just call driver.Copy
if srcStorage.GetStorage() == dstStorage.GetStorage() { if srcStorage.GetStorage() == dstStorage.GetStorage() {
return false, op.Copy(ctx, srcStorage, srcObjActualPath, dstDirActualPath) return false, op.Copy(ctx, srcStorage, srcObjActualPath, dstDirActualPath, lazyCache...)
} }
// not in the same storage // not in the same storage
CopyTaskManager.Submit(task.WithCancelCtx(&task.Task[uint64]{ CopyTaskManager.Submit(task.WithCancelCtx(&task.Task[uint64]{
@ -95,5 +95,5 @@ func copyFileBetween2Storages(tsk *task.Task[uint64], srcStorage, dstStorage dri
if err != nil { if err != nil {
return errors.WithMessagef(err, "failed get [%s] stream", srcFilePath) return errors.WithMessagef(err, "failed get [%s] stream", srcFilePath)
} }
return op.Put(tsk.Ctx, dstStorage, dstDirPath, stream, tsk.SetProgress) return op.Put(tsk.Ctx, dstStorage, dstDirPath, stream, tsk.SetProgress, true)
} }

View File

@ -40,32 +40,32 @@ func Link(ctx context.Context, path string, args model.LinkArgs) (*model.Link, m
return res, file, nil return res, file, nil
} }
func MakeDir(ctx context.Context, path string) error { func MakeDir(ctx context.Context, path string, lazyCache ...bool) error {
err := makeDir(ctx, path) err := makeDir(ctx, path, lazyCache...)
if err != nil { if err != nil {
log.Errorf("failed make dir %s: %+v", path, err) log.Errorf("failed make dir %s: %+v", path, err)
} }
return err return err
} }
func Move(ctx context.Context, srcPath, dstDirPath string) error { func Move(ctx context.Context, srcPath, dstDirPath string, lazyCache ...bool) error {
err := move(ctx, srcPath, dstDirPath) err := move(ctx, srcPath, dstDirPath, lazyCache...)
if err != nil { if err != nil {
log.Errorf("failed move %s to %s: %+v", srcPath, dstDirPath, err) log.Errorf("failed move %s to %s: %+v", srcPath, dstDirPath, err)
} }
return err return err
} }
func Copy(ctx context.Context, srcObjPath, dstDirPath string) (bool, error) { func Copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (bool, error) {
res, err := _copy(ctx, srcObjPath, dstDirPath) res, err := _copy(ctx, srcObjPath, dstDirPath, lazyCache...)
if err != nil { if err != nil {
log.Errorf("failed copy %s to %s: %+v", srcObjPath, dstDirPath, err) log.Errorf("failed copy %s to %s: %+v", srcObjPath, dstDirPath, err)
} }
return res, err return res, err
} }
func Rename(ctx context.Context, srcPath, dstName string) error { func Rename(ctx context.Context, srcPath, dstName string, lazyCache ...bool) error {
err := rename(ctx, srcPath, dstName) err := rename(ctx, srcPath, dstName, lazyCache...)
if err != nil { if err != nil {
log.Errorf("failed rename %s to %s: %+v", srcPath, dstName, err) log.Errorf("failed rename %s to %s: %+v", srcPath, dstName, err)
} }
@ -80,8 +80,8 @@ func Remove(ctx context.Context, path string) error {
return err return err
} }
func PutDirectly(ctx context.Context, dstDirPath string, file *model.FileStream) error { func PutDirectly(ctx context.Context, dstDirPath string, file *model.FileStream, lazyCache ...bool) error {
err := putDirectly(ctx, dstDirPath, file) err := putDirectly(ctx, dstDirPath, file, lazyCache...)
if err != nil { if err != nil {
log.Errorf("failed put %s: %+v", dstDirPath, err) log.Errorf("failed put %s: %+v", dstDirPath, err)
} }

View File

@ -9,15 +9,15 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func makeDir(ctx context.Context, path string) error { func makeDir(ctx context.Context, path string, lazyCache ...bool) error {
storage, actualPath, err := op.GetStorageAndActualPath(path) storage, actualPath, err := op.GetStorageAndActualPath(path)
if err != nil { if err != nil {
return errors.WithMessage(err, "failed get storage") return errors.WithMessage(err, "failed get storage")
} }
return op.MakeDir(ctx, storage, actualPath) return op.MakeDir(ctx, storage, actualPath, lazyCache...)
} }
func move(ctx context.Context, srcPath, dstDirPath string) error { func move(ctx context.Context, srcPath, dstDirPath string, lazyCache ...bool) error {
srcStorage, srcActualPath, err := op.GetStorageAndActualPath(srcPath) srcStorage, srcActualPath, err := op.GetStorageAndActualPath(srcPath)
if err != nil { if err != nil {
return errors.WithMessage(err, "failed get src storage") return errors.WithMessage(err, "failed get src storage")
@ -29,15 +29,15 @@ func move(ctx context.Context, srcPath, dstDirPath string) error {
if srcStorage.GetStorage() != dstStorage.GetStorage() { if srcStorage.GetStorage() != dstStorage.GetStorage() {
return errors.WithStack(errs.MoveBetweenTwoStorages) return errors.WithStack(errs.MoveBetweenTwoStorages)
} }
return op.Move(ctx, srcStorage, srcActualPath, dstDirActualPath) return op.Move(ctx, srcStorage, srcActualPath, dstDirActualPath, lazyCache...)
} }
func rename(ctx context.Context, srcPath, dstName string) error { func rename(ctx context.Context, srcPath, dstName string, lazyCache ...bool) error {
storage, srcActualPath, err := op.GetStorageAndActualPath(srcPath) storage, srcActualPath, err := op.GetStorageAndActualPath(srcPath)
if err != nil { if err != nil {
return errors.WithMessage(err, "failed get storage") return errors.WithMessage(err, "failed get storage")
} }
return op.Rename(ctx, storage, srcActualPath, dstName) return op.Rename(ctx, storage, srcActualPath, dstName, lazyCache...)
} }
func remove(ctx context.Context, path string) error { func remove(ctx context.Context, path string) error {

View File

@ -36,14 +36,14 @@ func putAsTask(dstDirPath string, file *model.FileStream) error {
UploadTaskManager.Submit(task.WithCancelCtx(&task.Task[uint64]{ UploadTaskManager.Submit(task.WithCancelCtx(&task.Task[uint64]{
Name: fmt.Sprintf("upload %s to [%s](%s)", file.GetName(), storage.GetStorage().MountPath, dstDirActualPath), Name: fmt.Sprintf("upload %s to [%s](%s)", file.GetName(), storage.GetStorage().MountPath, dstDirActualPath),
Func: func(task *task.Task[uint64]) error { Func: func(task *task.Task[uint64]) error {
return op.Put(task.Ctx, storage, dstDirActualPath, file, nil) return op.Put(task.Ctx, storage, dstDirActualPath, file, nil, true)
}, },
})) }))
return nil return nil
} }
// putDirect put the file and return after finish // putDirect put the file and return after finish
func putDirectly(ctx context.Context, dstDirPath string, file *model.FileStream) error { func putDirectly(ctx context.Context, dstDirPath string, file *model.FileStream, lazyCache ...bool) error {
storage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath) storage, dstDirActualPath, err := op.GetStorageAndActualPath(dstDirPath)
if err != nil { if err != nil {
return errors.WithMessage(err, "failed get storage") return errors.WithMessage(err, "failed get storage")
@ -51,5 +51,5 @@ func putDirectly(ctx context.Context, dstDirPath string, file *model.FileStream)
if storage.Config().NoUpload { if storage.Config().NoUpload {
return errors.WithStack(errs.UploadNotSupported) return errors.WithStack(errs.UploadNotSupported)
} }
return op.Put(ctx, storage, dstDirActualPath, file, nil) return op.Put(ctx, storage, dstDirActualPath, file, nil, lazyCache...)
} }

View File

@ -99,12 +99,45 @@ func ExtractFolder(objs []Obj, extractFolder string) {
}) })
} }
// Wrap
func WrapObjName(objs Obj) Obj {
return &ObjWrapName{Obj: objs}
}
func WrapObjsName(objs []Obj) { func WrapObjsName(objs []Obj) {
for i := 0; i < len(objs); i++ { for i := 0; i < len(objs); i++ {
objs[i] = &ObjWrapName{Obj: objs[i]} objs[i] = &ObjWrapName{Obj: objs[i]}
} }
} }
func UnwrapObjs(obj Obj) Obj {
if unwrap, ok := obj.(UnwrapObj); ok {
obj = unwrap.Unwrap()
}
return obj
}
func GetThumb(obj Obj) (thumb string, ok bool) {
if obj, ok := obj.(Thumb); ok {
return obj.Thumb(), true
}
if unwrap, ok := obj.(UnwrapObj); ok {
return GetThumb(unwrap.Unwrap())
}
return thumb, false
}
func GetUrl(obj Obj) (url string, ok bool) {
if obj, ok := obj.(URL); ok {
return obj.URL(), true
}
if unwrap, ok := obj.(UnwrapObj); ok {
return GetUrl(unwrap.Unwrap())
}
return url, false
}
// Merge
func NewObjMerge() *ObjMerge { func NewObjMerge() *ObjMerge {
return &ObjMerge{ return &ObjMerge{
set: mapset.NewSet[string](), set: mapset.NewSet[string](),

View File

@ -21,6 +21,49 @@ import (
var listCache = cache.NewMemCache(cache.WithShards[[]model.Obj](64)) var listCache = cache.NewMemCache(cache.WithShards[[]model.Obj](64))
var listG singleflight.Group[[]model.Obj] var listG singleflight.Group[[]model.Obj]
func updateCacheObj(storage driver.Driver, path string, oldObj model.Obj, newObj model.Obj) {
key := Key(storage, path)
objs, ok := listCache.Get(key)
if ok {
for i, obj := range objs {
if obj.GetName() == oldObj.GetName() {
objs[i] = newObj
break
}
}
listCache.Set(key, objs, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
}
}
func delCacheObj(storage driver.Driver, path string, obj model.Obj) {
key := Key(storage, path)
objs, ok := listCache.Get(key)
if ok {
for i, oldObj := range objs {
if oldObj.GetName() == obj.GetName() {
objs = append(objs[:i], objs[i+1:]...)
break
}
}
listCache.Set(key, objs, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
}
}
func addCacheObj(storage driver.Driver, path string, newObj model.Obj) {
key := Key(storage, path)
objs, ok := listCache.Get(key)
if ok {
for i, obj := range objs {
if obj.GetName() == newObj.GetName() {
objs[i] = newObj
return
}
}
objs = append(objs, newObj)
listCache.Set(key, objs, cache.WithEx[[]model.Obj](time.Minute*time.Duration(storage.GetStorage().CacheExpiration)))
}
}
func ClearCache(storage driver.Driver, path string) { func ClearCache(storage driver.Driver, path string) {
listCache.Del(Key(storage, path)) listCache.Del(Key(storage, path))
} }
@ -37,7 +80,7 @@ func List(ctx context.Context, storage driver.Driver, path string, args model.Li
path = utils.FixAndCleanPath(path) path = utils.FixAndCleanPath(path)
log.Debugf("op.List %s", path) log.Debugf("op.List %s", path)
key := Key(storage, path) key := Key(storage, path)
if len(refresh) == 0 || !refresh[0] { if !utils.IsBool(refresh...) {
if files, ok := listCache.Get(key); ok { if files, ok := listCache.Get(key); ok {
log.Debugf("use cache when list %s", path) log.Debugf("use cache when list %s", path)
return files, nil return files, nil
@ -148,10 +191,7 @@ func GetUnwrap(ctx context.Context, storage driver.Driver, path string) (model.O
if err != nil { if err != nil {
return nil, err return nil, err
} }
if unwrap, ok := obj.(model.UnwrapObj); ok { return model.UnwrapObjs(obj), err
obj = unwrap.Unwrap()
}
return obj, err
} }
var linkCache = cache.NewMemCache(cache.WithShards[*model.Link](16)) var linkCache = cache.NewMemCache(cache.WithShards[*model.Link](16))
@ -169,7 +209,7 @@ func Link(ctx context.Context, storage driver.Driver, path string, args model.Li
if file.IsDir() { if file.IsDir() {
return nil, nil, errors.WithStack(errs.NotFile) return nil, nil, errors.WithStack(errs.NotFile)
} }
key := stdpath.Join(storage.GetStorage().MountPath, path) + ":" + args.IP key := Key(storage, path) + ":" + args.IP
if link, ok := linkCache.Get(key); ok { if link, ok := linkCache.Get(key); ok {
return link, file, nil return link, file, nil
} }
@ -206,7 +246,7 @@ func Other(ctx context.Context, storage driver.Driver, args model.FsOtherArgs) (
var mkdirG singleflight.Group[interface{}] var mkdirG singleflight.Group[interface{}]
func MakeDir(ctx context.Context, storage driver.Driver, path string) error { func MakeDir(ctx context.Context, storage driver.Driver, path string, lazyCache ...bool) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK { if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status) return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
} }
@ -227,32 +267,124 @@ func MakeDir(ctx context.Context, storage driver.Driver, path string) error {
if err != nil { if err != nil {
return nil, errors.WithMessagef(err, "failed to get parent dir [%s]", parentPath) return nil, errors.WithMessagef(err, "failed to get parent dir [%s]", parentPath)
} }
err = storage.MakeDir(ctx, parentDir, dirName)
switch s := storage.(type) {
case driver.MkdirResult:
var newObj model.Obj
newObj, err = s.MakeDir(ctx, parentDir, dirName)
if err == nil { if err == nil {
if newObj != nil {
addCacheObj(storage, parentPath, model.WrapObjName(newObj))
} else if !utils.IsBool(lazyCache...) {
ClearCache(storage, parentPath) ClearCache(storage, parentPath)
} }
}
case driver.Mkdir:
err = s.MakeDir(ctx, parentDir, dirName)
if err == nil && !utils.IsBool(lazyCache...) {
ClearCache(storage, parentPath)
}
default:
return nil, errs.NotImplement
}
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} else { }
return nil, errors.WithMessage(err, "failed to check if dir exists") return nil, errors.WithMessage(err, "failed to check if dir exists")
} }
} else {
// dir exists // dir exists
if f.IsDir() { if f.IsDir() {
return nil, nil return nil, nil
} else { }
// dir to make is a file // dir to make is a file
return nil, errors.New("file exists") return nil, errors.New("file exists")
}
}
}) })
return err return err
} }
func Move(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string) error { func Move(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string, lazyCache ...bool) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK { if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status) return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
} }
srcPath = utils.FixAndCleanPath(srcPath)
dstDirPath = utils.FixAndCleanPath(dstDirPath)
srcRawObj, err := Get(ctx, storage, srcPath)
if err != nil {
return errors.WithMessage(err, "failed to get src object")
}
srcObj := model.UnwrapObjs(srcRawObj)
dstDir, err := GetUnwrap(ctx, storage, dstDirPath)
if err != nil {
return errors.WithMessage(err, "failed to get dst dir")
}
srcDirPath := stdpath.Dir(srcPath)
switch s := storage.(type) {
case driver.MoveResult:
var newObj model.Obj
newObj, err = s.Move(ctx, srcObj, dstDir)
if err == nil {
delCacheObj(storage, srcDirPath, srcRawObj)
if newObj != nil {
addCacheObj(storage, dstDirPath, model.WrapObjName(newObj))
} else if !utils.IsBool(lazyCache...) {
ClearCache(storage, dstDirPath)
}
}
case driver.Move:
err = s.Move(ctx, srcObj, dstDir)
if err == nil {
delCacheObj(storage, srcDirPath, srcRawObj)
if !utils.IsBool(lazyCache...) {
ClearCache(storage, dstDirPath)
}
}
default:
return errs.NotImplement
}
return errors.WithStack(err)
}
func Rename(ctx context.Context, storage driver.Driver, srcPath, dstName string, lazyCache ...bool) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
srcPath = utils.FixAndCleanPath(srcPath)
srcRawObj, err := Get(ctx, storage, srcPath)
if err != nil {
return errors.WithMessage(err, "failed to get src object")
}
srcObj := model.UnwrapObjs(srcRawObj)
srcDirPath := stdpath.Dir(srcPath)
switch s := storage.(type) {
case driver.RenameResult:
var newObj model.Obj
newObj, err = s.Rename(ctx, srcObj, dstName)
if err == nil {
if newObj != nil {
updateCacheObj(storage, srcDirPath, srcRawObj, model.WrapObjName(newObj))
} else if !utils.IsBool(lazyCache...) {
ClearCache(storage, srcDirPath)
}
}
case driver.Rename:
err = s.Rename(ctx, srcObj, dstName)
if err == nil && !utils.IsBool(lazyCache...) {
ClearCache(storage, srcDirPath)
}
default:
return errs.NotImplement
}
return errors.WithStack(err)
}
// Copy Just copy file[s] in a storage
func Copy(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string, lazyCache ...bool) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
}
srcPath = utils.FixAndCleanPath(srcPath)
dstDirPath = utils.FixAndCleanPath(dstDirPath)
srcObj, err := GetUnwrap(ctx, storage, srcPath) srcObj, err := GetUnwrap(ctx, storage, srcPath)
if err != nil { if err != nil {
return errors.WithMessage(err, "failed to get src object") return errors.WithMessage(err, "failed to get src object")
@ -261,38 +393,35 @@ func Move(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string
if err != nil { if err != nil {
return errors.WithMessage(err, "failed to get dst dir") return errors.WithMessage(err, "failed to get dst dir")
} }
return errors.WithStack(storage.Move(ctx, srcObj, dstDir))
}
func Rename(ctx context.Context, storage driver.Driver, srcPath, dstName string) error { switch s := storage.(type) {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK { case driver.CopyResult:
return errors.Errorf("storage not init: %s", storage.GetStorage().Status) var newObj model.Obj
newObj, err = s.Copy(ctx, srcObj, dstDir)
if err == nil {
if newObj != nil {
addCacheObj(storage, dstDirPath, model.WrapObjName(newObj))
} else if !utils.IsBool(lazyCache...) {
ClearCache(storage, dstDirPath)
} }
srcObj, err := GetUnwrap(ctx, storage, srcPath)
if err != nil {
return errors.WithMessage(err, "failed to get src object")
} }
return errors.WithStack(storage.Rename(ctx, srcObj, dstName)) case driver.Copy:
} err = s.Copy(ctx, srcObj, dstDir)
if err == nil && !utils.IsBool(lazyCache...) {
// Copy Just copy file[s] in a storage ClearCache(storage, dstDirPath)
func Copy(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
} }
srcObj, err := GetUnwrap(ctx, storage, srcPath) default:
if err != nil { return errs.NotImplement
return errors.WithMessage(err, "failed to get src object")
} }
dstDir, err := GetUnwrap(ctx, storage, dstDirPath) return errors.WithStack(err)
return errors.WithStack(storage.Copy(ctx, srcObj, dstDir))
} }
func Remove(ctx context.Context, storage driver.Driver, path string) error { func Remove(ctx context.Context, storage driver.Driver, path string) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK { if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status) return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
} }
obj, err := GetUnwrap(ctx, storage, path) path = utils.FixAndCleanPath(path)
rawObj, err := Get(ctx, storage, path)
if err != nil { if err != nil {
// if object not found, it's ok // if object not found, it's ok
if errs.IsObjectNotFound(err) { if errs.IsObjectNotFound(err) {
@ -300,31 +429,21 @@ func Remove(ctx context.Context, storage driver.Driver, path string) error {
} }
return errors.WithMessage(err, "failed to get object") return errors.WithMessage(err, "failed to get object")
} }
err = storage.Remove(ctx, obj) dirPath := stdpath.Dir(path)
switch s := storage.(type) {
case driver.Remove:
err = s.Remove(ctx, model.UnwrapObjs(rawObj))
if err == nil { if err == nil {
key := Key(storage, stdpath.Dir(path)) delCacheObj(storage, dirPath, rawObj)
if objs, ok := listCache.Get(key); ok {
j := -1
for i, m := range objs {
if m.GetName() == obj.GetName() {
j = i
break
}
}
if j >= 0 && j < len(objs) {
objs = append(objs[:j], objs[j+1:]...)
listCache.Set(key, objs)
} else {
log.Debugf("not found obj")
}
} else {
log.Debugf("not found parent cache")
} }
default:
return errs.NotImplement
} }
return errors.WithStack(err) return errors.WithStack(err)
} }
func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file *model.FileStream, up driver.UpdateProgress) error { func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file *model.FileStream, up driver.UpdateProgress, lazyCache ...bool) error {
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK { if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
return errors.Errorf("storage not init: %s", storage.GetStorage().Status) return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
} }
@ -342,6 +461,7 @@ func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file *mo
} }
}() }()
// if file exist and size = 0, delete it // if file exist and size = 0, delete it
dstDirPath = utils.FixAndCleanPath(dstDirPath)
dstPath := stdpath.Join(dstDirPath, file.GetName()) dstPath := stdpath.Join(dstDirPath, file.GetName())
fi, err := GetUnwrap(ctx, storage, dstPath) fi, err := GetUnwrap(ctx, storage, dstPath)
if err == nil { if err == nil {
@ -367,7 +487,26 @@ func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file *mo
if up == nil { if up == nil {
up = func(p int) {} up = func(p int) {}
} }
err = storage.Put(ctx, parentDir, file, up)
switch s := storage.(type) {
case driver.PutResult:
var newObj model.Obj
newObj, err = s.Put(ctx, parentDir, file, up)
if err == nil {
if newObj != nil {
addCacheObj(storage, dstDirPath, model.WrapObjName(newObj))
} else if !utils.IsBool(lazyCache...) {
ClearCache(storage, dstDirPath)
}
}
case driver.Put:
err = s.Put(ctx, parentDir, file, up)
if err == nil && !utils.IsBool(lazyCache...) {
ClearCache(storage, dstDirPath)
}
default:
return errs.NotImplement
}
log.Debugf("put file [%s] done", file.GetName()) log.Debugf("put file [%s] done", file.GetName())
//if err == nil { //if err == nil {
// //clear cache // //clear cache

5
pkg/utils/bool.go Normal file
View File

@ -0,0 +1,5 @@
package utils
func IsBool(bs ...bool) bool {
return len(bs) > 0 && bs[0]
}

View File

@ -48,7 +48,6 @@ func FsMkdir(c *gin.Context) {
common.ErrorResp(c, err, 500) common.ErrorResp(c, err, 500)
return return
} }
fs.ClearCache(stdpath.Dir(reqPath))
common.SuccessResp(c) common.SuccessResp(c)
} }
@ -83,15 +82,13 @@ func FsMove(c *gin.Context) {
common.ErrorResp(c, err, 403) common.ErrorResp(c, err, 403)
return return
} }
for _, name := range req.Names { for i, name := range req.Names {
err := fs.Move(c, stdpath.Join(srcDir, name), dstDir) err := fs.Move(c, stdpath.Join(srcDir, name), dstDir, len(req.Names) > i+1)
if err != nil { if err != nil {
common.ErrorResp(c, err, 500) common.ErrorResp(c, err, 500)
return return
} }
} }
fs.ClearCache(srcDir)
fs.ClearCache(dstDir)
common.SuccessResp(c) common.SuccessResp(c)
} }
@ -121,8 +118,8 @@ func FsCopy(c *gin.Context) {
return return
} }
var addedTask []string var addedTask []string
for _, name := range req.Names { for i, name := range req.Names {
ok, err := fs.Copy(c, stdpath.Join(srcDir, name), dstDir) ok, err := fs.Copy(c, stdpath.Join(srcDir, name), dstDir, len(req.Names) > i+1)
if ok { if ok {
addedTask = append(addedTask, name) addedTask = append(addedTask, name)
} }
@ -131,9 +128,6 @@ func FsCopy(c *gin.Context) {
return return
} }
} }
if len(req.Names) != len(addedTask) {
fs.ClearCache(dstDir)
}
if len(addedTask) > 0 { if len(addedTask) > 0 {
common.SuccessResp(c, fmt.Sprintf("Added %d tasks", len(addedTask))) common.SuccessResp(c, fmt.Sprintf("Added %d tasks", len(addedTask)))
} else { } else {
@ -166,7 +160,6 @@ func FsRename(c *gin.Context) {
common.ErrorResp(c, err, 500) common.ErrorResp(c, err, 500)
return return
} }
fs.ClearCache(stdpath.Dir(reqPath))
common.SuccessResp(c) common.SuccessResp(c)
} }

View File

@ -191,10 +191,7 @@ func pagination(objs []model.Obj, req *model.PageReq) (int, []model.Obj) {
func toObjsResp(objs []model.Obj, parent string, encrypt bool) []ObjResp { func toObjsResp(objs []model.Obj, parent string, encrypt bool) []ObjResp {
var resp []ObjResp var resp []ObjResp
for _, obj := range objs { for _, obj := range objs {
thumb := "" thumb, _ := model.GetThumb(obj)
if t, ok := obj.(model.Thumb); ok {
thumb = t.Thumb()
}
resp = append(resp, ObjResp{ resp = append(resp, ObjResp{
Name: obj.GetName(), Name: obj.GetName(),
Size: obj.GetSize(), Size: obj.GetSize(),
@ -276,8 +273,8 @@ func FsGet(c *gin.Context) {
} }
} else { } else {
// file have raw url // file have raw url
if u, ok := obj.(model.URL); ok { if url, ok := model.GetUrl(obj); ok {
rawURL = u.URL() rawURL = url
} else { } else {
// if storage is not proxy, use raw url by fs.Link // if storage is not proxy, use raw url by fs.Link
link, _, err := fs.Link(c, reqPath, model.LinkArgs{IP: c.ClientIP(), Header: c.Request.Header}) link, _, err := fs.Link(c, reqPath, model.LinkArgs{IP: c.ClientIP(), Header: c.Request.Header})

View File

@ -46,7 +46,7 @@ func FsStream(c *gin.Context) {
if asTask { if asTask {
err = fs.PutAsTask(dir, stream) err = fs.PutAsTask(dir, stream)
} else { } else {
err = fs.PutDirectly(c, dir, stream) err = fs.PutDirectly(c, dir, stream, true)
} }
if err != nil { if err != nil {
common.ErrorResp(c, err, 500) common.ErrorResp(c, err, 500)
@ -102,7 +102,7 @@ func FsForm(c *gin.Context) {
if asTask { if asTask {
err = fs.PutAsTask(dir, stream) err = fs.PutAsTask(dir, stream)
} else { } else {
err = fs.PutDirectly(c, dir, stream) err = fs.PutDirectly(c, dir, stream, true)
} }
if err != nil { if err != nil {
common.ErrorResp(c, err, 500) common.ErrorResp(c, err, 500)

View File

@ -46,8 +46,6 @@ func moveFiles(ctx context.Context, src, dst string, overwrite bool) (status int
if err != nil { if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
fs.ClearCache(srcDir)
fs.ClearCache(dstDir)
// TODO if there are no files copy, should return 204 // TODO if there are no files copy, should return 204
return http.StatusCreated, nil return http.StatusCreated, nil
} }
@ -60,7 +58,6 @@ func copyFiles(ctx context.Context, src, dst string, overwrite bool) (status int
if err != nil { if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
fs.ClearCache(path.Dir(dst))
// TODO if there are no files copy, should return 204 // TODO if there are no files copy, should return 204
return http.StatusCreated, nil return http.StatusCreated, nil
} }

View File

@ -337,7 +337,6 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int,
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
w.Header().Set("ETag", etag) w.Header().Set("ETag", etag)
fs.ClearCache(path.Dir(reqPath))
return http.StatusCreated, nil return http.StatusCreated, nil
} }
@ -368,7 +367,6 @@ func (h *Handler) handleMkcol(w http.ResponseWriter, r *http.Request) (status in
} }
return http.StatusMethodNotAllowed, err return http.StatusMethodNotAllowed, err
} }
fs.ClearCache(path.Dir(reqPath))
return http.StatusCreated, nil return http.StatusCreated, nil
} }