mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-13 20:03:46 +00:00
feat: 命令行工具
This commit is contained in:
1 parent
f150ec23c4
commit
046729bfaa
10 files changed
+195
-31
No files matched your search
+41
-1
@@ -1,19 +1,39 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/monkeyWie/gopeed-core/download"
|
"github.com/monkeyWie/gopeed-core/download"
|
||||||
"github.com/monkeyWie/gopeed-core/download/base"
|
"github.com/monkeyWie/gopeed-core/download/base"
|
||||||
"github.com/monkeyWie/gopeed-core/download/http"
|
"github.com/monkeyWie/gopeed-core/download/http"
|
||||||
|
"github.com/superhawk610/bar"
|
||||||
|
"github.com/ttacon/chalk"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
b := bar.NewWithOpts(
|
||||||
|
bar.WithDimensions(10000, 20),
|
||||||
|
bar.WithDisplay("[", "■", "■", "□", "]"),
|
||||||
|
bar.WithFormat(
|
||||||
|
fmt.Sprintf(
|
||||||
|
" %s:status%s :percent :bar%s :speedKB/s%s ",
|
||||||
|
chalk.Green,
|
||||||
|
chalk.Reset,
|
||||||
|
chalk.Blue,
|
||||||
|
chalk.Reset,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
downloader := download.NewDownloader(http.FetcherBuilder)
|
downloader := download.NewDownloader(http.FetcherBuilder)
|
||||||
res, err := downloader.Resolve(&base.Request{
|
res, err := downloader.Resolve(&base.Request{
|
||||||
URL: "http://192.168.200.163:8088/docker-compose",
|
URL: "https://dldir1.qq.com/weixin/Windows/WeChatSetup.exe",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = downloader.Create(res, &base.Options{
|
err = downloader.Create(res, &base.Options{
|
||||||
Path: "E:\\test\\gopeed\\http",
|
Path: "E:\\test\\gopeed\\http",
|
||||||
Connections: 4,
|
Connections: 4,
|
||||||
@@ -21,4 +41,24 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
downloader.Listener(func(taskInfo *download.TaskInfo, eventKey base.EventKey) {
|
||||||
|
if eventKey == base.EventKeyProgress {
|
||||||
|
b.Update(int(10000*(float64(taskInfo.Progress.Downloaded)/float64(taskInfo.Res.TotalSize))), bar.Context{
|
||||||
|
bar.Ctx("status", "downloading..."),
|
||||||
|
bar.Ctx("speed", strconv.Itoa(int(taskInfo.Progress.Speed/1024))),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if eventKey == base.EventKeyDone {
|
||||||
|
b.Update(10000, bar.Context{
|
||||||
|
bar.Ctx("status", "complete"),
|
||||||
|
bar.Ctx("speed", strconv.Itoa(int(taskInfo.Progress.Speed/1024))),
|
||||||
|
})
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
wg.Wait()
|
||||||
|
b.Done()
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,16 @@ const (
|
|||||||
DownloadStatusDone
|
DownloadStatusDone
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type EventKey string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventKeyStart = "start"
|
||||||
|
EventKeyPause = "pause"
|
||||||
|
EventKeyProgress = "progress"
|
||||||
|
EventKeyError = "error"
|
||||||
|
EventKeyDone = "done"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
HttpCodeOK = 200
|
HttpCodeOK = 200
|
||||||
HttpCodePartialContent = 206
|
HttpCodePartialContent = 206
|
||||||
|
|||||||
@@ -142,3 +142,15 @@ func (d *DialerWarp) Dial(network, addr string) (c net.Conn, err error) {
|
|||||||
}
|
}
|
||||||
return &ConnWarp{conn: conn}, nil
|
return &ConnWarp{conn: conn}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取任务中各个文件的已下载字节数
|
||||||
|
type Progress []int64
|
||||||
|
|
||||||
|
// TotalDownloaded 获取任务总下载字节数
|
||||||
|
func (p Progress) TotalDownloaded() int64 {
|
||||||
|
total := int64(0)
|
||||||
|
for _, d := range p {
|
||||||
|
total += d
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ type Fetcher interface {
|
|||||||
Pause() (err error)
|
Pause() (err error)
|
||||||
Continue() (err error)
|
Continue() (err error)
|
||||||
|
|
||||||
|
// 获取任务下载进度
|
||||||
|
Progress() Progress
|
||||||
// 该方法会一直阻塞,直到任务下载结束
|
// 该方法会一直阻塞,直到任务下载结束
|
||||||
Wait() (err error)
|
Wait() (err error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// 计时器
|
||||||
|
type Timer struct {
|
||||||
|
t int64
|
||||||
|
used int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Timer) Start() {
|
||||||
|
t.t = time.Now().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Timer) Pause() {
|
||||||
|
t.used += time.Now().UnixNano() - t.t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Timer) Continue() {
|
||||||
|
t.t = time.Now().UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Timer) Used() int64 {
|
||||||
|
return (time.Now().UnixNano() - t.t) + t.used
|
||||||
|
}
|
||||||
+70
-28
@@ -7,16 +7,19 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TaskInfo struct {
|
type TaskInfo struct {
|
||||||
ID string
|
ID string
|
||||||
Res *base.Resource
|
Res *base.Resource
|
||||||
Opts *base.Options
|
Opts *base.Options
|
||||||
Status base.Status
|
Status base.Status
|
||||||
Files map[string]*base.FileInfo
|
Files map[string]*base.FileInfo
|
||||||
|
Progress *Progress
|
||||||
|
|
||||||
fetcher base.Fetcher
|
fetcher base.Fetcher
|
||||||
|
timer *base.Timer
|
||||||
locker *sync.Mutex
|
locker *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +29,7 @@ type Downloader struct {
|
|||||||
*base.DefaultController
|
*base.DefaultController
|
||||||
fetchBuilders map[string]func() base.Fetcher
|
fetchBuilders map[string]func() base.Fetcher
|
||||||
tasks map[string]*TaskInfo
|
tasks map[string]*TaskInfo
|
||||||
listener func(taskInfo *TaskInfo, status base.Status)
|
listener func(taskInfo *TaskInfo, eventKey base.EventKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDownloader(fbs ...FetcherBuilder) *Downloader {
|
func NewDownloader(fbs ...FetcherBuilder) *Downloader {
|
||||||
@@ -39,6 +42,27 @@ func NewDownloader(fbs ...FetcherBuilder) *Downloader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.tasks = make(map[string]*TaskInfo)
|
d.tasks = make(map[string]*TaskInfo)
|
||||||
|
|
||||||
|
// 每秒统计一次下载速度
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if len(d.tasks) > 0 {
|
||||||
|
for _, task := range d.tasks {
|
||||||
|
if task.Status == base.DownloadStatusDone ||
|
||||||
|
task.Status == base.DownloadStatusError ||
|
||||||
|
task.Status == base.DownloadStatusPause {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
current := task.fetcher.Progress().TotalDownloaded()
|
||||||
|
task.Progress.Used = task.timer.Used()
|
||||||
|
task.Progress.Speed = current - task.Progress.Downloaded
|
||||||
|
task.Progress.Downloaded = current
|
||||||
|
d.emit(task, base.EventKeyProgress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,26 +97,33 @@ func (d *Downloader) Create(res *base.Resource, opts *base.Options) (err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := uuid.New().String()
|
id := uuid.New().String()
|
||||||
d.tasks[id] = &TaskInfo{
|
task := &TaskInfo{
|
||||||
ID: id,
|
ID: id,
|
||||||
Res: res,
|
Res: res,
|
||||||
Opts: opts,
|
Opts: opts,
|
||||||
Status: base.DownloadStatusReady,
|
Status: base.DownloadStatusReady,
|
||||||
fetcher: fetcher,
|
Progress: &Progress{},
|
||||||
locker: new(sync.Mutex),
|
fetcher: fetcher,
|
||||||
|
timer: &base.Timer{},
|
||||||
|
locker: new(sync.Mutex),
|
||||||
|
}
|
||||||
|
d.tasks[id] = task
|
||||||
|
task.timer.Start()
|
||||||
|
d.emit(task, base.EventKeyStart)
|
||||||
|
err = fetcher.Start()
|
||||||
|
if err != nil {
|
||||||
|
d.emit(task, base.EventKeyError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
d.emit(d.tasks[id], base.DownloadStatusStart)
|
|
||||||
go func() {
|
go func() {
|
||||||
err = fetcher.Start()
|
|
||||||
if err != nil {
|
|
||||||
d.emit(d.tasks[id], base.DownloadStatusError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = fetcher.Wait()
|
err = fetcher.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.emit(d.tasks[id], base.DownloadStatusError)
|
d.emit(task, base.EventKeyError)
|
||||||
} else {
|
} else {
|
||||||
d.emit(d.tasks[id], base.DownloadStatusDone)
|
task.Progress.Used = task.timer.Used()
|
||||||
|
task.Progress.Speed = task.Res.TotalSize / (task.Progress.Used / int64(time.Second))
|
||||||
|
task.Progress.Downloaded = task.Res.TotalSize
|
||||||
|
d.emit(d.tasks[id], base.EventKeyDone)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return
|
return
|
||||||
@@ -102,24 +133,35 @@ func (d *Downloader) Pause(id string) {
|
|||||||
task := d.tasks[id]
|
task := d.tasks[id]
|
||||||
task.locker.Lock()
|
task.locker.Lock()
|
||||||
defer task.locker.Unlock()
|
defer task.locker.Unlock()
|
||||||
d.tasks[id].fetcher.Pause()
|
task.timer.Pause()
|
||||||
d.emit(d.tasks[id], base.DownloadStatusPause)
|
task.fetcher.Pause()
|
||||||
|
d.emit(task, base.EventKeyPause)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) Continue(id string) {
|
func (d *Downloader) Continue(id string) {
|
||||||
task := d.tasks[id]
|
task := d.tasks[id]
|
||||||
task.locker.Lock()
|
task.locker.Lock()
|
||||||
defer task.locker.Unlock()
|
defer task.locker.Unlock()
|
||||||
d.tasks[id].fetcher.Continue()
|
task.timer.Continue()
|
||||||
d.emit(d.tasks[id], base.DownloadStatusStart)
|
task.fetcher.Continue()
|
||||||
|
d.emit(task, base.EventKeyStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) Listener(fn func(taskInfo *TaskInfo, status base.Status)) {
|
func (d *Downloader) Listener(fn func(taskInfo *TaskInfo, eventKey base.EventKey)) {
|
||||||
d.listener = fn
|
d.listener = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) emit(taskInfo *TaskInfo, status base.Status) {
|
func (d *Downloader) emit(taskInfo *TaskInfo, eventKey base.EventKey) {
|
||||||
if d.listener != nil {
|
if d.listener != nil {
|
||||||
d.listener(taskInfo, status)
|
d.listener(taskInfo, eventKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Progress struct {
|
||||||
|
// 下载耗时(纳秒)
|
||||||
|
Used int64
|
||||||
|
// 每秒下载字节数
|
||||||
|
Speed int64
|
||||||
|
// 已下载的字节数
|
||||||
|
Downloaded int64
|
||||||
|
}
|
||||||
@@ -53,8 +53,8 @@ func TestDownloader_Create(t *testing.T) {
|
|||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
downloader.Listener(func(taskInfo *TaskInfo, status base.Status) {
|
downloader.Listener(func(taskInfo *TaskInfo, eventKey base.EventKey) {
|
||||||
if status == base.DownloadStatusDone {
|
if eventKey == base.EventKeyDone {
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -199,6 +199,18 @@ func (f *Fetcher) Continue() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Fetcher) Progress() base.Progress {
|
||||||
|
p := make(base.Progress, 0)
|
||||||
|
if len(f.chunks) > 0 {
|
||||||
|
total := int64(0)
|
||||||
|
for _, chunk := range f.chunks {
|
||||||
|
total += chunk.Downloaded
|
||||||
|
}
|
||||||
|
p = append(p, total)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Fetcher) filename() string {
|
func (f *Fetcher) filename() string {
|
||||||
// 创建文件
|
// 创建文件
|
||||||
var filename = f.opts.Name
|
var filename = f.opts.Name
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ require (
|
|||||||
github.com/cenkalti/mse v0.0.0-20140930130441-6ef65f170972
|
github.com/cenkalti/mse v0.0.0-20140930130441-6ef65f170972
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e
|
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e
|
||||||
|
github.com/mattn/go-tty v0.0.3 // indirect
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
|
github.com/superhawk610/bar v0.0.2
|
||||||
|
github.com/superhawk610/terminal v0.1.0 // indirect
|
||||||
|
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
)
|
)
|
||||||
@@ -22,6 +22,13 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGi
|
|||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e h1:KMs6SK8iDSR1+ZzOK10L5wGPpWDByyvOe5nrqk51g2U=
|
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e h1:KMs6SK8iDSR1+ZzOK10L5wGPpWDByyvOe5nrqk51g2U=
|
||||||
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e/go.mod h1:+AHfJo5+69p+fjvMJTmYajNP9rFBHQcaTDFmuXRRATI=
|
github.com/marksamman/bencode v0.0.0-20150821143521-dc84f26e086e/go.mod h1:+AHfJo5+69p+fjvMJTmYajNP9rFBHQcaTDFmuXRRATI=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
|
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=
|
||||||
|
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||||
@@ -35,8 +42,14 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/superhawk610/bar v0.0.2 h1:Jf9+rXkpGgzJkpogpx+BGjC4EwkFZc8L7t8QBrmyfqY=
|
||||||
|
github.com/superhawk610/bar v0.0.2/go.mod h1:xc6t0MG+8Mbj9wnHBEdvX2TRtNIaqhM5fW3R+dF9vH8=
|
||||||
|
github.com/superhawk610/terminal v0.1.0 h1:OpWp0+861M3l5j4ZWprm8q0fgG9Y2xXZp5tkunvCm/M=
|
||||||
|
github.com/superhawk610/terminal v0.1.0/go.mod h1:NQ3EEKWSeofexUwENLX3lv4WR2qeGiLlbf/NveZ7ZAQ=
|
||||||
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
||||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
|
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4=
|
||||||
|
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
|
||||||
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
||||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@@ -44,12 +57,16 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
|||||||
Reference in new issue
Block a user