mirror of https://github.com/Xhofe/alist
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
parent
e2bcca2fbd
commit
62a06fa0f9
|
@ -9,7 +9,7 @@ import (
|
|||
type Driver interface {
|
||||
Meta
|
||||
Reader
|
||||
Writer
|
||||
//Writer
|
||||
//Other
|
||||
}
|
||||
|
||||
|
@ -42,19 +42,66 @@ type Getter interface {
|
|||
GetRoot(ctx context.Context) (model.Obj, error)
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
// MakeDir make a folder named `dirName` in `parentDir`
|
||||
//type Writer interface {
|
||||
// Mkdir
|
||||
// Move
|
||||
// Rename
|
||||
// Copy
|
||||
// Remove
|
||||
// Put
|
||||
//}
|
||||
|
||||
type Mkdir interface {
|
||||
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
|
||||
// Rename rename `srcObject` to `newName`
|
||||
}
|
||||
|
||||
type Rename interface {
|
||||
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
|
||||
// Remove remove `object`
|
||||
}
|
||||
|
||||
type Remove interface {
|
||||
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
|
||||
}
|
||||
|
||||
//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)
|
||||
|
|
|
@ -21,7 +21,7 @@ var CopyTaskManager = task.NewTaskManager(3, func(tid *uint64) {
|
|||
|
||||
// Copy if in the same storage, call move method
|
||||
// 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)
|
||||
if err != nil {
|
||||
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
|
||||
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
|
||||
CopyTaskManager.Submit(task.WithCancelCtx(&task.Task[uint64]{
|
||||
|
@ -95,5 +95,5 @@ func copyFileBetween2Storages(tsk *task.Task[uint64], srcStorage, dstStorage dri
|
|||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -40,32 +40,32 @@ func Link(ctx context.Context, path string, args model.LinkArgs) (*model.Link, m
|
|||
return res, file, nil
|
||||
}
|
||||
|
||||
func MakeDir(ctx context.Context, path string) error {
|
||||
err := makeDir(ctx, path)
|
||||
func MakeDir(ctx context.Context, path string, lazyCache ...bool) error {
|
||||
err := makeDir(ctx, path, lazyCache...)
|
||||
if err != nil {
|
||||
log.Errorf("failed make dir %s: %+v", path, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Move(ctx context.Context, srcPath, dstDirPath string) error {
|
||||
err := move(ctx, srcPath, dstDirPath)
|
||||
func Move(ctx context.Context, srcPath, dstDirPath string, lazyCache ...bool) error {
|
||||
err := move(ctx, srcPath, dstDirPath, lazyCache...)
|
||||
if err != nil {
|
||||
log.Errorf("failed move %s to %s: %+v", srcPath, dstDirPath, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Copy(ctx context.Context, srcObjPath, dstDirPath string) (bool, error) {
|
||||
res, err := _copy(ctx, srcObjPath, dstDirPath)
|
||||
func Copy(ctx context.Context, srcObjPath, dstDirPath string, lazyCache ...bool) (bool, error) {
|
||||
res, err := _copy(ctx, srcObjPath, dstDirPath, lazyCache...)
|
||||
if err != nil {
|
||||
log.Errorf("failed copy %s to %s: %+v", srcObjPath, dstDirPath, err)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
func Rename(ctx context.Context, srcPath, dstName string) error {
|
||||
err := rename(ctx, srcPath, dstName)
|
||||
func Rename(ctx context.Context, srcPath, dstName string, lazyCache ...bool) error {
|
||||
err := rename(ctx, srcPath, dstName, lazyCache...)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func PutDirectly(ctx context.Context, dstDirPath string, file *model.FileStream) error {
|
||||
err := putDirectly(ctx, dstDirPath, file)
|
||||
func PutDirectly(ctx context.Context, dstDirPath string, file *model.FileStream, lazyCache ...bool) error {
|
||||
err := putDirectly(ctx, dstDirPath, file, lazyCache...)
|
||||
if err != nil {
|
||||
log.Errorf("failed put %s: %+v", dstDirPath, err)
|
||||
}
|
||||
|
|
|
@ -9,15 +9,15 @@ import (
|
|||
"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)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
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() {
|
||||
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)
|
||||
if err != nil {
|
||||
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 {
|
||||
|
|
|
@ -36,14 +36,14 @@ func putAsTask(dstDirPath string, file *model.FileStream) error {
|
|||
UploadTaskManager.Submit(task.WithCancelCtx(&task.Task[uint64]{
|
||||
Name: fmt.Sprintf("upload %s to [%s](%s)", file.GetName(), storage.GetStorage().MountPath, dstDirActualPath),
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
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 {
|
||||
return errors.WithStack(errs.UploadNotSupported)
|
||||
}
|
||||
return op.Put(ctx, storage, dstDirActualPath, file, nil)
|
||||
return op.Put(ctx, storage, dstDirActualPath, file, nil, lazyCache...)
|
||||
}
|
||||
|
|
|
@ -99,12 +99,45 @@ func ExtractFolder(objs []Obj, extractFolder string) {
|
|||
})
|
||||
}
|
||||
|
||||
// Wrap
|
||||
func WrapObjName(objs Obj) Obj {
|
||||
return &ObjWrapName{Obj: objs}
|
||||
}
|
||||
|
||||
func WrapObjsName(objs []Obj) {
|
||||
for i := 0; i < len(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 {
|
||||
return &ObjMerge{
|
||||
set: mapset.NewSet[string](),
|
||||
|
|
|
@ -21,6 +21,49 @@ import (
|
|||
var listCache = cache.NewMemCache(cache.WithShards[[]model.Obj](64))
|
||||
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) {
|
||||
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)
|
||||
log.Debugf("op.List %s", path)
|
||||
key := Key(storage, path)
|
||||
if len(refresh) == 0 || !refresh[0] {
|
||||
if !utils.IsBool(refresh...) {
|
||||
if files, ok := listCache.Get(key); ok {
|
||||
log.Debugf("use cache when list %s", path)
|
||||
return files, nil
|
||||
|
@ -148,10 +191,7 @@ func GetUnwrap(ctx context.Context, storage driver.Driver, path string) (model.O
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if unwrap, ok := obj.(model.UnwrapObj); ok {
|
||||
obj = unwrap.Unwrap()
|
||||
}
|
||||
return obj, err
|
||||
return model.UnwrapObjs(obj), err
|
||||
}
|
||||
|
||||
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() {
|
||||
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 {
|
||||
return link, file, nil
|
||||
}
|
||||
|
@ -206,7 +246,7 @@ func Other(ctx context.Context, storage driver.Driver, args model.FsOtherArgs) (
|
|||
|
||||
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 {
|
||||
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 {
|
||||
return nil, errors.WithMessagef(err, "failed to get parent dir [%s]", parentPath)
|
||||
}
|
||||
err = storage.MakeDir(ctx, parentDir, dirName)
|
||||
if err == nil {
|
||||
ClearCache(storage, parentPath)
|
||||
|
||||
switch s := storage.(type) {
|
||||
case driver.MkdirResult:
|
||||
var newObj model.Obj
|
||||
newObj, err = s.MakeDir(ctx, parentDir, dirName)
|
||||
if err == nil {
|
||||
if newObj != nil {
|
||||
addCacheObj(storage, parentPath, model.WrapObjName(newObj))
|
||||
} else if !utils.IsBool(lazyCache...) {
|
||||
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)
|
||||
} else {
|
||||
return nil, errors.WithMessage(err, "failed to check if dir exists")
|
||||
}
|
||||
} else {
|
||||
// dir exists
|
||||
if f.IsDir() {
|
||||
return nil, nil
|
||||
} else {
|
||||
// dir to make is a file
|
||||
return nil, errors.New("file exists")
|
||||
}
|
||||
return nil, errors.WithMessage(err, "failed to check if dir exists")
|
||||
}
|
||||
// dir exists
|
||||
if f.IsDir() {
|
||||
return nil, nil
|
||||
}
|
||||
// dir to make is a file
|
||||
return nil, errors.New("file exists")
|
||||
})
|
||||
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 {
|
||||
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)
|
||||
if err != nil {
|
||||
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 {
|
||||
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 {
|
||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
||||
return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
|
||||
switch s := storage.(type) {
|
||||
case driver.CopyResult:
|
||||
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)
|
||||
}
|
||||
}
|
||||
case driver.Copy:
|
||||
err = s.Copy(ctx, srcObj, dstDir)
|
||||
if err == nil && !utils.IsBool(lazyCache...) {
|
||||
ClearCache(storage, dstDirPath)
|
||||
}
|
||||
default:
|
||||
return errs.NotImplement
|
||||
}
|
||||
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))
|
||||
}
|
||||
|
||||
// Copy Just copy file[s] in a storage
|
||||
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)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed to get src object")
|
||||
}
|
||||
dstDir, err := GetUnwrap(ctx, storage, dstDirPath)
|
||||
return errors.WithStack(storage.Copy(ctx, srcObj, dstDir))
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
func Remove(ctx context.Context, storage driver.Driver, path string) error {
|
||||
if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
|
||||
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 object not found, it's ok
|
||||
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")
|
||||
}
|
||||
err = storage.Remove(ctx, obj)
|
||||
if err == nil {
|
||||
key := Key(storage, stdpath.Dir(path))
|
||||
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")
|
||||
dirPath := stdpath.Dir(path)
|
||||
|
||||
switch s := storage.(type) {
|
||||
case driver.Remove:
|
||||
err = s.Remove(ctx, model.UnwrapObjs(rawObj))
|
||||
if err == nil {
|
||||
delCacheObj(storage, dirPath, rawObj)
|
||||
}
|
||||
default:
|
||||
return errs.NotImplement
|
||||
}
|
||||
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 {
|
||||
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
|
||||
dstDirPath = utils.FixAndCleanPath(dstDirPath)
|
||||
dstPath := stdpath.Join(dstDirPath, file.GetName())
|
||||
fi, err := GetUnwrap(ctx, storage, dstPath)
|
||||
if err == nil {
|
||||
|
@ -367,7 +487,26 @@ func Put(ctx context.Context, storage driver.Driver, dstDirPath string, file *mo
|
|||
if up == nil {
|
||||
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())
|
||||
//if err == nil {
|
||||
// //clear cache
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package utils
|
||||
|
||||
func IsBool(bs ...bool) bool {
|
||||
return len(bs) > 0 && bs[0]
|
||||
}
|
|
@ -48,7 +48,6 @@ func FsMkdir(c *gin.Context) {
|
|||
common.ErrorResp(c, err, 500)
|
||||
return
|
||||
}
|
||||
fs.ClearCache(stdpath.Dir(reqPath))
|
||||
common.SuccessResp(c)
|
||||
}
|
||||
|
||||
|
@ -83,15 +82,13 @@ func FsMove(c *gin.Context) {
|
|||
common.ErrorResp(c, err, 403)
|
||||
return
|
||||
}
|
||||
for _, name := range req.Names {
|
||||
err := fs.Move(c, stdpath.Join(srcDir, name), dstDir)
|
||||
for i, name := range req.Names {
|
||||
err := fs.Move(c, stdpath.Join(srcDir, name), dstDir, len(req.Names) > i+1)
|
||||
if err != nil {
|
||||
common.ErrorResp(c, err, 500)
|
||||
return
|
||||
}
|
||||
}
|
||||
fs.ClearCache(srcDir)
|
||||
fs.ClearCache(dstDir)
|
||||
common.SuccessResp(c)
|
||||
}
|
||||
|
||||
|
@ -121,8 +118,8 @@ func FsCopy(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
var addedTask []string
|
||||
for _, name := range req.Names {
|
||||
ok, err := fs.Copy(c, stdpath.Join(srcDir, name), dstDir)
|
||||
for i, name := range req.Names {
|
||||
ok, err := fs.Copy(c, stdpath.Join(srcDir, name), dstDir, len(req.Names) > i+1)
|
||||
if ok {
|
||||
addedTask = append(addedTask, name)
|
||||
}
|
||||
|
@ -131,9 +128,6 @@ func FsCopy(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
}
|
||||
if len(req.Names) != len(addedTask) {
|
||||
fs.ClearCache(dstDir)
|
||||
}
|
||||
if len(addedTask) > 0 {
|
||||
common.SuccessResp(c, fmt.Sprintf("Added %d tasks", len(addedTask)))
|
||||
} else {
|
||||
|
@ -166,7 +160,6 @@ func FsRename(c *gin.Context) {
|
|||
common.ErrorResp(c, err, 500)
|
||||
return
|
||||
}
|
||||
fs.ClearCache(stdpath.Dir(reqPath))
|
||||
common.SuccessResp(c)
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
var resp []ObjResp
|
||||
for _, obj := range objs {
|
||||
thumb := ""
|
||||
if t, ok := obj.(model.Thumb); ok {
|
||||
thumb = t.Thumb()
|
||||
}
|
||||
thumb, _ := model.GetThumb(obj)
|
||||
resp = append(resp, ObjResp{
|
||||
Name: obj.GetName(),
|
||||
Size: obj.GetSize(),
|
||||
|
@ -276,8 +273,8 @@ func FsGet(c *gin.Context) {
|
|||
}
|
||||
} else {
|
||||
// file have raw url
|
||||
if u, ok := obj.(model.URL); ok {
|
||||
rawURL = u.URL()
|
||||
if url, ok := model.GetUrl(obj); ok {
|
||||
rawURL = url
|
||||
} else {
|
||||
// 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})
|
||||
|
|
|
@ -46,7 +46,7 @@ func FsStream(c *gin.Context) {
|
|||
if asTask {
|
||||
err = fs.PutAsTask(dir, stream)
|
||||
} else {
|
||||
err = fs.PutDirectly(c, dir, stream)
|
||||
err = fs.PutDirectly(c, dir, stream, true)
|
||||
}
|
||||
if err != nil {
|
||||
common.ErrorResp(c, err, 500)
|
||||
|
@ -102,7 +102,7 @@ func FsForm(c *gin.Context) {
|
|||
if asTask {
|
||||
err = fs.PutAsTask(dir, stream)
|
||||
} else {
|
||||
err = fs.PutDirectly(c, dir, stream)
|
||||
err = fs.PutDirectly(c, dir, stream, true)
|
||||
}
|
||||
if err != nil {
|
||||
common.ErrorResp(c, err, 500)
|
||||
|
|
|
@ -46,8 +46,6 @@ func moveFiles(ctx context.Context, src, dst string, overwrite bool) (status int
|
|||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
fs.ClearCache(srcDir)
|
||||
fs.ClearCache(dstDir)
|
||||
// TODO if there are no files copy, should return 204
|
||||
return http.StatusCreated, nil
|
||||
}
|
||||
|
@ -60,7 +58,6 @@ func copyFiles(ctx context.Context, src, dst string, overwrite bool) (status int
|
|||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
fs.ClearCache(path.Dir(dst))
|
||||
// TODO if there are no files copy, should return 204
|
||||
return http.StatusCreated, nil
|
||||
}
|
||||
|
|
|
@ -337,7 +337,6 @@ func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int,
|
|||
return http.StatusInternalServerError, err
|
||||
}
|
||||
w.Header().Set("ETag", etag)
|
||||
fs.ClearCache(path.Dir(reqPath))
|
||||
return http.StatusCreated, nil
|
||||
}
|
||||
|
||||
|
@ -368,7 +367,6 @@ func (h *Handler) handleMkcol(w http.ResponseWriter, r *http.Request) (status in
|
|||
}
|
||||
return http.StatusMethodNotAllowed, err
|
||||
}
|
||||
fs.ClearCache(path.Dir(reqPath))
|
||||
return http.StatusCreated, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue