From 6d136604dbc5fb80e3a68ffc35d267f6e66bb53c Mon Sep 17 00:00:00 2001 From: Tracey Lesley <45711711+MrGlp@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:43:12 +0800 Subject: [PATCH] feat: downloader task stats (#339) --- go.mod | 8 ++++---- go.sum | 14 +++++++------- internal/protocol/http/fetcher.go | 1 + pkg/download/downloader.go | 15 +++++++++++++-- pkg/download/model.go | 2 ++ pkg/rest/api.go | 15 +++++++++++++++ pkg/rest/server.go | 1 + 7 files changed, 43 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 7d9bab2e..b48b5cd1 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/matoous/go-nanoid/v2 v2.0.0 + github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.31.0 github.com/virtuald/go-paniclog v0.0.0-20190812204905-43a7fa316459 go.etcd.io/bbolt v1.3.8 @@ -89,7 +90,6 @@ require ( github.com/pion/udp v0.1.4 // indirect github.com/pion/webrtc/v3 v3.1.42 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/skeema/knownhosts v1.2.0 // indirect @@ -97,10 +97,10 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect go.opentelemetry.io/otel v1.8.0 // indirect go.opentelemetry.io/otel/trace v1.8.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.18.0 // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect golang.org/x/tools v0.6.0 // indirect diff --git a/go.sum b/go.sum index 258b079d..bab782c8 100644 --- a/go.sum +++ b/go.sum @@ -433,8 +433,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d h1:vtUKgx8dahOomfFzLREU8nSv25YHnTgLBn4rDnWZdU0= golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= @@ -476,8 +476,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -528,8 +528,8 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -537,7 +537,7 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/internal/protocol/http/fetcher.go b/internal/protocol/http/fetcher.go index 0e20ef44..a2cd6faa 100644 --- a/internal/protocol/http/fetcher.go +++ b/internal/protocol/http/fetcher.go @@ -105,6 +105,7 @@ func (f *Fetcher) Resolve(req *base.Request) error { Range: false, Files: []*base.FileInfo{}, } + if base.HttpCodePartialContent == httpResp.StatusCode || (base.HttpCodeOK == httpResp.StatusCode && httpResp.Header.Get(base.HttpHeaderAcceptRanges) == base.HttpHeaderBytes && strings.HasPrefix(httpResp.Header.Get(base.HttpHeaderContentRange), base.HttpHeaderBytes)) { // 1.返回206响应码表示支持断点下载 2.不返回206但是Accept-Ranges首部并且等于bytes也表示支持断点下载 res.Range = true diff --git a/pkg/download/downloader.go b/pkg/download/downloader.go index 6c87557c..f89c9c3d 100644 --- a/pkg/download/downloader.go +++ b/pkg/download/downloader.go @@ -35,7 +35,8 @@ const ( ) var ( - ErrTaskNotFound = errors.New("task not found") + ErrTaskNotFound = errors.New("task not found") + ErrUnSupportedProtocol = errors.New("unsupported protocol") ) type Listener func(event *Event) @@ -211,7 +212,7 @@ func (d *Downloader) parseFb(url string) (fetcher.FetcherBuilder, error) { if ok { return fetchBuilder, nil } - return nil, errors.New("unsupported protocol") + return nil, ErrUnSupportedProtocol } func (d *Downloader) setupFetcher(fetcher fetcher.Fetcher) { @@ -508,6 +509,15 @@ func (d *Downloader) DeleteByStatues(statues []base.Status, force bool) (err err return } +func (d *Downloader) Stats(id string) (sr any, err error) { + task := d.GetTask(id) + if task == nil { + return sr, ErrTaskNotFound + } + sr = task.fetcher.Stats() + return +} + func (d *Downloader) doDelete(task *Task, force bool) (err error) { err = func() error { if task.fetcher != nil { @@ -754,6 +764,7 @@ func (d *Downloader) doCreate(fetcher fetcher.Fetcher, opts *base.Options) (task task := NewTask() task.fetcherBuilder = fb task.fetcher = fetcher + task.Protocol = fetcher.Name() task.Meta = fetcher.Meta() task.Progress = &Progress{} initTask(task) diff --git a/pkg/download/model.go b/pkg/download/model.go index a17ba44a..4d83a221 100644 --- a/pkg/download/model.go +++ b/pkg/download/model.go @@ -7,6 +7,7 @@ import ( "github.com/GopeedLab/gopeed/internal/protocol/http" "github.com/GopeedLab/gopeed/pkg/base" "github.com/GopeedLab/gopeed/pkg/util" + gonanoid "github.com/matoous/go-nanoid/v2" "net/url" "sync" @@ -22,6 +23,7 @@ type Task struct { ID string `json:"id"` Meta *fetcher.FetcherMeta `json:"meta"` Status base.Status `json:"status"` + Protocol string `json:"protocol"` Progress *Progress `json:"progress"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` diff --git a/pkg/rest/api.go b/pkg/rest/api.go index 79378254..d95964dd 100644 --- a/pkg/rest/api.go +++ b/pkg/rest/api.go @@ -281,6 +281,21 @@ func DoProxy(w http.ResponseWriter, r *http.Request) { w.Write(buf) } +func GetStats(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + taskId := vars["id"] + if taskId == "" { + WriteJson(w, model.NewErrorResult("param invalid: id", model.CodeInvalidParam)) + return + } + statsResult, err := Downloader.Stats(taskId) + if err != nil { + writeError(w, err.Error()) + return + } + WriteJson(w, model.NewOkResult(statsResult)) +} + func convertStatues(statues []string) []base.Status { result := make([]base.Status, 0) for _, status := range statues { diff --git a/pkg/rest/server.go b/pkg/rest/server.go index 73fce377..962c7b04 100644 --- a/pkg/rest/server.go +++ b/pkg/rest/server.go @@ -98,6 +98,7 @@ func BuildServer(startCfg *model.StartConfig) (*http.Server, net.Listener, error r.Methods(http.MethodDelete).Path("/api/v1/tasks").HandlerFunc(DeleteTasks) r.Methods(http.MethodGet).Path("/api/v1/tasks/{id}").HandlerFunc(GetTask) r.Methods(http.MethodGet).Path("/api/v1/tasks").HandlerFunc(GetTasks) + r.Methods(http.MethodGet).Path("/api/v1/tasks/{id}/stats").HandlerFunc(GetStats) r.Methods(http.MethodGet).Path("/api/v1/config").HandlerFunc(GetConfig) r.Methods(http.MethodPut).Path("/api/v1/config").HandlerFunc(PutConfig) r.Methods(http.MethodPost).Path("/api/v1/extensions").HandlerFunc(InstallExtension)