mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 23:57:54 +00:00
丰富单元测试
This commit is contained in:
1 parent
dd47b52952
commit
df2dbca475
6 files changed
+345
-113
No files matched your search
@@ -36,10 +36,9 @@ type Options struct {
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
Name string
|
||||
Path string
|
||||
Size int64
|
||||
Downloaded int64
|
||||
Name string
|
||||
Path string
|
||||
Size int64
|
||||
}
|
||||
|
||||
type Process interface {
|
||||
@@ -53,25 +52,42 @@ type Controller struct {
|
||||
Files map[string]*os.File
|
||||
}
|
||||
|
||||
func (c *Controller) Touch(name string, size int64) error {
|
||||
func NewController() *Controller {
|
||||
return &Controller{Files: make(map[string]*os.File)}
|
||||
}
|
||||
|
||||
func (c *Controller) Touch(name string, size int64) (file *os.File, err error) {
|
||||
if size > 0 {
|
||||
return os.Truncate(name, size)
|
||||
err := os.Truncate(name, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file, err = os.OpenFile(name, os.O_RDWR, 0666)
|
||||
} else {
|
||||
file, err = os.Create(name)
|
||||
}
|
||||
_, err := os.Create(name)
|
||||
return err
|
||||
if err == nil {
|
||||
c.Files[name] = file
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Controller) Open(name string) (file *os.File, err error) {
|
||||
file, err = os.OpenFile(name, os.O_RDWR, 0666)
|
||||
if err == nil {
|
||||
c.Files[name] = file
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Controller) Write(name string, offset int64, buf []byte) (int, error) {
|
||||
file, ok := c.Files[name]
|
||||
if !ok {
|
||||
var err error
|
||||
file, err = os.OpenFile(name, os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
c.Files[name] = file
|
||||
}
|
||||
return file.WriteAt(buf, offset)
|
||||
return c.Files[name].WriteAt(buf, offset)
|
||||
}
|
||||
|
||||
func (c *Controller) Close(name string) error {
|
||||
err := c.Files[name].Close()
|
||||
delete(c.Files, name)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Controller) ContextDialer() (proxy.Dialer, error) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/monkeyWie/gopeed/download/common"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -26,7 +25,7 @@ type Downloader struct {
|
||||
}
|
||||
|
||||
func NewDownloader(fetchers ...common.Fetcher) *Downloader {
|
||||
d := &Downloader{Controller: &common.Controller{Files: make(map[string]*os.File)}}
|
||||
d := &Downloader{Controller: common.NewController()}
|
||||
d.fetches = make(map[string]common.Fetcher)
|
||||
for _, f := range fetchers {
|
||||
for _, p := range f.Protocols() {
|
||||
|
||||
@@ -2,7 +2,6 @@ package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/monkeyWie/gopeed/download/common"
|
||||
"github.com/monkeyWie/gopeed/download/http/model"
|
||||
@@ -16,10 +15,27 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type RequestError struct {
|
||||
Code int
|
||||
Msg string
|
||||
}
|
||||
|
||||
func NewRequestError(code int, msg string) *RequestError {
|
||||
return &RequestError{Code: code, Msg: msg}
|
||||
}
|
||||
|
||||
func (re *RequestError) Error() string {
|
||||
return fmt.Sprintf("http request fail,code:%d", re.Code)
|
||||
}
|
||||
|
||||
type Fetcher struct {
|
||||
*common.BaseFetcher
|
||||
}
|
||||
|
||||
func NewFetcher() *Fetcher {
|
||||
return &Fetcher{BaseFetcher: &common.BaseFetcher{}}
|
||||
}
|
||||
|
||||
func (h *Fetcher) Protocols() []string {
|
||||
return []string{"HTTP", "HTTPS"}
|
||||
}
|
||||
@@ -36,7 +52,8 @@ func (h *Fetcher) Resolve(req *common.Request) (*common.Resource, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer httpResp.Body.Close()
|
||||
// 拿到响应头就关闭,不用加defer
|
||||
httpResp.Body.Close()
|
||||
res := &common.Resource{
|
||||
Req: req,
|
||||
Range: false,
|
||||
@@ -57,13 +74,15 @@ func (h *Fetcher) Resolve(req *common.Request) (*common.Resource, error) {
|
||||
} else if common.HttpCodeOK == httpResp.StatusCode {
|
||||
// 返回200响应码,不支持断点下载,通过Content-Length头获取文件大小,获取不到的话可能是chunked编码
|
||||
contentLength := httpResp.Header.Get(common.HttpHeaderContentLength)
|
||||
parse, err := strconv.ParseInt(contentLength, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if contentLength != "" {
|
||||
parse, err := strconv.ParseInt(contentLength, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.Size = parse
|
||||
}
|
||||
res.Size = parse
|
||||
} else {
|
||||
return nil, errors.New("http request fail")
|
||||
return nil, NewRequestError(httpResp.StatusCode, httpResp.Status)
|
||||
}
|
||||
file := &common.FileInfo{
|
||||
Size: res.Size,
|
||||
|
||||
+195
-73
@@ -1,41 +1,171 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"github.com/monkeyWie/gopeed/download/common"
|
||||
"golang.org/x/net/proxy"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func startMockServer() net.Listener {
|
||||
const testDir = "./"
|
||||
const buildSize = 200 * 1024 * 1024
|
||||
const buildName = "build.data"
|
||||
const buildFile = testDir + buildName
|
||||
const downloadName = "download.data"
|
||||
const downloadFile = testDir + downloadName
|
||||
|
||||
func TestFetcher_Resolve(t *testing.T) {
|
||||
testResolve(startTestFileServer, &common.Resource{
|
||||
Size: buildSize,
|
||||
Range: true,
|
||||
Files: []*common.FileInfo{
|
||||
{
|
||||
Name: buildName,
|
||||
Size: buildSize,
|
||||
},
|
||||
},
|
||||
}, t)
|
||||
testResolve(startTestChunkedServer, &common.Resource{
|
||||
Size: 0,
|
||||
Range: false,
|
||||
Files: []*common.FileInfo{
|
||||
{
|
||||
Name: buildName,
|
||||
Size: 0,
|
||||
},
|
||||
},
|
||||
}, t)
|
||||
}
|
||||
|
||||
func testResolve(startTestServer func() net.Listener, want *common.Resource, t *testing.T) {
|
||||
listener := startTestServer()
|
||||
defer listener.Close()
|
||||
fetcher := NewFetcher()
|
||||
res, err := fetcher.Resolve(&common.Request{
|
||||
URL: "http://" + listener.Addr().String() + "/" + buildName,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res.Req = nil
|
||||
if !reflect.DeepEqual(want, res) {
|
||||
t.Errorf("Resolve error = %v, want %v", res, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetcher_DownloadNormal(t *testing.T) {
|
||||
listener := startTestFileServer()
|
||||
defer listener.Close()
|
||||
// 正常下载
|
||||
downloadNormal(listener, 1, t)
|
||||
downloadNormal(listener, 5, t)
|
||||
downloadNormal(listener, 8, t)
|
||||
downloadNormal(listener, 16, t)
|
||||
}
|
||||
|
||||
func TestFetcher_DownloadContinue(t *testing.T) {
|
||||
listener := startTestFileServer()
|
||||
defer listener.Close()
|
||||
// 暂停继续
|
||||
//downloadContinue(listener, 1, t)
|
||||
downloadContinue(listener, 5, t)
|
||||
//downloadContinue(listener, 8, t)
|
||||
//downloadContinue(listener, 16, t)
|
||||
}
|
||||
|
||||
func TestFetcher_DownloadChunked(t *testing.T) {
|
||||
listener := startTestChunkedServer()
|
||||
defer listener.Close()
|
||||
// chunked编码下载
|
||||
downloadNormal(listener, 1, t)
|
||||
downloadContinue(listener, 1, t)
|
||||
}
|
||||
|
||||
func TestFetcher_DownloadRetry(t *testing.T) {
|
||||
listener := startTestRetryServer()
|
||||
defer listener.Close()
|
||||
// chunked编码下载
|
||||
downloadNormal(listener, 1, t)
|
||||
}
|
||||
|
||||
func startTestFileServer() net.Listener {
|
||||
return startTestServer(func() http.Handler {
|
||||
return http.FileServer(http.Dir(testDir))
|
||||
})
|
||||
}
|
||||
|
||||
func startTestChunkedServer() net.Listener {
|
||||
return startTestServer(func() http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/"+buildName, func(writer http.ResponseWriter, request *http.Request) {
|
||||
file, err := os.Open(buildFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
io.Copy(writer, file)
|
||||
})
|
||||
return mux
|
||||
})
|
||||
}
|
||||
|
||||
func startTestRetryServer() net.Listener {
|
||||
counter := 0
|
||||
return startTestServer(func() http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/"+buildName, func(writer http.ResponseWriter, request *http.Request) {
|
||||
counter++
|
||||
if counter != 1 && counter < 5 {
|
||||
writer.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
file, err := os.Open(buildFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
io.Copy(writer, file)
|
||||
})
|
||||
return mux
|
||||
})
|
||||
}
|
||||
|
||||
func startTestServer(serverHandle func() http.Handler) net.Listener {
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
file, err := os.Create("./test.data")
|
||||
file, err := os.Create(buildFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf := make([]byte, 1024)
|
||||
for i := 0; i < 20*1024; i++ {
|
||||
//随机生成一个文件
|
||||
l := int64(8192)
|
||||
buf := make([]byte, l)
|
||||
size := int64(0)
|
||||
for {
|
||||
_, err := rand.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
file.WriteAt(buf, int64(i*1024))
|
||||
if size+l >= buildSize {
|
||||
file.WriteAt(buf[0:buildSize-size], size)
|
||||
break
|
||||
}
|
||||
file.WriteAt(buf, size)
|
||||
size += l
|
||||
}
|
||||
server := &http.Server{}
|
||||
server.Handler = serverHandle()
|
||||
go server.Serve(listener)
|
||||
|
||||
go func() {
|
||||
http.Serve(listener, http.FileServer(http.Dir("./")))
|
||||
}()
|
||||
return &delFileListener{
|
||||
File: file,
|
||||
Listener: listener,
|
||||
@@ -48,93 +178,85 @@ type delFileListener struct {
|
||||
}
|
||||
|
||||
func (c *delFileListener) Close() error {
|
||||
c.File.Close()
|
||||
err := os.Remove(c.File.Name())
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
c.File.Close()
|
||||
os.Remove(c.File.Name())
|
||||
os.Remove(downloadFile)
|
||||
}()
|
||||
return c.Listener.Close()
|
||||
}
|
||||
|
||||
func TestFetcher_Resolve(t *testing.T) {
|
||||
listener := startMockServer()
|
||||
defer listener.Close()
|
||||
fetcher := &Fetcher{}
|
||||
resolve, err := fetcher.Resolve(&common.Request{
|
||||
URL: "http://" + listener.Addr().String() + "/test.data",
|
||||
func downloadReady(listener net.Listener, connections int, t *testing.T) common.Process {
|
||||
fetcher := NewFetcher()
|
||||
fetcher.InitCtl(common.NewController())
|
||||
res, err := fetcher.Resolve(&common.Request{
|
||||
URL: "http://" + listener.Addr().String() + "/" + buildName,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
buf, err := json.Marshal(resolve)
|
||||
process, err := fetcher.Create(res, &common.Options{
|
||||
Name: downloadName,
|
||||
Path: testDir,
|
||||
Connections: connections,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%s\n", string(buf))
|
||||
return process
|
||||
|
||||
}
|
||||
|
||||
func Test2(t *testing.T) {
|
||||
socks5, err := proxy.SOCKS5("tcp", "127.0.0.1:1080", nil, nil)
|
||||
func downloadNormal(listener net.Listener, connections int, t *testing.T) {
|
||||
process := downloadReady(listener, connections, t)
|
||||
err := process.Start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conn, err := socks5.Dial("tcp", "www.baidu.com:80")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
want := fileMd5(buildFile)
|
||||
got := fileMd5(downloadFile)
|
||||
if want != got {
|
||||
t.Errorf("Download error = %v, want %v", got, want)
|
||||
}
|
||||
conn.Write([]byte("GET"))
|
||||
}
|
||||
|
||||
func Test3(t *testing.T) {
|
||||
var u User
|
||||
fmt.Println((&u).Say1())
|
||||
fmt.Println(u.Say2())
|
||||
}
|
||||
|
||||
func Test4(t *testing.T) {
|
||||
resp, err := http.Get("http://192.168.200.163:8088/go1.12.7.linux-amd64.tar.gz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
func downloadContinue(listener net.Listener, connections int, t *testing.T) {
|
||||
process := downloadReady(listener, connections, t)
|
||||
go func() {
|
||||
time.Sleep(time.Second * 3)
|
||||
err2 := resp.Body.Close()
|
||||
if err2 != nil {
|
||||
fmt.Println("close err2:" + err2.Error())
|
||||
err := process.Start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
_, err = io.Copy(ioutil.Discard, resp.Body)
|
||||
if err != nil {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
if err := process.Pause(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
if err := process.Continue(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := fileMd5(buildFile)
|
||||
got := fileMd5(downloadFile)
|
||||
if want != got {
|
||||
t.Errorf("Download error = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func Test5(t *testing.T) {
|
||||
name := "E:\\test\\gopeed\\http\\test.txt"
|
||||
err := os.Truncate(name, 10)
|
||||
func fileMd5(filePath string) string {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
panic(err)
|
||||
}
|
||||
file, err := os.OpenFile(name, os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = file.WriteAt([]byte("test"), 5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
// Tell the program to call the following function when the current function returns
|
||||
defer file.Close()
|
||||
|
||||
// Open a new hash interface to write to
|
||||
hash := md5.New()
|
||||
|
||||
// Copy the file in the hash interface and check for any error
|
||||
if _, err := io.Copy(hash, file); err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type User struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (u *User) Say1() string {
|
||||
return "hello1 " + u.name
|
||||
}
|
||||
|
||||
func (u User) Say2() string {
|
||||
return "hello2 " + u.name
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
common2 "github.com/monkeyWie/gopeed/download/common"
|
||||
"github.com/monkeyWie/gopeed/download/common"
|
||||
)
|
||||
|
||||
type Chunk struct {
|
||||
Status common2.Status
|
||||
Status common.Status
|
||||
Begin int64
|
||||
End int64
|
||||
Downloaded int64
|
||||
@@ -13,7 +13,7 @@ type Chunk struct {
|
||||
|
||||
func NewChunk(begin int64, end int64) *Chunk {
|
||||
return &Chunk{
|
||||
Status: common2.DownloadStatusReady,
|
||||
Status: common.DownloadStatusReady,
|
||||
Begin: begin,
|
||||
End: end,
|
||||
}
|
||||
|
||||
+86
-10
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Process struct {
|
||||
@@ -17,6 +18,8 @@ type Process struct {
|
||||
status common.Status
|
||||
clients []*http.Response
|
||||
chunks []*model.Chunk
|
||||
|
||||
pauseLock *sync.Mutex
|
||||
}
|
||||
|
||||
func NewProcess(fetcher *Fetcher, res *common.Resource, opts *common.Options) *Process {
|
||||
@@ -25,6 +28,8 @@ func NewProcess(fetcher *Fetcher, res *common.Resource, opts *common.Options) *P
|
||||
res: res,
|
||||
opts: opts,
|
||||
status: common.DownloadStatusReady,
|
||||
|
||||
pauseLock: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +37,14 @@ func (p *Process) Start() error {
|
||||
ctl := p.fetcher.GetCtl()
|
||||
// 创建文件
|
||||
name := p.name()
|
||||
err := ctl.Touch(name, p.res.Size)
|
||||
_, err := ctl.Touch(name, p.res.Size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p.res.Range && p.res.Size > 0 {
|
||||
defer p.close()
|
||||
p.status = common.DownloadStatusStart
|
||||
var fetchErr error
|
||||
if p.res.Range {
|
||||
// 每个连接平均需要下载的分块大小
|
||||
var (
|
||||
chunkSize = p.res.Size / int64(p.opts.Connections)
|
||||
@@ -62,12 +70,27 @@ func (p *Process) Start() error {
|
||||
errCh <- p.fetchChunk(i, name, chunk)
|
||||
}(i)
|
||||
}
|
||||
return p.wait(errCh)
|
||||
fetchErr = p.wait(errCh)
|
||||
} else {
|
||||
// 只支持单连接下载
|
||||
p.chunks = make([]*model.Chunk, 1)
|
||||
p.clients = make([]*http.Response, 1)
|
||||
p.chunks[0] = model.NewChunk(0, 0)
|
||||
fetchErr = p.fetchChunk(0, name, p.chunks[0])
|
||||
}
|
||||
return nil
|
||||
if p.status == common.DownloadStatusPause {
|
||||
return nil
|
||||
}
|
||||
return fetchErr
|
||||
}
|
||||
|
||||
func (p *Process) Pause() error {
|
||||
p.pauseLock.Lock()
|
||||
defer p.pauseLock.Unlock()
|
||||
if common.DownloadStatusStart != p.status {
|
||||
return nil
|
||||
}
|
||||
p.status = common.DownloadStatusPause
|
||||
if len(p.clients) > 0 {
|
||||
for _, client := range p.clients {
|
||||
client.Body.Close()
|
||||
@@ -77,10 +100,28 @@ func (p *Process) Pause() error {
|
||||
}
|
||||
|
||||
func (p *Process) Continue() error {
|
||||
if func() bool {
|
||||
p.pauseLock.Lock()
|
||||
defer p.pauseLock.Unlock()
|
||||
if common.DownloadStatusPause != p.status && common.DownloadStatusError != p.status {
|
||||
return true
|
||||
}
|
||||
p.status = common.DownloadStatusStart
|
||||
return false
|
||||
}() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
ctl = p.fetcher.GetCtl()
|
||||
name = p.name()
|
||||
errCh = make(chan error)
|
||||
)
|
||||
_, err := ctl.Open(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ctl.Close(name)
|
||||
for i := 0; i < p.opts.Connections; i++ {
|
||||
go func(i int) {
|
||||
errCh <- p.fetchChunk(i, name, p.chunks[i])
|
||||
@@ -93,6 +134,10 @@ func (p *Process) Delete() error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (p *Process) close() error {
|
||||
return p.fetcher.GetCtl().Close(p.name())
|
||||
}
|
||||
|
||||
func (p *Process) name() string {
|
||||
// 创建文件
|
||||
var filename = p.opts.Name
|
||||
@@ -120,6 +165,14 @@ func (p *Process) wait(errCh <-chan error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type action int
|
||||
|
||||
const (
|
||||
actionDirect action = iota
|
||||
actionContinue
|
||||
actionReturn
|
||||
)
|
||||
|
||||
func (p *Process) fetchChunk(index int, name string, chunk *model.Chunk) (err error) {
|
||||
httpReq, err := BuildRequest(p.res.Req)
|
||||
if err != nil {
|
||||
@@ -135,14 +188,37 @@ func (p *Process) fetchChunk(index int, name string, chunk *model.Chunk) (err er
|
||||
resp *http.Response
|
||||
retry bool
|
||||
)
|
||||
httpReq.Header.Set(common.HttpHeaderRange,
|
||||
fmt.Sprintf(common.HttpHeaderRangeFormat, chunk.Begin+chunk.Downloaded, chunk.End))
|
||||
resp, err = client.Do(httpReq)
|
||||
if err != nil {
|
||||
// 连接失败,直接重试
|
||||
if p.res.Range {
|
||||
httpReq.Header.Set(common.HttpHeaderRange,
|
||||
fmt.Sprintf(common.HttpHeaderRangeFormat, chunk.Begin+chunk.Downloaded, chunk.End))
|
||||
} else {
|
||||
chunk.Downloaded = 0
|
||||
}
|
||||
var act action
|
||||
act, err = func() (action, error) {
|
||||
p.pauseLock.Lock()
|
||||
defer p.pauseLock.Unlock()
|
||||
if p.status == common.DownloadStatusPause {
|
||||
return actionReturn, nil
|
||||
}
|
||||
resp, err = client.Do(httpReq)
|
||||
if err != nil {
|
||||
// 连接失败,直接重试
|
||||
return actionContinue, err
|
||||
}
|
||||
if resp.StatusCode != common.HttpCodeOK && resp.StatusCode != common.HttpCodePartialContent {
|
||||
err = NewRequestError(resp.StatusCode, resp.Status)
|
||||
return actionContinue, err
|
||||
}
|
||||
p.clients[index] = resp
|
||||
return actionDirect, nil
|
||||
}()
|
||||
fmt.Printf("action:%d\n", act)
|
||||
if act == actionContinue {
|
||||
continue
|
||||
} else if act == actionReturn {
|
||||
return nil
|
||||
}
|
||||
p.clients[index] = resp
|
||||
retry, err = func() (bool, error) {
|
||||
defer resp.Body.Close()
|
||||
for {
|
||||
|
||||
Reference in new issue
Block a user