mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-11-25 11:29:29 +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>
224 lines
5.0 KiB
Go
224 lines
5.0 KiB
Go
package smb
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/OpenListTeam/OpenList/v4/internal/driver"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
|
"github.com/OpenListTeam/OpenList/v4/internal/stream"
|
|
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
|
|
|
|
"github.com/cloudsoda/go-smb2"
|
|
)
|
|
|
|
type SMB struct {
|
|
lastConnTime int64
|
|
model.Storage
|
|
Addition
|
|
fs *smb2.Share
|
|
}
|
|
|
|
func (d *SMB) Config() driver.Config {
|
|
return config
|
|
}
|
|
|
|
func (d *SMB) GetAddition() driver.Additional {
|
|
return &d.Addition
|
|
}
|
|
|
|
func (d *SMB) Init(ctx context.Context) error {
|
|
if !strings.Contains(d.Addition.Address, ":") {
|
|
d.Addition.Address = d.Addition.Address + ":445"
|
|
}
|
|
return d._initFS(ctx)
|
|
}
|
|
|
|
func (d *SMB) Drop(ctx context.Context) error {
|
|
if d.fs != nil {
|
|
_ = d.fs.Umount()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *SMB) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
fullPath := dir.GetPath()
|
|
rawFiles, err := d.fs.ReadDir(fullPath)
|
|
if err != nil {
|
|
d.cleanLastConnTime()
|
|
return nil, err
|
|
}
|
|
d.updateLastConnTime()
|
|
var files []model.Obj
|
|
for _, f := range rawFiles {
|
|
file := model.ObjThumb{
|
|
Object: model.Object{
|
|
Name: f.Name(),
|
|
Modified: f.ModTime(),
|
|
Size: f.Size(),
|
|
IsFolder: f.IsDir(),
|
|
Ctime: f.(*smb2.FileStat).CreationTime,
|
|
},
|
|
}
|
|
files = append(files, &file)
|
|
}
|
|
return files, nil
|
|
}
|
|
|
|
func (d *SMB) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
fullPath := file.GetPath()
|
|
remoteFile, err := d.fs.Open(fullPath)
|
|
if err != nil {
|
|
d.cleanLastConnTime()
|
|
return nil, err
|
|
}
|
|
d.updateLastConnTime()
|
|
mFile := &stream.RateLimitFile{
|
|
File: remoteFile,
|
|
Limiter: stream.ServerDownloadLimit,
|
|
Ctx: ctx,
|
|
}
|
|
return &model.Link{
|
|
RangeReader: stream.GetRangeReaderFromMFile(file.GetSize(), mFile),
|
|
SyncClosers: utils.NewSyncClosers(remoteFile),
|
|
RequireReference: true,
|
|
}, nil
|
|
}
|
|
|
|
func (d *SMB) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return err
|
|
}
|
|
fullPath := filepath.Join(parentDir.GetPath(), dirName)
|
|
err := d.fs.MkdirAll(fullPath, 0700)
|
|
if err != nil {
|
|
d.cleanLastConnTime()
|
|
return err
|
|
}
|
|
d.updateLastConnTime()
|
|
return nil
|
|
}
|
|
|
|
func (d *SMB) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return err
|
|
}
|
|
srcPath := srcObj.GetPath()
|
|
dstPath := filepath.Join(dstDir.GetPath(), srcObj.GetName())
|
|
err := d.fs.Rename(srcPath, dstPath)
|
|
if err != nil {
|
|
d.cleanLastConnTime()
|
|
return err
|
|
}
|
|
d.updateLastConnTime()
|
|
return nil
|
|
}
|
|
|
|
func (d *SMB) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return err
|
|
}
|
|
srcPath := srcObj.GetPath()
|
|
dstPath := filepath.Join(filepath.Dir(srcPath), newName)
|
|
err := d.fs.Rename(srcPath, dstPath)
|
|
if err != nil {
|
|
d.cleanLastConnTime()
|
|
return err
|
|
}
|
|
d.updateLastConnTime()
|
|
return nil
|
|
}
|
|
|
|
func (d *SMB) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return err
|
|
}
|
|
srcPath := srcObj.GetPath()
|
|
dstPath := filepath.Join(dstDir.GetPath(), srcObj.GetName())
|
|
var err error
|
|
if srcObj.IsDir() {
|
|
err = d.CopyDir(srcPath, dstPath)
|
|
} else {
|
|
err = d.CopyFile(srcPath, dstPath)
|
|
}
|
|
if err != nil {
|
|
d.cleanLastConnTime()
|
|
return err
|
|
}
|
|
d.updateLastConnTime()
|
|
return nil
|
|
}
|
|
|
|
func (d *SMB) Remove(ctx context.Context, obj model.Obj) error {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return err
|
|
}
|
|
var err error
|
|
fullPath := obj.GetPath()
|
|
if obj.IsDir() {
|
|
err = d.fs.RemoveAll(fullPath)
|
|
} else {
|
|
err = d.fs.Remove(fullPath)
|
|
}
|
|
if err != nil {
|
|
d.cleanLastConnTime()
|
|
return err
|
|
}
|
|
d.updateLastConnTime()
|
|
return nil
|
|
}
|
|
|
|
func (d *SMB) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return err
|
|
}
|
|
fullPath := filepath.Join(dstDir.GetPath(), stream.GetName())
|
|
out, err := d.fs.Create(fullPath)
|
|
if err != nil {
|
|
d.cleanLastConnTime()
|
|
return err
|
|
}
|
|
d.updateLastConnTime()
|
|
defer func() {
|
|
_ = out.Close()
|
|
if errors.Is(err, context.Canceled) {
|
|
_ = d.fs.Remove(fullPath)
|
|
}
|
|
}()
|
|
err = utils.CopyWithCtx(ctx, out, driver.NewLimitedUploadStream(ctx, stream), stream.GetSize(), up)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *SMB) GetDetails(ctx context.Context) (*model.StorageDetails, error) {
|
|
if err := d.checkConn(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
stat, err := d.fs.Statfs(d.RootFolderPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &model.StorageDetails{
|
|
DiskUsage: model.DiskUsage{
|
|
TotalSpace: stat.BlockSize() * stat.TotalBlockCount(),
|
|
FreeSpace: stat.BlockSize() * stat.AvailableBlockCount(),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
//func (d *SMB) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
|
|
// return nil, errs.NotSupport
|
|
//}
|
|
|
|
var _ driver.Driver = (*SMB)(nil)
|