Files
gopeed/internal/protocol/ftp/fetcher_manager.go
T

110 lines
2.9 KiB
Go

package ftp
import (
"crypto/tls"
"net/url"
"path"
"strings"
"github.com/GopeedLab/gopeed/internal/fetcher"
"github.com/GopeedLab/gopeed/pkg/base"
pftp "github.com/GopeedLab/gopeed/pkg/protocol/ftp"
)
// fetcherData is what a task saves to resume later. Segments has the same
// Begin, End and Downloaded fields every version writes; the other fields are
// optional, so a save without them still restores.
type fetcherData struct {
Segments []*segment
// MaxConns is the login ceiling the server enforced, 0 when none was hit.
MaxConns int `json:",omitempty"`
// NoRest records that the server refused REST, so the task downloads each
// file in one sequential stream.
NoRest bool `json:",omitempty"`
}
// FetcherManager handles ftp://, ftps:// (implicit TLS) and ftpes:// (explicit
// TLS) URLs.
type FetcherManager struct {
// baseTLS is the base for every TLS connection. Nil means the system
// roots; the package's tests set it to trust their own certificate. The
// task's skipVerifyCert still turns verification off.
baseTLS *tls.Config
}
func (fm *FetcherManager) Name() string {
return "ftp"
}
func (fm *FetcherManager) Filters() []*fetcher.SchemeFilter {
return []*fetcher.SchemeFilter{
{Type: fetcher.FilterTypeUrl, Pattern: "FTP"},
{Type: fetcher.FilterTypeUrl, Pattern: "FTPS"},
{Type: fetcher.FilterTypeUrl, Pattern: "FTPES"},
}
}
func (fm *FetcherManager) Build() fetcher.Fetcher {
return &Fetcher{manager: fm}
}
// ParseName names a task before it is resolved. It never includes the
// userinfo of the URL.
func (fm *FetcherManager) ParseName(u string) string {
parsed, err := url.Parse(u)
if err != nil {
return ""
}
name := path.Base(strings.TrimSuffix(parsed.Path, "/"))
if name == "" || name == "/" || name == "." {
name = parsed.Hostname()
}
return name
}
func (fm *FetcherManager) AutoRename() bool {
return true
}
func (fm *FetcherManager) DefaultConfig() any {
return &config{Connections: defaultConnections}
}
func (fm *FetcherManager) Store(f fetcher.Fetcher) (any, error) {
ff := f.(*Fetcher)
ff.mu.Lock()
defer ff.mu.Unlock()
segments := make([]*segment, len(ff.segments))
for i, s := range ff.segments {
c := *s
segments[i] = &c
}
return &fetcherData{
Segments: segments,
MaxConns: ff.maxConns,
NoRest: ff.noRest,
}, nil
}
func (fm *FetcherManager) Restore() (v any, f func(meta *fetcher.FetcherMeta, v any) fetcher.Fetcher) {
return &fetcherData{}, func(meta *fetcher.FetcherMeta, v any) fetcher.Fetcher {
fd := v.(*fetcherData)
ff := fm.Build().(*Fetcher)
ff.meta = meta
if meta != nil && meta.Req != nil {
_ = base.ParseReqExtra[pftp.ReqExtra](meta.Req)
}
if meta != nil && meta.Opts != nil {
_ = base.ParseOptExtra[pftp.OptsExtra](meta.Opts)
}
ff.segments = fd.Segments
ff.maxConns = fd.MaxConns
ff.noRest = fd.NoRest
return ff
}
}
func (fm *FetcherManager) Close() error {
return nil
}