diff --git a/internal/db/meta.go b/internal/db/meta.go index 8fd54fd3..8b6a605e 100644 --- a/internal/db/meta.go +++ b/internal/db/meta.go @@ -1,52 +1,16 @@ package db import ( - stdpath "path" - "time" - - "github.com/Xhofe/go-cache" - "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/internal/model" - "github.com/alist-org/alist/v3/pkg/singleflight" - "github.com/alist-org/alist/v3/pkg/utils" "github.com/pkg/errors" - "gorm.io/gorm" ) -var metaCache = cache.NewMemCache(cache.WithShards[*model.Meta](2)) - -// metaG maybe not needed -var metaG singleflight.Group[*model.Meta] - -func GetNearestMeta(path string) (*model.Meta, error) { - path = utils.FixAndCleanPath(path) - meta, err := GetMetaByPath(path) - if err == nil { - return meta, nil - } - if errors.Cause(err) != gorm.ErrRecordNotFound { - return nil, err - } - if path == "/" { - return nil, errors.WithStack(errs.MetaNotFound) - } - return GetNearestMeta(stdpath.Dir(path)) -} - func GetMetaByPath(path string) (*model.Meta, error) { - meta, ok := metaCache.Get(path) - if ok { - return meta, nil + meta := model.Meta{Path: path} + if err := db.Where(meta).First(&meta).Error; err != nil { + return nil, errors.Wrapf(err, "failed select meta") } - meta, err, _ := metaG.Do(path, func() (*model.Meta, error) { - meta := model.Meta{Path: path} - if err := db.Where(meta).First(&meta).Error; err != nil { - return nil, errors.Wrapf(err, "failed select meta") - } - metaCache.Set(path, &meta, cache.WithEx[*model.Meta](time.Hour)) - return &meta, nil - }) - return meta, err + return &meta, nil } func GetMetaById(id uint) (*model.Meta, error) { @@ -62,32 +26,20 @@ func CreateMeta(u *model.Meta) error { } func UpdateMeta(u *model.Meta) error { - old, err := GetMetaById(u.ID) - if err != nil { - return err - } - metaCache.Del(old.Path) return errors.WithStack(db.Save(u).Error) } -func GetMetas(pageIndex, pageSize int) ([]model.Meta, int64, error) { +func GetMetas(pageIndex, pageSize int) (metas []model.Meta, count int64, err error) { metaDB := db.Model(&model.Meta{}) - var count int64 - if err := metaDB.Count(&count).Error; err != nil { + if err = metaDB.Count(&count).Error; err != nil { return nil, 0, errors.Wrapf(err, "failed get metas count") } - var metas []model.Meta - if err := metaDB.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&metas).Error; err != nil { + if err = metaDB.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&metas).Error; err != nil { return nil, 0, errors.Wrapf(err, "failed get find metas") } return metas, count, nil } func DeleteMetaById(id uint) error { - old, err := GetMetaById(id) - if err != nil { - return err - } - metaCache.Del(old.Path) return errors.WithStack(db.Delete(&model.Meta{}, id).Error) } diff --git a/internal/db/meta_test.go b/internal/db/meta_test.go deleted file mode 100644 index c44b85c6..00000000 --- a/internal/db/meta_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package db - -import ( - "testing" - - "github.com/alist-org/alist/v3/internal/errs" - "github.com/alist-org/alist/v3/internal/model" - "github.com/pkg/errors" - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -func init() { - db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{}) - if err != nil { - panic("failed to connect database") - } - Init(db) -} - -func TestCreateMeta(t *testing.T) { - metas := []model.Meta{ - {Path: "/"}, - {Path: "/a"}, - {Path: "/a/b"}, - {Path: "/a/b/c"}, - } - for _, meta := range metas { - err := CreateMeta(&meta) - if err != nil { - t.Errorf("failed to create meta: %+v", err) - } - } -} - -func TestUpdateMeta(t *testing.T) { - meta := model.Meta{ID: 1, Path: "/b"} - err := UpdateMeta(&meta) - if err != nil { - t.Errorf("failed to update meta: %+v", err) - } -} - -func TestGetNearestMeta1(t *testing.T) { - meta, err := GetNearestMeta("/b/c/d") - if err != nil { - t.Errorf("failed to get nearest meta: %+v", err) - } - if meta.Path != "/b" { - t.Errorf("unexpected meta: %+v", meta) - } -} - -func TestGetNearestMeta2(t *testing.T) { - meta, err := GetNearestMeta("/c/d/e") - if errors.Cause(err) != errs.MetaNotFound { - t.Errorf("unexpected error: %+v", err) - t.Errorf("unexpected meta: %+v", meta) - } -} diff --git a/internal/fs/walk.go b/internal/fs/walk.go index 53d1aec0..2069b879 100644 --- a/internal/fs/walk.go +++ b/internal/fs/walk.go @@ -5,8 +5,8 @@ import ( "path" "path/filepath" - "github.com/alist-org/alist/v3/internal/db" "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/internal/op" ) // WalkFS traverses filesystem fs starting at name up to depth levels. @@ -26,7 +26,7 @@ func WalkFS(ctx context.Context, depth int, name string, info model.Obj, walkFn if !info.IsDir() || depth == 0 { return nil } - meta, _ := db.GetNearestMeta(name) + meta, _ := op.GetNearestMeta(name) // Read directory names. objs, err := List(context.WithValue(ctx, "meta", meta), name) if err != nil { diff --git a/internal/op/meta.go b/internal/op/meta.go new file mode 100644 index 00000000..af14f395 --- /dev/null +++ b/internal/op/meta.go @@ -0,0 +1,88 @@ +package op + +import ( + stdpath "path" + "time" + + "github.com/Xhofe/go-cache" + "github.com/alist-org/alist/v3/internal/db" + "github.com/alist-org/alist/v3/internal/errs" + "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/pkg/singleflight" + "github.com/alist-org/alist/v3/pkg/utils" + "github.com/pkg/errors" + "gorm.io/gorm" +) + +var metaCache = cache.NewMemCache(cache.WithShards[*model.Meta](2)) + +// metaG maybe not needed +var metaG singleflight.Group[*model.Meta] + +func GetNearestMeta(path string) (*model.Meta, error) { + return getNearestMeta(utils.FixAndCleanPath(path)) +} +func getNearestMeta(path string) (*model.Meta, error) { + meta, err := GetMetaByPath(path) + if err == nil { + return meta, nil + } + if errors.Cause(err) != gorm.ErrRecordNotFound { + return nil, err + } + if path == "/" { + return nil, errs.MetaNotFound + } + return getNearestMeta(stdpath.Dir(path)) +} + +func GetMetaByPath(path string) (*model.Meta, error) { + return getMetaByPath(utils.FixAndCleanPath(path)) +} +func getMetaByPath(path string) (*model.Meta, error) { + meta, ok := metaCache.Get(path) + if ok { + return meta, nil + } + meta, err, _ := metaG.Do(path, func() (*model.Meta, error) { + _meta, err := db.GetMetaByPath(path) + if err != nil { + return nil, err + } + metaCache.Set(path, _meta, cache.WithEx[*model.Meta](time.Hour)) + return _meta, nil + }) + return meta, err +} + +func DeleteMetaById(id uint) error { + old, err := db.GetMetaById(id) + if err != nil { + return err + } + metaCache.Del(old.Path) + return db.DeleteMetaById(id) +} + +func UpdateMeta(u *model.Meta) error { + u.Path = utils.FixAndCleanPath(u.Path) + old, err := db.GetMetaById(u.ID) + if err != nil { + return err + } + metaCache.Del(old.Path) + return db.UpdateMeta(u) +} + +func CreateMeta(u *model.Meta) error { + u.Path = utils.FixAndCleanPath(u.Path) + return db.CreateMeta(u) +} + +func GetMetaById(id uint) (*model.Meta, error) { + return db.GetMetaById(id) +} + +func GetMetas(pageIndex, pageSize int) (metas []model.Meta, count int64, err error) { + return db.GetMetas(pageIndex, pageSize) +} diff --git a/server/handles/fsmanage.go b/server/handles/fsmanage.go index 1cfa44e9..7b95af5b 100644 --- a/server/handles/fsmanage.go +++ b/server/handles/fsmanage.go @@ -4,10 +4,10 @@ import ( "fmt" stdpath "path" - "github.com/alist-org/alist/v3/internal/db" "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/internal/fs" "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/internal/op" "github.com/alist-org/alist/v3/internal/sign" "github.com/alist-org/alist/v3/pkg/utils" "github.com/alist-org/alist/v3/server/common" @@ -32,7 +32,7 @@ func FsMkdir(c *gin.Context) { return } if !user.CanWrite() { - meta, err := db.GetNearestMeta(stdpath.Dir(reqPath)) + meta, err := op.GetNearestMeta(stdpath.Dir(reqPath)) if err != nil { if !errors.Is(errors.Cause(err), errs.MetaNotFound) { common.ErrorResp(c, err, 500, true) diff --git a/server/handles/fsread.go b/server/handles/fsread.go index aaa90e81..4d4d617a 100644 --- a/server/handles/fsread.go +++ b/server/handles/fsread.go @@ -6,10 +6,10 @@ import ( "strings" "time" - "github.com/alist-org/alist/v3/internal/db" "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/internal/fs" "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/internal/op" "github.com/alist-org/alist/v3/internal/sign" "github.com/alist-org/alist/v3/pkg/utils" "github.com/alist-org/alist/v3/server/common" @@ -61,7 +61,7 @@ func FsList(c *gin.Context) { common.ErrorResp(c, err, 403) return } - meta, err := db.GetNearestMeta(reqPath) + meta, err := op.GetNearestMeta(reqPath) if err != nil { if !errors.Is(errors.Cause(err), errs.MetaNotFound) { common.ErrorResp(c, err, 500, true) @@ -118,7 +118,7 @@ func FsDirs(c *gin.Context) { } reqPath = tmp } - meta, err := db.GetNearestMeta(reqPath) + meta, err := op.GetNearestMeta(reqPath) if err != nil { if !errors.Is(errors.Cause(err), errs.MetaNotFound) { common.ErrorResp(c, err, 500, true) @@ -233,7 +233,7 @@ func FsGet(c *gin.Context) { common.ErrorResp(c, err, 403) return } - meta, err := db.GetNearestMeta(reqPath) + meta, err := op.GetNearestMeta(reqPath) if err != nil { if !errors.Is(errors.Cause(err), errs.MetaNotFound) { common.ErrorResp(c, err, 500) @@ -295,7 +295,7 @@ func FsGet(c *gin.Context) { if err == nil { related = filterRelated(sameLevelFiles, obj) } - parentMeta, _ := db.GetNearestMeta(parentPath) + parentMeta, _ := op.GetNearestMeta(parentPath) common.SuccessResp(c, FsGetResp{ ObjResp: ObjResp{ Name: obj.GetName(), @@ -344,7 +344,7 @@ func FsOther(c *gin.Context) { common.ErrorResp(c, err, 403) return } - meta, err := db.GetNearestMeta(req.Path) + meta, err := op.GetNearestMeta(req.Path) if err != nil { if !errors.Is(errors.Cause(err), errs.MetaNotFound) { common.ErrorResp(c, err, 500) diff --git a/server/handles/meta.go b/server/handles/meta.go index 34825907..e7454d9d 100644 --- a/server/handles/meta.go +++ b/server/handles/meta.go @@ -6,9 +6,8 @@ import ( "strconv" "strings" - "github.com/alist-org/alist/v3/internal/db" "github.com/alist-org/alist/v3/internal/model" - "github.com/alist-org/alist/v3/pkg/utils" + "github.com/alist-org/alist/v3/internal/op" "github.com/alist-org/alist/v3/server/common" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" @@ -22,7 +21,7 @@ func ListMetas(c *gin.Context) { } req.Validate() log.Debugf("%+v", req) - metas, total, err := db.GetMetas(req.Page, req.PerPage) + metas, total, err := op.GetMetas(req.Page, req.PerPage) if err != nil { common.ErrorResp(c, err, 500, true) return @@ -44,8 +43,7 @@ func CreateMeta(c *gin.Context) { common.ErrorStrResp(c, fmt.Sprintf("%s is illegal: %s", r, err.Error()), 400) return } - req.Path = utils.FixAndCleanPath(req.Path) - if err := db.CreateMeta(&req); err != nil { + if err := op.CreateMeta(&req); err != nil { common.ErrorResp(c, err, 500, true) } else { common.SuccessResp(c) @@ -63,8 +61,7 @@ func UpdateMeta(c *gin.Context) { common.ErrorStrResp(c, fmt.Sprintf("%s is illegal: %s", r, err.Error()), 400) return } - req.Path = utils.FixAndCleanPath(req.Path) - if err := db.UpdateMeta(&req); err != nil { + if err := op.UpdateMeta(&req); err != nil { common.ErrorResp(c, err, 500, true) } else { common.SuccessResp(c) @@ -89,7 +86,7 @@ func DeleteMeta(c *gin.Context) { common.ErrorResp(c, err, 400) return } - if err := db.DeleteMetaById(uint(id)); err != nil { + if err := op.DeleteMetaById(uint(id)); err != nil { common.ErrorResp(c, err, 500, true) return } @@ -103,7 +100,7 @@ func GetMeta(c *gin.Context) { common.ErrorResp(c, err, 400) return } - meta, err := db.GetMetaById(uint(id)) + meta, err := op.GetMetaById(uint(id)) if err != nil { common.ErrorResp(c, err, 500, true) return diff --git a/server/handles/search.go b/server/handles/search.go index 8b4d72d6..8881731b 100644 --- a/server/handles/search.go +++ b/server/handles/search.go @@ -4,9 +4,9 @@ import ( "path" "strings" - "github.com/alist-org/alist/v3/internal/db" "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/internal/op" "github.com/alist-org/alist/v3/internal/search" "github.com/alist-org/alist/v3/pkg/utils" "github.com/alist-org/alist/v3/server/common" @@ -53,7 +53,7 @@ func Search(c *gin.Context) { if !strings.HasPrefix(node.Parent, user.BasePath) { continue } - meta, err := db.GetNearestMeta(node.Parent) + meta, err := op.GetNearestMeta(node.Parent) if err != nil && !errors.Is(errors.Cause(err), errs.MetaNotFound) { continue } diff --git a/server/middlewares/down.go b/server/middlewares/down.go index 411d053c..48e9ea72 100644 --- a/server/middlewares/down.go +++ b/server/middlewares/down.go @@ -4,9 +4,9 @@ import ( "strings" "github.com/alist-org/alist/v3/internal/conf" - "github.com/alist-org/alist/v3/internal/db" "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/internal/op" "github.com/alist-org/alist/v3/internal/setting" "github.com/alist-org/alist/v3/internal/sign" "github.com/alist-org/alist/v3/pkg/utils" @@ -18,7 +18,7 @@ import ( func Down(c *gin.Context) { rawPath := parsePath(c.Param("path")) c.Set("path", rawPath) - meta, err := db.GetNearestMeta(rawPath) + meta, err := op.GetNearestMeta(rawPath) if err != nil { if !errors.Is(errors.Cause(err), errs.MetaNotFound) { common.ErrorResp(c, err, 500, true) diff --git a/server/middlewares/fsup.go b/server/middlewares/fsup.go index 3e503cc6..809e8f29 100644 --- a/server/middlewares/fsup.go +++ b/server/middlewares/fsup.go @@ -4,9 +4,9 @@ import ( "net/url" stdpath "path" - "github.com/alist-org/alist/v3/internal/db" "github.com/alist-org/alist/v3/internal/errs" "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/internal/op" "github.com/alist-org/alist/v3/server/common" "github.com/gin-gonic/gin" "github.com/pkg/errors" @@ -27,7 +27,7 @@ func FsUp(c *gin.Context) { common.ErrorResp(c, err, 403) return } - meta, err := db.GetNearestMeta(stdpath.Dir(path)) + meta, err := op.GetNearestMeta(stdpath.Dir(path)) if err != nil { if !errors.Is(errors.Cause(err), errs.MetaNotFound) { common.ErrorResp(c, err, 500, true) diff --git a/server/webdav/file.go b/server/webdav/file.go index 4840f126..c053a4cb 100644 --- a/server/webdav/file.go +++ b/server/webdav/file.go @@ -10,9 +10,9 @@ import ( "path" "path/filepath" - "github.com/alist-org/alist/v3/internal/db" "github.com/alist-org/alist/v3/internal/fs" "github.com/alist-org/alist/v3/internal/model" + "github.com/alist-org/alist/v3/internal/op" ) // slashClean is equivalent to but slightly more efficient than @@ -85,7 +85,7 @@ func walkFS(ctx context.Context, depth int, name string, info model.Obj, walkFn if depth == 1 { depth = 0 } - meta, _ := db.GetNearestMeta(name) + meta, _ := op.GetNearestMeta(name) // Read directory names. objs, err := fs.List(context.WithValue(ctx, "meta", meta), name) //f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0)