mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-10 02:20:28 +00:00
feat: integration torrent (#30)
This commit is contained in:
1 parent
43378c7dc8
commit
034137322f
20 files changed
+925
-139
No files matched your search
@@ -39,29 +39,14 @@ type Fetcher struct {
|
||||
res *base.Resource
|
||||
opts *base.Options
|
||||
status base.Status
|
||||
clients []*http.Response
|
||||
chunks []*Chunk
|
||||
clients []*http.Response
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
pauseCh chan interface{}
|
||||
}
|
||||
|
||||
func NewFetcher() *Fetcher {
|
||||
return &Fetcher{
|
||||
DefaultFetcher: new(fetcher.DefaultFetcher),
|
||||
pauseCh: make(chan interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
var protocols = []string{"HTTP", "HTTPS"}
|
||||
|
||||
func FetcherBuilder() ([]string, func() fetcher.Fetcher) {
|
||||
return protocols, func() fetcher.Fetcher {
|
||||
return NewFetcher()
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Fetcher) Resolve(req *base.Request) (*base.Resource, error) {
|
||||
httpReq, err := buildRequest(nil, req)
|
||||
if err != nil {
|
||||
@@ -91,7 +76,7 @@ func (f *Fetcher) Resolve(req *base.Request) (*base.Resource, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.TotalSize = parse
|
||||
res.Length = parse
|
||||
}
|
||||
} else if base.HttpCodeOK == httpResp.StatusCode {
|
||||
// 返回200响应码,不支持断点下载,通过Content-Length头获取文件大小,获取不到的话可能是chunked编码
|
||||
@@ -101,13 +86,13 @@ func (f *Fetcher) Resolve(req *base.Request) (*base.Resource, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.TotalSize = parse
|
||||
res.Length = parse
|
||||
}
|
||||
} else {
|
||||
return nil, NewRequestError(httpResp.StatusCode, httpResp.Status)
|
||||
}
|
||||
file := &base.FileInfo{
|
||||
Size: res.TotalSize,
|
||||
Size: res.Length,
|
||||
}
|
||||
contentDisposition := httpResp.Header.Get(base.HttpHeaderContentDisposition)
|
||||
if contentDisposition != "" {
|
||||
@@ -139,14 +124,14 @@ func (f *Fetcher) Create(res *base.Resource, opts *base.Options) error {
|
||||
func (f *Fetcher) Start() (err error) {
|
||||
// 创建文件
|
||||
name := f.filename()
|
||||
_, err = f.Ctl.Touch(name, f.res.TotalSize)
|
||||
_, err = f.Ctl.Touch(name, f.res.Length)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.status = base.DownloadStatusStart
|
||||
if f.res.Range {
|
||||
// 每个连接平均需要下载的分块大小
|
||||
chunkSize := f.res.TotalSize / int64(f.opts.Connections)
|
||||
chunkSize := f.res.Length / int64(f.opts.Connections)
|
||||
f.chunks = make([]*Chunk, f.opts.Connections)
|
||||
f.clients = make([]*http.Response, f.opts.Connections)
|
||||
for i := 0; i < f.opts.Connections; i++ {
|
||||
@@ -156,7 +141,7 @@ func (f *Fetcher) Start() (err error) {
|
||||
)
|
||||
if i == f.opts.Connections-1 {
|
||||
// 最后一个分块需要保证把文件下载完
|
||||
end = f.res.TotalSize - 1
|
||||
end = f.res.Length - 1
|
||||
} else {
|
||||
end = begin + chunkSize - 1
|
||||
}
|
||||
@@ -340,7 +325,7 @@ func buildClient() *http.Client {
|
||||
jar, _ := cookiejar.New(nil)
|
||||
return &http.Client{
|
||||
Jar: jar,
|
||||
Timeout: time.Second * 10,
|
||||
Timeout: time.Second * 60,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,3 +370,40 @@ func buildRequest(ctx context.Context, req *base.Request) (httpReq *http.Request
|
||||
httpReq.Header = headers
|
||||
return httpReq, nil
|
||||
}
|
||||
|
||||
type FetcherData struct {
|
||||
Chunks []*Chunk
|
||||
}
|
||||
|
||||
type FetcherBuilder struct {
|
||||
}
|
||||
|
||||
var schemes = []string{"HTTP", "HTTPS"}
|
||||
|
||||
func (fb *FetcherBuilder) Schemes() []string {
|
||||
return schemes
|
||||
}
|
||||
|
||||
func (fb *FetcherBuilder) Build() fetcher.Fetcher {
|
||||
return &Fetcher{
|
||||
DefaultFetcher: new(fetcher.DefaultFetcher),
|
||||
pauseCh: make(chan interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (fb *FetcherBuilder) Store(f fetcher.Fetcher) interface{} {
|
||||
_f := f.(*Fetcher)
|
||||
return &FetcherData{
|
||||
Chunks: _f.chunks,
|
||||
}
|
||||
}
|
||||
|
||||
func (fb *FetcherBuilder) Resume(res *base.Resource, opts *base.Options, data interface{}) fetcher.Fetcher {
|
||||
fetcher := new(FetcherBuilder).Build().(*Fetcher)
|
||||
fs := data.(*FetcherData)
|
||||
fetcher.res = res
|
||||
fetcher.opts = opts
|
||||
fetcher.chunks = fs.Chunks
|
||||
fetcher.status = base.DownloadStatusPause
|
||||
return fetcher
|
||||
}
|
||||
Reference in new issue
Block a user