perf(link): optimize concurrent response (#641)

* fix(crypt): bug caused by link cache

* perf(crypt,mega,halalcloud,quark,uc): optimize concurrent response link

* chore: 删除无用代码

* ftp

* 修复bug;资源释放

* 添加SyncClosers

* local,sftp,smb

* 重构,优化,增强

* Update internal/stream/util.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com>

* chore

* chore

* 优化,修复bug

* .

---------

Signed-off-by: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
j2rong4cn
2025-07-12 17:57:54 +08:00
committed by GitHub
parent e5fbe72581
commit cc01b410a4
83 changed files with 796 additions and 751 deletions

View File

@ -18,7 +18,6 @@ var config = driver.Config{
Name: "115 Cloud",
DefaultRoot: "0",
// OnlyProxy: true,
// OnlyLocal: true,
// NoOverwriteUpload: true,
}

View File

@ -11,23 +11,14 @@ type Addition struct {
// define other
OrderBy string `json:"order_by" type:"select" options:"file_name,file_size,user_utime,file_type"`
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc"`
LimitRate float64 `json:"limit_rate" type:"float" default:"1" help:"limit all api request rate ([limit]r/1s)"`
LimitRate float64 `json:"limit_rate" type:"float" default:"1" help:"limit all api request rate ([limit]r/1s)"`
AccessToken string `json:"access_token" required:"true"`
RefreshToken string `json:"refresh_token" required:"true"`
}
var config = driver.Config{
Name: "115 Open",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "0",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "115 Open",
DefaultRoot: "0",
}
func init() {

View File

@ -19,12 +19,7 @@ type Addition struct {
var config = driver.Config{
Name: "115 Share",
DefaultRoot: "0",
// OnlyProxy: true,
// OnlyLocal: true,
CheckStatus: false,
Alert: "",
NoOverwriteUpload: true,
NoUpload: true,
NoUpload: true,
}
func init() {

View File

@ -15,17 +15,10 @@ type Addition struct {
}
var config = driver.Config{
Name: "123PanShare",
LocalSort: true,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: true,
NeedMs: false,
DefaultRoot: "0",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "123PanShare",
LocalSort: true,
NoUpload: true,
DefaultRoot: "0",
}
func init() {

View File

@ -3,6 +3,7 @@ package alias
import (
"context"
"errors"
"fmt"
"io"
stdpath "path"
"strings"
@ -11,8 +12,10 @@ import (
"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/sign"
"github.com/OpenListTeam/OpenList/v4/internal/stream"
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
"github.com/OpenListTeam/OpenList/v4/server/common"
)
type Alias struct {
@ -111,21 +114,43 @@ func (d *Alias) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (
return nil, errs.ObjectNotFound
}
for _, dst := range dsts {
link, err := d.link(ctx, dst, sub, args)
if err == nil {
link.Expiration = nil // 去除非必要缓存d.link里op.Lin有缓存
if !args.Redirect && len(link.URL) > 0 {
// 正常情况下 多并发 仅支持返回URL的驱动
// alias套娃alias 可以让crypt、mega等驱动(不返回URL的) 支持并发
if d.DownloadConcurrency > 0 {
link.Concurrency = d.DownloadConcurrency
}
if d.DownloadPartSize > 0 {
link.PartSize = d.DownloadPartSize * utils.KB
reqPath := stdpath.Join(dst, sub)
link, file, err := d.link(ctx, reqPath, args)
if err != nil {
continue
}
var resultLink *model.Link
if link != nil {
resultLink = &model.Link{
URL: link.URL,
Header: link.Header,
RangeReader: link.RangeReader,
SyncClosers: utils.NewSyncClosers(link),
}
if link.MFile != nil {
resultLink.RangeReader = &model.FileRangeReader{
RangeReaderIF: stream.GetRangeReaderFromMFile(file.GetSize(), link.MFile),
}
}
return link, nil
} else {
resultLink = &model.Link{
URL: fmt.Sprintf("%s/p%s?sign=%s",
common.GetApiUrl(ctx),
utils.EncodePath(reqPath, true),
sign.Sign(reqPath)),
}
}
if !args.Redirect {
if d.DownloadConcurrency > 0 {
resultLink.Concurrency = d.DownloadConcurrency
}
if d.DownloadPartSize > 0 {
resultLink.PartSize = d.DownloadPartSize * utils.KB
}
}
return resultLink, nil
}
return nil, errs.ObjectNotFound
}
@ -251,9 +276,13 @@ func (d *Alias) Put(ctx context.Context, dstDir model.Obj, s model.FileStreamer,
reqPath, err := d.getReqPath(ctx, dstDir, true)
if err == nil {
if len(reqPath) == 1 {
return fs.PutDirectly(ctx, *reqPath[0], s)
return fs.PutDirectly(ctx, *reqPath[0], &stream.FileStream{
Obj: s,
Mimetype: s.GetMimetype(),
WebPutAsTask: s.NeedStore(),
Reader: s,
})
} else {
defer s.Close()
file, err := s.CacheFullInTempFile()
if err != nil {
return err
@ -338,14 +367,6 @@ func (d *Alias) Extract(ctx context.Context, obj model.Obj, args model.ArchiveIn
for _, dst := range dsts {
link, err := d.extract(ctx, dst, sub, args)
if err == nil {
if !args.Redirect && len(link.URL) > 0 {
if d.DownloadConcurrency > 0 {
link.Concurrency = d.DownloadConcurrency
}
if d.DownloadPartSize > 0 {
link.PartSize = d.DownloadPartSize * utils.KB
}
}
return link, nil
}
}

View File

@ -96,37 +96,23 @@ func (d *Alias) list(ctx context.Context, dst, sub string, args *fs.ListArgs) ([
})
}
func (d *Alias) link(ctx context.Context, dst, sub string, args model.LinkArgs) (*model.Link, error) {
reqPath := stdpath.Join(dst, sub)
// 参考 crypt 驱动
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, err
return nil, nil, err
}
useRawLink := len(common.GetApiUrl(ctx)) == 0 // ftps3
if !useRawLink {
_, ok := storage.(*Alias)
useRawLink = !ok && !args.Redirect
// proxy || ftp,s3
if !args.Redirect || len(common.GetApiUrl(ctx)) == 0 {
return op.Link(ctx, storage, reqActualPath, args)
}
if useRawLink {
link, _, err := op.Link(ctx, storage, reqActualPath, args)
return link, err
}
_, err = fs.Get(ctx, reqPath, &fs.GetArgs{NoLog: true})
obj, err := fs.Get(ctx, reqPath, &fs.GetArgs{NoLog: true})
if err != nil {
return nil, err
return nil, nil, err
}
if common.ShouldProxy(storage, stdpath.Base(sub)) {
link := &model.Link{
URL: fmt.Sprintf("%s/p%s?sign=%s",
common.GetApiUrl(ctx),
utils.EncodePath(reqPath, true),
sign.Sign(reqPath)),
}
return link, nil
if common.ShouldProxy(storage, stdpath.Base(reqPath)) {
return nil, obj, nil
}
link, _, err := op.Link(ctx, storage, reqActualPath, args)
return link, err
return op.Link(ctx, storage, reqActualPath, args)
}
func (d *Alias) getReqPath(ctx context.Context, obj model.Obj, isParent bool) ([]*string, error) {

View File

@ -165,7 +165,7 @@ func (d *AliDrive) Remove(ctx context.Context, obj model.Obj) error {
}
func (d *AliDrive) Put(ctx context.Context, dstDir model.Obj, streamer model.FileStreamer, up driver.UpdateProgress) error {
file := stream.FileStream{
file := &stream.FileStream{
Obj: streamer,
Reader: streamer,
Mimetype: streamer.GetMimetype(),
@ -209,7 +209,7 @@ func (d *AliDrive) Put(ctx context.Context, dstDir model.Obj, streamer model.Fil
io.Closer
}{
Reader: io.MultiReader(buf, file),
Closer: &file,
Closer: file,
}
}
} else {

View File

@ -25,12 +25,6 @@ type Addition struct {
var config = driver.Config{
Name: "AliyundriveOpen",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "root",
NoOverwriteUpload: true,
}

View File

@ -32,7 +32,6 @@ func init() {
config: driver.Config{
Name: "ChaoXingGroupDrive",
OnlyProxy: true,
OnlyLocal: false,
DefaultRoot: "-1",
NoOverwriteUpload: true,
},

View File

@ -26,15 +26,8 @@ type Addition struct {
var config = driver.Config{
Name: "Cloudreve V4",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "cloudreve://my",
CheckStatus: true,
Alert: "",
NoOverwriteUpload: true,
}

View File

@ -1,12 +1,14 @@
package crypt
import (
"bytes"
"context"
"fmt"
"io"
stdpath "path"
"regexp"
"strings"
"sync"
"github.com/OpenListTeam/OpenList/v4/internal/driver"
"github.com/OpenListTeam/OpenList/v4/internal/errs"
@ -241,6 +243,9 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) {
//return nil, errs.ObjectNotFound
}
// https://github.com/rclone/rclone/blob/v1.67.0/backend/crypt/cipher.go#L37
const fileHeaderSize = 32
func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
dstDirActualPath, err := d.getActualPathForRemote(file.GetPath(), false)
if err != nil {
@ -251,58 +256,64 @@ func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (
return nil, err
}
if remoteLink.RangeReadCloser == nil && remoteLink.MFile == nil && len(remoteLink.URL) == 0 {
rrf, err := stream.GetRangeReaderFromLink(remoteFile.GetSize(), remoteLink)
if err != nil {
_ = remoteLink.Close()
return nil, fmt.Errorf("the remote storage driver need to be enhanced to support encrytion")
}
resultRangeReadCloser := &model.RangeReadCloser{}
resultRangeReadCloser.TryAdd(remoteLink.MFile)
if remoteLink.RangeReadCloser != nil {
resultRangeReadCloser.AddClosers(remoteLink.RangeReadCloser.GetClosers())
}
remoteFileSize := remoteFile.GetSize()
rangeReaderFunc := func(ctx context.Context, underlyingOffset, underlyingLength int64) (io.ReadCloser, error) {
length := underlyingLength
if underlyingLength >= 0 && underlyingOffset+underlyingLength >= remoteFileSize {
length = -1
}
if remoteLink.MFile != nil {
_, err := remoteLink.MFile.Seek(underlyingOffset, io.SeekStart)
if err != nil {
return nil, err
}
//keep reuse same MFile and close at last.
return io.NopCloser(remoteLink.MFile), nil
}
rrc := remoteLink.RangeReadCloser
if rrc == nil && len(remoteLink.URL) > 0 {
var err error
rrc, err = stream.GetRangeReadCloserFromLink(remoteFileSize, remoteLink)
if err != nil {
return nil, err
}
resultRangeReadCloser.AddClosers(rrc.GetClosers())
remoteLink.RangeReadCloser = rrc
}
if rrc != nil {
remoteReader, err := rrc.RangeRead(ctx, http_range.Range{Start: underlyingOffset, Length: length})
if err != nil {
return nil, err
}
return remoteReader, nil
}
return nil, errs.NotSupport
}
resultRangeReadCloser.RangeReader = func(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error) {
readSeeker, err := d.cipher.DecryptDataSeek(ctx, rangeReaderFunc, httpRange.Start, httpRange.Length)
mu := &sync.Mutex{}
var fileHeader []byte
rangeReaderFunc := func(ctx context.Context, offset, limit int64) (io.ReadCloser, error) {
length := limit
if offset == 0 && limit > 0 {
mu.Lock()
if limit <= fileHeaderSize {
defer mu.Unlock()
if fileHeader != nil {
return io.NopCloser(bytes.NewReader(fileHeader[:limit])), nil
}
length = fileHeaderSize
} else if fileHeader == nil {
defer mu.Unlock()
} else {
mu.Unlock()
}
}
remoteReader, err := rrf.RangeRead(ctx, http_range.Range{Start: offset, Length: length})
if err != nil {
return nil, err
}
return readSeeker, nil
}
if offset == 0 && limit > 0 {
fileHeader = make([]byte, fileHeaderSize)
n, _ := io.ReadFull(remoteReader, fileHeader)
if n != fileHeaderSize {
fileHeader = nil
return nil, fmt.Errorf("can't read data, expected=%d, got=%d", fileHeaderSize, n)
}
if limit <= fileHeaderSize {
remoteReader.Close()
return io.NopCloser(bytes.NewReader(fileHeader[:limit])), nil
} else {
remoteReader = utils.ReadCloser{
Reader: io.MultiReader(bytes.NewReader(fileHeader), remoteReader),
Closer: remoteReader,
}
}
}
return remoteReader, nil
}
return &model.Link{
RangeReadCloser: resultRangeReadCloser,
RangeReader: stream.RangeReaderFunc(func(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error) {
readSeeker, err := d.cipher.DecryptDataSeek(ctx, rangeReaderFunc, httpRange.Start, httpRange.Length)
if err != nil {
return nil, err
}
return readSeeker, nil
}),
SyncClosers: utils.NewSyncClosers(remoteLink),
}, nil
}

View File

@ -26,17 +26,12 @@ type Addition struct {
}
var config = driver.Config{
Name: "Crypt",
LocalSort: true,
OnlyLocal: true,
OnlyProxy: true,
NoCache: true,
NoUpload: false,
NeedMs: false,
DefaultRoot: "/",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "Crypt",
LocalSort: true,
OnlyProxy: true,
NoCache: true,
DefaultRoot: "/",
NoLinkURL: true,
}
func init() {

View File

@ -16,17 +16,9 @@ type Addition struct {
}
var config = driver.Config{
Name: "Doubao",
LocalSort: true,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "0",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "Doubao",
LocalSort: true,
DefaultRoot: "0",
}
func init() {

View File

@ -12,17 +12,10 @@ type Addition struct {
}
var config = driver.Config{
Name: "DoubaoShare",
LocalSort: true,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: true,
NeedMs: false,
DefaultRoot: "/",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "DoubaoShare",
LocalSort: true,
NoUpload: true,
DefaultRoot: "/",
}
func init() {

View File

@ -18,13 +18,6 @@ type Addition struct {
var config = driver.Config{
Name: "Dropbox",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "",
NoOverwriteUpload: true,
}

View File

@ -16,17 +16,9 @@ type Addition struct {
}
var config = driver.Config{
Name: "FebBox",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: true,
NeedMs: false,
DefaultRoot: "0",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "FebBox",
NoUpload: true,
DefaultRoot: "0",
}
func init() {

View File

@ -8,6 +8,7 @@ import (
"github.com/OpenListTeam/OpenList/v4/internal/errs"
"github.com/OpenListTeam/OpenList/v4/internal/model"
"github.com/OpenListTeam/OpenList/v4/internal/stream"
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
"github.com/jlaffaye/ftp"
)
@ -26,7 +27,7 @@ func (d *FTP) GetAddition() driver.Additional {
}
func (d *FTP) Init(ctx context.Context) error {
return d.login()
return d._login()
}
func (d *FTP) Drop(ctx context.Context) error {
@ -65,15 +66,22 @@ func (d *FTP) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*m
return nil, err
}
r := NewFileReader(d.conn, encode(file.GetPath(), d.Encoding), file.GetSize())
link := &model.Link{
remoteFile := NewFileReader(d.conn, encode(file.GetPath(), d.Encoding), file.GetSize())
if remoteFile != nil && !d.Config().OnlyLinkMFile {
return &model.Link{
RangeReader: &model.FileRangeReader{
RangeReaderIF: stream.RateLimitRangeReaderFunc(stream.GetRangeReaderFromMFile(file.GetSize(), remoteFile)),
},
SyncClosers: utils.NewSyncClosers(remoteFile),
}, nil
}
return &model.Link{
MFile: &stream.RateLimitFile{
File: r,
File: remoteFile,
Limiter: stream.ServerDownloadLimit,
Ctx: ctx,
},
}
return link, nil
}, nil
}
func (d *FTP) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {

View File

@ -31,10 +31,11 @@ type Addition struct {
}
var config = driver.Config{
Name: "FTP",
LocalSort: true,
OnlyLocal: true,
DefaultRoot: "/",
Name: "FTP",
LocalSort: true,
OnlyLinkMFile: true,
DefaultRoot: "/",
NoLinkURL: true,
}
func init() {

View File

@ -1,18 +1,28 @@
package ftp
import (
"fmt"
"io"
"os"
"sync"
"sync/atomic"
"time"
"github.com/OpenListTeam/OpenList/v4/pkg/singleflight"
"github.com/jlaffaye/ftp"
)
// do others that not defined in Driver interface
func (d *FTP) login() error {
err, _, _ := singleflight.ErrorGroup.Do(fmt.Sprintf("FTP.login:%p", d), func() (error, error) {
return d._login(), nil
})
return err
}
func (d *FTP) _login() error {
if d.conn != nil {
_, err := d.conn.CurrentDir()
if err == nil {

View File

@ -15,17 +15,8 @@ type Addition struct {
}
var config = driver.Config{
Name: "GitHub Releases",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "GitHub Releases",
NoUpload: true,
}
func init() {

View File

@ -14,6 +14,7 @@ import (
"github.com/OpenListTeam/OpenList/v4/internal/driver"
"github.com/OpenListTeam/OpenList/v4/internal/model"
"github.com/OpenListTeam/OpenList/v4/internal/op"
"github.com/OpenListTeam/OpenList/v4/internal/stream"
"github.com/OpenListTeam/OpenList/v4/pkg/http_range"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
@ -253,8 +254,8 @@ func (d *HalalCloud) getLink(ctx context.Context, file model.Obj, args model.Lin
chunks := getChunkSizes(result.Sizes)
resultRangeReader := func(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error) {
length := httpRange.Length
if httpRange.Length >= 0 && httpRange.Start+httpRange.Length >= size {
length = -1
if httpRange.Length < 0 || httpRange.Start+httpRange.Length >= size {
length = size - httpRange.Start
}
oo := &openObject{
ctx: ctx,
@ -276,10 +277,9 @@ func (d *HalalCloud) getLink(ctx context.Context, file model.Obj, args model.Lin
duration = time.Until(time.Now().Add(time.Hour))
}
resultRangeReadCloser := &model.RangeReadCloser{RangeReader: resultRangeReader}
return &model.Link{
RangeReadCloser: resultRangeReadCloser,
Expiration: &duration,
RangeReader: stream.RateLimitRangeReaderFunc(resultRangeReader),
Expiration: &duration,
}, nil
}

View File

@ -18,17 +18,10 @@ type Addition struct {
}
var config = driver.Config{
Name: "HalalCloud",
LocalSort: false,
OnlyLocal: true,
OnlyProxy: true,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "/",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "HalalCloud",
OnlyProxy: true,
DefaultRoot: "/",
NoLinkURL: true,
}
func init() {

View File

@ -29,17 +29,8 @@ func init() {
op.RegisterDriver(func() driver.Driver {
return &ILanZou{
config: driver.Config{
Name: "ILanZou",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "0",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "ILanZou",
DefaultRoot: "0",
},
conf: Conf{
base: "https://api.ilanzou.com",
@ -55,17 +46,8 @@ func init() {
op.RegisterDriver(func() driver.Driver {
return &ILanZou{
config: driver.Config{
Name: "FeijiPan",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "0",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "FeijiPan",
DefaultRoot: "0",
},
conf: Conf{
base: "https://api.feijipan.com",

View File

@ -17,7 +17,6 @@ var config = driver.Config{
Name: "IPFS API",
DefaultRoot: "/",
LocalSort: true,
OnlyProxy: false,
}
func init() {

View File

@ -14,8 +14,7 @@ type Addition struct {
}
var config = driver.Config{
Name: "KodBox",
DefaultRoot: "",
Name: "KodBox",
}
func init() {

View File

@ -13,17 +13,9 @@ type Addition struct {
}
var config = driver.Config{
Name: "LenovoNasShare",
LocalSort: true,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: true,
NeedMs: false,
DefaultRoot: "",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "LenovoNasShare",
LocalSort: true,
NoUpload: true,
}
func init() {

View File

@ -19,6 +19,7 @@ import (
"github.com/OpenListTeam/OpenList/v4/internal/errs"
"github.com/OpenListTeam/OpenList/v4/internal/model"
"github.com/OpenListTeam/OpenList/v4/internal/sign"
"github.com/OpenListTeam/OpenList/v4/internal/stream"
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
"github.com/OpenListTeam/OpenList/v4/server/common"
"github.com/OpenListTeam/times"
@ -220,7 +221,7 @@ func (d *Local) Get(ctx context.Context, path string) (model.Obj, error) {
func (d *Local) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
fullPath := file.GetPath()
var link model.Link
link := &model.Link{}
if args.Type == "thumb" && utils.Ext(file.GetName()) != "svg" {
var buf *bytes.Buffer
var thumbPath *string
@ -252,7 +253,14 @@ func (d *Local) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (
}
link.MFile = open
}
return &link, nil
if link.MFile != nil && !d.Config().OnlyLinkMFile {
link.AddIfCloser(link.MFile)
link.RangeReader = &model.FileRangeReader{
RangeReaderIF: stream.GetRangeReaderFromMFile(file.GetSize(), link.MFile),
}
link.MFile = nil
}
return link, nil
}
func (d *Local) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {

View File

@ -17,11 +17,12 @@ type Addition struct {
}
var config = driver.Config{
Name: "Local",
OnlyLocal: true,
LocalSort: true,
NoCache: true,
DefaultRoot: "/",
Name: "Local",
OnlyLinkMFile: false,
LocalSort: true,
NoCache: true,
DefaultRoot: "/",
NoLinkURL: true,
}
func init() {

View File

@ -14,6 +14,7 @@ import (
"github.com/OpenListTeam/OpenList/v4/internal/driver"
"github.com/OpenListTeam/OpenList/v4/internal/errs"
"github.com/OpenListTeam/OpenList/v4/internal/model"
"github.com/OpenListTeam/OpenList/v4/internal/stream"
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
log "github.com/sirupsen/logrus"
"github.com/t3rm1n4l/go-mega"
@ -95,8 +96,8 @@ func (d *Mega) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*
size := file.GetSize()
resultRangeReader := func(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error) {
length := httpRange.Length
if httpRange.Length >= 0 && httpRange.Start+httpRange.Length >= size {
length = -1
if httpRange.Length < 0 || httpRange.Start+httpRange.Length >= size {
length = size - httpRange.Start
}
var down *mega.Download
err := utils.Retry(3, time.Second, func() (err error) {
@ -114,11 +115,9 @@ func (d *Mega) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*
return readers.NewLimitedReadCloser(oo, length), nil
}
resultRangeReadCloser := &model.RangeReadCloser{RangeReader: resultRangeReader}
resultLink := &model.Link{
RangeReadCloser: resultRangeReadCloser,
}
return resultLink, nil
return &model.Link{
RangeReader: stream.RateLimitRangeReaderFunc(resultRangeReader),
}, nil
}
return nil, fmt.Errorf("unable to convert dir to mega n")
}

View File

@ -18,7 +18,8 @@ type Addition struct {
var config = driver.Config{
Name: "Mega_nz",
LocalSort: true,
OnlyLocal: true,
OnlyProxy: true,
NoLinkURL: true,
}
func init() {

View File

@ -15,17 +15,8 @@ type Addition struct {
}
var config = driver.Config{
Name: "Misskey",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "/",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
Name: "Misskey",
DefaultRoot: "/",
}
func init() {

View File

@ -27,8 +27,7 @@ func (a *Addition) GetRootId() string {
}
var config = driver.Config{
Name: "MoPan",
// DefaultRoot: "root, / or other",
Name: "MoPan",
CheckStatus: true,
Alert: "warning|This network disk may store your password in clear text. Please set your password carefully",
}

View File

@ -73,7 +73,7 @@ func (d *NeteaseMusic) List(ctx context.Context, dir model.Obj, args model.ListA
func (d *NeteaseMusic) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
if lrc, ok := file.(*LyricObj); ok {
if args.Type == "parsed" {
if args.Type == "parsed" && !args.Redirect {
return lrc.getLyricLink(), nil
} else {
return lrc.getProxyLink(ctx), nil

View File

@ -10,6 +10,7 @@ import (
"github.com/OpenListTeam/OpenList/v4/internal/driver"
"github.com/OpenListTeam/OpenList/v4/internal/model"
"github.com/OpenListTeam/OpenList/v4/internal/sign"
"github.com/OpenListTeam/OpenList/v4/internal/stream"
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
"github.com/OpenListTeam/OpenList/v4/pkg/utils/random"
"github.com/OpenListTeam/OpenList/v4/server/common"
@ -54,7 +55,9 @@ func (lrc *LyricObj) getProxyLink(ctx context.Context) *model.Link {
func (lrc *LyricObj) getLyricLink() *model.Link {
return &model.Link{
MFile: strings.NewReader(lrc.lyric),
RangeReader: &model.FileRangeReader{
RangeReaderIF: stream.GetRangeReaderFromMFile(int64(len(lrc.lyric)), strings.NewReader(lrc.lyric)),
},
}
}

View File

@ -22,7 +22,6 @@ var config = driver.Config{
OnlyProxy: true,
NoUpload: true,
DefaultRoot: "/",
CheckStatus: false,
}
func init() {

View File

@ -17,9 +17,8 @@ type Addition struct {
}
var config = driver.Config{
Name: "PikPak",
LocalSort: true,
DefaultRoot: "",
Name: "PikPak",
LocalSort: true,
}
func init() {

View File

@ -15,10 +15,9 @@ type Addition struct {
}
var config = driver.Config{
Name: "PikPakShare",
LocalSort: true,
NoUpload: true,
DefaultRoot: "",
Name: "PikPakShare",
LocalSort: true,
NoUpload: true,
}
func init() {

View File

@ -28,7 +28,7 @@ func init() {
return &QuarkOpen{
config: driver.Config{
Name: "QuarkOpen",
OnlyLocal: true,
OnlyProxy: true,
DefaultRoot: "0",
NoOverwriteUpload: true,
},

View File

@ -27,7 +27,6 @@ func init() {
return &QuarkOrUC{
config: driver.Config{
Name: "Quark",
OnlyLocal: false,
DefaultRoot: "0",
NoOverwriteUpload: true,
},
@ -43,7 +42,7 @@ func init() {
return &QuarkOrUC{
config: driver.Config{
Name: "UC",
OnlyLocal: true,
OnlyProxy: true,
DefaultRoot: "0",
NoOverwriteUpload: true,
},

View File

@ -30,7 +30,6 @@ func init() {
return &QuarkUCTV{
config: driver.Config{
Name: "QuarkTV",
OnlyLocal: false,
DefaultRoot: "0",
NoOverwriteUpload: true,
NoUpload: true,
@ -49,7 +48,6 @@ func init() {
return &QuarkUCTV{
config: driver.Config{
Name: "UCTV",
OnlyLocal: false,
DefaultRoot: "0",
NoOverwriteUpload: true,
NoUpload: true,

View File

@ -4,7 +4,6 @@ import (
"bytes"
"context"
"fmt"
"io"
"net/url"
stdpath "path"
"strings"
@ -158,7 +157,7 @@ func (d *S3) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) e
Name: getPlaceholderName(d.Placeholder),
Modified: time.Now(),
},
Reader: io.NopCloser(bytes.NewReader([]byte{})),
Reader: bytes.NewReader([]byte{}),
Mimetype: "application/octet-stream",
}, func(float64) {})
}

View File

@ -30,7 +30,7 @@ func (d *SFTP) GetAddition() driver.Additional {
}
func (d *SFTP) Init(ctx context.Context) error {
return d.initClient()
return d._initClient()
}
func (d *SFTP) Drop(ctx context.Context) error {
@ -63,6 +63,14 @@ func (d *SFTP) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*
if err != nil {
return nil, err
}
if remoteFile != nil && !d.Config().OnlyLinkMFile {
return &model.Link{
RangeReader: &model.FileRangeReader{
RangeReaderIF: stream.RateLimitRangeReaderFunc(stream.GetRangeReaderFromMFile(file.GetSize(), remoteFile)),
},
SyncClosers: utils.NewSyncClosers(remoteFile),
}, nil
}
return &model.Link{
MFile: &stream.RateLimitFile{
File: remoteFile,

View File

@ -16,11 +16,12 @@ type Addition struct {
}
var config = driver.Config{
Name: "SFTP",
LocalSort: true,
OnlyLocal: true,
DefaultRoot: "/",
CheckStatus: true,
Name: "SFTP",
LocalSort: true,
OnlyLinkMFile: false,
DefaultRoot: "/",
CheckStatus: true,
NoLinkURL: true,
}
func init() {

View File

@ -1,8 +1,10 @@
package sftp
import (
"fmt"
"path"
"github.com/OpenListTeam/OpenList/v4/pkg/singleflight"
"github.com/pkg/sftp"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
@ -11,6 +13,12 @@ import (
// do others that not defined in Driver interface
func (d *SFTP) initClient() error {
err, _, _ := singleflight.ErrorGroup.Do(fmt.Sprintf("SFTP.initClient:%p", d), func() (error, error) {
return d._initClient(), nil
})
return err
}
func (d *SFTP) _initClient() error {
var auth ssh.AuthMethod
if len(d.PrivateKey) > 0 {
var err error
@ -52,7 +60,9 @@ func (d *SFTP) clientReconnectOnConnectionError() error {
return nil
}
log.Debugf("[sftp] discarding closed sftp connection: %v", err)
_ = d.client.Close()
if d.client != nil {
_ = d.client.Close()
}
err = d.initClient()
return err
}

View File

@ -30,10 +30,10 @@ func (d *SMB) GetAddition() driver.Additional {
}
func (d *SMB) Init(ctx context.Context) error {
if strings.Index(d.Addition.Address, ":") < 0 {
if !strings.Contains(d.Addition.Address, ":") {
d.Addition.Address = d.Addition.Address + ":445"
}
return d.initFS()
return d._initFS()
}
func (d *SMB) Drop(ctx context.Context) error {
@ -81,6 +81,13 @@ func (d *SMB) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*m
return nil, err
}
d.updateLastConnTime()
if remoteFile != nil && !d.Config().OnlyLinkMFile {
return &model.Link{
RangeReader: &model.FileRangeReader{
RangeReaderIF: stream.RateLimitRangeReaderFunc(stream.GetRangeReaderFromMFile(file.GetSize(), remoteFile)),
},
}, nil
}
return &model.Link{
MFile: &stream.RateLimitFile{
File: remoteFile,

View File

@ -14,11 +14,12 @@ type Addition struct {
}
var config = driver.Config{
Name: "SMB",
LocalSort: true,
OnlyLocal: true,
DefaultRoot: ".",
NoCache: true,
Name: "SMB",
LocalSort: true,
OnlyLinkMFile: false,
DefaultRoot: ".",
NoCache: true,
NoLinkURL: true,
}
func init() {

View File

@ -1,6 +1,7 @@
package smb
import (
"fmt"
"io/fs"
"net"
"os"
@ -8,6 +9,7 @@ import (
"sync/atomic"
"time"
"github.com/OpenListTeam/OpenList/v4/pkg/singleflight"
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
"github.com/hirochachacha/go-smb2"
@ -26,6 +28,12 @@ func (d *SMB) getLastConnTime() time.Time {
}
func (d *SMB) initFS() error {
err, _, _ := singleflight.ErrorGroup.Do(fmt.Sprintf("SMB.initFS:%p", d), func() (error, error) {
return d._initFS(), nil
})
return err
}
func (d *SMB) _initFS() error {
conn, err := net.Dial("tcp", d.Address)
if err != nil {
return err

View File

@ -13,13 +13,14 @@ type Addition struct {
}
var config = driver.Config{
Name: "Strm",
LocalSort: true,
NoCache: true,
NoUpload: true,
DefaultRoot: "/",
OnlyLocal: true,
OnlyProxy: true,
Name: "Strm",
LocalSort: true,
NoCache: true,
NoUpload: true,
DefaultRoot: "/",
OnlyLinkMFile: true,
OnlyProxy: true,
NoLinkURL: true,
}
func init() {

View File

@ -16,7 +16,7 @@ type Addition struct {
var config = driver.Config{
Name: "Template",
LocalSort: false,
OnlyLocal: false,
OnlyLinkMFile: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
@ -25,6 +25,7 @@ var config = driver.Config{
CheckStatus: false,
Alert: "",
NoOverwriteUpload: false,
NoLinkURL: false,
}
func init() {

View File

@ -85,7 +85,6 @@ func (i *Addition) GetIdentity() string {
var config = driver.Config{
Name: "ThunderX",
LocalSort: true,
OnlyProxy: false,
}
var configExpert = driver.Config{

View File

@ -16,17 +16,10 @@ type Addition struct {
}
var config = driver.Config{
Name: "UrlTree",
LocalSort: true,
OnlyLocal: false,
OnlyProxy: false,
NoCache: true,
NoUpload: false,
NeedMs: false,
DefaultRoot: "",
CheckStatus: true,
Alert: "",
NoOverwriteUpload: false,
Name: "UrlTree",
LocalSort: true,
NoCache: true,
CheckStatus: true,
}
func init() {

View File

@ -14,11 +14,11 @@ type Addition struct {
}
var config = driver.Config{
Name: "Virtual",
OnlyLocal: true,
LocalSort: true,
NeedMs: true,
//NoCache: true,
Name: "Virtual",
OnlyLinkMFile: true,
LocalSort: true,
NeedMs: true,
NoLinkURL: true,
}
func init() {

View File

@ -14,12 +14,9 @@ type Addition struct {
}
var config = driver.Config{
Name: "WeiYun",
LocalSort: false,
OnlyProxy: true,
CheckStatus: true,
Alert: "",
NoOverwriteUpload: false,
Name: "WeiYun",
OnlyProxy: true,
CheckStatus: true,
}
func init() {

View File

@ -18,15 +18,7 @@ type Addition struct {
var config = driver.Config{
Name: "WoPan",
LocalSort: false,
OnlyLocal: false,
OnlyProxy: false,
NoCache: false,
NoUpload: false,
NeedMs: false,
DefaultRoot: "0",
CheckStatus: false,
Alert: "",
NoOverwriteUpload: true,
}