mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-11-25 19:37:41 +08:00
* feat(cache): improve cache management * feat(disk-usage): add cache * feat(disk-usage): add refresh * fix(disk-usage): cache with ttl * feat(cache): implement KeyedCache and TypedCache for improved caching mechanism * fix(copy): update object retrieval to use Get instead of GetUnwrap * refactor(cache): simplify DirectoryCache structure and improve object management * fix(cache): correct cache entry initialization and key deletion logic in TypedCache * refactor(driver): remove GetObjInfo interface and simplify Link function logic https://github.com/OpenListTeam/OpenList/pull/888/files#r2430925783 * fix(link): optimize link retrieval and caching logic * refactor(cache): consolidate cache management and improve directory cache handling * fix(cache): add cache control based on storage configuration in List function * . * refactor: replace fmt.Sprintf with strconv for integer conversions * refactor(cache): enhance cache entry management with Expirable interface * fix(cache): improve link reference acquisition logic to handle expiration * refactor: replace OnlyLinkMFile with NoLinkSF in driver configurations and logic * refactor(link): enhance link caching logic with dynamic type keys based on IP and User-Agent * feat(drivers): add LinkCacheType to driver configurations for enhanced caching * refactor(cache): streamline directory object management in cache operations * refactor(cache): remove unnecessary 'dirty' field from CacheEntry structure * refactor(cache): replace 'dirty' field with bitwise flags * refactor(io): 调高SyncClosers.AcquireReference的优先级 * refactor(link): 优化链接获取逻辑,增加重 * refactor(link): 添加RequireReference字段以增强链接管理 * refactor(link): 移除MFile字段,改用RangeReader * refactor: 移除不必要的NoLinkSF字段 * refactor(cache): 修改目录缓存的脏标志定义和更新逻辑 * feat(cache): add expiration gc --------- Co-authored-by: KirCute <951206789@qq.com> Co-authored-by: KirCute <kircute@foxmail.com> Co-authored-by: j2rong4cn <j2rong@qq.com>
197 lines
5.2 KiB
Go
197 lines
5.2 KiB
Go
package alias
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
stdpath "path"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/OpenListTeam/OpenList/v4/internal/driver"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/fs"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/op"
|
|
"github.com/OpenListTeam/OpenList/v4/server/common"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func (d *Alias) listRoot(ctx context.Context, withDetails, refresh bool) []model.Obj {
|
|
var objs []model.Obj
|
|
var wg sync.WaitGroup
|
|
for _, k := range d.rootOrder {
|
|
obj := model.Object{
|
|
Name: k,
|
|
IsFolder: true,
|
|
Modified: d.Modified,
|
|
}
|
|
idx := len(objs)
|
|
objs = append(objs, &obj)
|
|
v := d.pathMap[k]
|
|
if !withDetails || len(v) != 1 {
|
|
continue
|
|
}
|
|
remoteDriver, err := op.GetStorageByMountPath(v[0])
|
|
if err != nil {
|
|
continue
|
|
}
|
|
_, ok := remoteDriver.(driver.WithDetails)
|
|
if !ok {
|
|
continue
|
|
}
|
|
objs[idx] = &model.ObjStorageDetails{
|
|
Obj: objs[idx],
|
|
StorageDetailsWithName: model.StorageDetailsWithName{
|
|
StorageDetails: nil,
|
|
DriverName: remoteDriver.Config().Name,
|
|
},
|
|
}
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
c, cancel := context.WithTimeout(ctx, time.Second)
|
|
defer cancel()
|
|
details, e := op.GetStorageDetails(c, remoteDriver, refresh)
|
|
if e != nil {
|
|
if !errors.Is(e, errs.NotImplement) && !errors.Is(e, errs.StorageNotInit) {
|
|
log.Errorf("failed get %s storage details: %+v", remoteDriver.GetStorage().MountPath, e)
|
|
}
|
|
return
|
|
}
|
|
objs[idx].(*model.ObjStorageDetails).StorageDetails = details
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
return objs
|
|
}
|
|
|
|
// do others that not defined in Driver interface
|
|
func getPair(path string) (string, string) {
|
|
// path = strings.TrimSpace(path)
|
|
if strings.Contains(path, ":") {
|
|
pair := strings.SplitN(path, ":", 2)
|
|
if !strings.Contains(pair[0], "/") {
|
|
return pair[0], pair[1]
|
|
}
|
|
}
|
|
return stdpath.Base(path), path
|
|
}
|
|
|
|
func (d *Alias) getRootAndPath(path string) (string, string) {
|
|
if d.autoFlatten {
|
|
return d.oneKey, path
|
|
}
|
|
path = strings.TrimPrefix(path, "/")
|
|
parts := strings.SplitN(path, "/", 2)
|
|
if len(parts) == 1 {
|
|
return parts[0], ""
|
|
}
|
|
return parts[0], parts[1]
|
|
}
|
|
|
|
func (d *Alias) link(ctx context.Context, reqPath string, args model.LinkArgs) (*model.Link, model.Obj, error) {
|
|
storage, reqActualPath, err := op.GetStorageAndActualPath(reqPath)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if !args.Redirect {
|
|
return op.Link(ctx, storage, reqActualPath, args)
|
|
}
|
|
obj, err := fs.Get(ctx, reqPath, &fs.GetArgs{NoLog: true})
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if common.ShouldProxy(storage, stdpath.Base(reqPath)) {
|
|
return nil, obj, nil
|
|
}
|
|
return op.Link(ctx, storage, reqActualPath, args)
|
|
}
|
|
|
|
func (d *Alias) getReqPath(ctx context.Context, obj model.Obj, isParent bool) ([]*string, error) {
|
|
root, sub := d.getRootAndPath(obj.GetPath())
|
|
if sub == "" && !isParent {
|
|
return nil, errs.NotSupport
|
|
}
|
|
dsts, ok := d.pathMap[root]
|
|
all := true
|
|
if !ok {
|
|
return nil, errs.ObjectNotFound
|
|
}
|
|
var reqPath []*string
|
|
for _, dst := range dsts {
|
|
path := stdpath.Join(dst, sub)
|
|
_, err := fs.Get(ctx, path, &fs.GetArgs{NoLog: true})
|
|
if err != nil {
|
|
all = false
|
|
if d.ProtectSameName && d.ParallelWrite && len(reqPath) >= 2 {
|
|
return nil, errs.NotImplement
|
|
}
|
|
continue
|
|
}
|
|
if !d.ProtectSameName && !d.ParallelWrite {
|
|
return []*string{&path}, nil
|
|
}
|
|
reqPath = append(reqPath, &path)
|
|
if d.ProtectSameName && !d.ParallelWrite && len(reqPath) >= 2 {
|
|
return nil, errs.NotImplement
|
|
}
|
|
if d.ProtectSameName && d.ParallelWrite && len(reqPath) >= 2 && !all {
|
|
return nil, errs.NotImplement
|
|
}
|
|
}
|
|
if len(reqPath) == 0 {
|
|
return nil, errs.ObjectNotFound
|
|
}
|
|
return reqPath, nil
|
|
}
|
|
|
|
func (d *Alias) getArchiveMeta(ctx context.Context, dst, sub string, args model.ArchiveArgs) (model.ArchiveMeta, error) {
|
|
reqPath := stdpath.Join(dst, sub)
|
|
storage, reqActualPath, err := op.GetStorageAndActualPath(reqPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, ok := storage.(driver.ArchiveReader); ok {
|
|
return op.GetArchiveMeta(ctx, storage, reqActualPath, model.ArchiveMetaArgs{
|
|
ArchiveArgs: args,
|
|
Refresh: true,
|
|
})
|
|
}
|
|
return nil, errs.NotImplement
|
|
}
|
|
|
|
func (d *Alias) listArchive(ctx context.Context, dst, sub string, args model.ArchiveInnerArgs) ([]model.Obj, error) {
|
|
reqPath := stdpath.Join(dst, sub)
|
|
storage, reqActualPath, err := op.GetStorageAndActualPath(reqPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, ok := storage.(driver.ArchiveReader); ok {
|
|
return op.ListArchive(ctx, storage, reqActualPath, model.ArchiveListArgs{
|
|
ArchiveInnerArgs: args,
|
|
Refresh: true,
|
|
})
|
|
}
|
|
return nil, errs.NotImplement
|
|
}
|
|
|
|
func (d *Alias) extract(ctx context.Context, reqPath string, args model.ArchiveInnerArgs) (*model.Link, error) {
|
|
storage, reqActualPath, err := op.GetStorageAndActualPath(reqPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, ok := storage.(driver.ArchiveReader); !ok {
|
|
return nil, errs.NotImplement
|
|
}
|
|
if args.Redirect && common.ShouldProxy(storage, stdpath.Base(reqPath)) {
|
|
_, err := fs.Get(ctx, reqPath, &fs.GetArgs{NoLog: true})
|
|
if err == nil {
|
|
return nil, err
|
|
}
|
|
return nil, nil
|
|
}
|
|
link, _, err := op.DriverExtract(ctx, storage, reqActualPath, args)
|
|
return link, err
|
|
}
|