From 317d190b7713392d342e61046eb4a43ef90cc871 Mon Sep 17 00:00:00 2001 From: j2rong4cn <36783515+j2rong4cn@users.noreply.github.com> Date: Wed, 6 Aug 2025 20:35:01 +0800 Subject: [PATCH] fix(ftp): create a new connection for each download (#989) --- drivers/ftp/driver.go | 50 +++++++++++++++++++++---------------------- drivers/ftp/util.go | 29 ------------------------- 2 files changed, 24 insertions(+), 55 deletions(-) diff --git a/drivers/ftp/driver.go b/drivers/ftp/driver.go index 0ed6ac2a..f8d0e6ef 100644 --- a/drivers/ftp/driver.go +++ b/drivers/ftp/driver.go @@ -2,10 +2,9 @@ package ftp import ( "context" + "errors" "io" stdpath "path" - "sync" - "time" "github.com/OpenListTeam/OpenList/v4/internal/driver" "github.com/OpenListTeam/OpenList/v4/internal/errs" @@ -72,45 +71,44 @@ func (d *FTP) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]m return res, nil } -func (d *FTP) Link(_ context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { - ctx, cancel := context.WithCancel(context.Background()) +func (d *FTP) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { conn, err := d._login(ctx) if err != nil { - cancel() return nil, err } - close := func() error { - _ = conn.Quit() - cancel() - return nil - } path := encode(file.GetPath(), d.Encoding) size := file.GetSize() - mu := &sync.Mutex{} resultRangeReader := func(context context.Context, httpRange http_range.Range) (io.ReadCloser, error) { length := httpRange.Length if length < 0 || httpRange.Start+length > size { length = size - httpRange.Start } - mu.Lock() - defer mu.Unlock() - r, err := conn.RetrFrom(path, uint64(httpRange.Start)) - if err != nil { - _ = conn.Quit() - conn, err = d._login(ctx) - if err == nil { - r, err = conn.RetrFrom(path, uint64(httpRange.Start)) - } + var c *ftp.ServerConn + if ctx == context { + c = conn + } else { + var err error + c, err = d._login(context) if err != nil { return nil, err } } - r.SetDeadline(time.Now().Add(time.Second)) - return &FileReader{ - Response: r, - Reader: io.LimitReader(r, length), - ctx: context, + resp, err := c.RetrFrom(path, uint64(httpRange.Start)) + if err != nil { + return nil, err + } + var close utils.CloseFunc + if context == ctx { + close = resp.Close + } else { + close = func() error { + return errors.Join(resp.Close(), c.Quit()) + } + } + return utils.ReadCloser{ + Reader: io.LimitReader(resp, length), + Closer: close, }, nil } @@ -118,7 +116,7 @@ func (d *FTP) Link(_ context.Context, file model.Obj, args model.LinkArgs) (*mod RangeReader: &model.FileRangeReader{ RangeReaderIF: stream.RateLimitRangeReaderFunc(resultRangeReader), }, - SyncClosers: utils.NewSyncClosers(utils.CloseFunc(close)), + SyncClosers: utils.NewSyncClosers(utils.CloseFunc(conn.Quit)), }, nil } diff --git a/drivers/ftp/util.go b/drivers/ftp/util.go index 5945a218..61c59f14 100644 --- a/drivers/ftp/util.go +++ b/drivers/ftp/util.go @@ -2,14 +2,10 @@ package ftp import ( "context" - "errors" "fmt" - "io" - "os" "time" "github.com/OpenListTeam/OpenList/v4/pkg/singleflight" - "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/jlaffaye/ftp" ) @@ -45,28 +41,3 @@ func (d *FTP) _login(ctx context.Context) (*ftp.ServerConn, error) { } return conn, nil } - -type FileReader struct { - *ftp.Response - io.Reader - ctx context.Context -} - -func (r *FileReader) Read(buf []byte) (int, error) { - n := 0 - for n < len(buf) { - w, err := r.Reader.Read(buf[n:]) - if utils.IsCanceled(r.ctx) { - return n, r.ctx.Err() - } - n += w - if errors.Is(err, os.ErrDeadlineExceeded) { - r.Response.SetDeadline(time.Now().Add(time.Second)) - continue - } - if err != nil || w == 0 { - return n, err - } - } - return n, nil -}