やりたいこと
「高速でダウンロードできるツールを Go で実装した。 - Qiita」で有名なpget
を使えば、並列にダンロードできたwget
とかcurl
より速くダウンロードできていつも助かってます。やっぱり速いは正義です!
このpget
を自分のGo製のアプリケーションに組み込んで、高速なダウンロードの恩恵に預かりたいです!
ライブラリとしてpgetを使う
うまくいくまで、少し時間がかかりましたが、分かればとても簡単でした。
以下に完全なコードの例を載せます。
以下のコードの挙動は、
http://releases.ubuntu.com/16.04/ubuntu-16.04.4-desktop-amd64.iso.zsyncのisoファイルを./SavedFileName.dat
としてカレントディレクトリに保存します。
import (
"fmt"
"github.com/Code-Hex/pget"
)
// pgetを使って並列にダウンロードする
func ParallelDownload(url string, dirPath string, fileName string) error {
pg := pget.New()
pg.URLs = []string{url}
pg.TargetDir = dirPath
pg.Utils.SetFileName(fileName)
if err := pg.Checking(); err != nil {
return err
}
if err := pg.Download(); err != nil {
return err
}
if err := pg.Utils.BindwithFiles(pg.Procs); err != nil {
return err
}
return nil
}
func main() {
url := "http://releases.ubuntu.com/16.04/ubuntu-16.04.4-desktop-amd64.iso.zsync"
dirPath := ""
fileName := "SavedFileName.dat"
if err := ParallelDownload(url, dirPath, fileName); err != nil {
fmt.Println(err)
}
}
簡単な説明
-
pg.URLs = ...
のところでダウンロードしたいURLを指定します -
pg.TargetDir = ""
は空文字だと$PWD
にダウンロードされることになります -
pg.Utils.SetFileName(fileName)
はダウンロードされたあとのファイル名になります。- (
ubuntu-16.04.4-desktop-amd64.iso.zsync
が./SavedFileName.dat
に保存されます)
- (
pg.Checking()
でContent-Lengthとかを手に入れたりしているのですpg.Download()
で並列ダウンロードの処理が走ってpg.Utils.BindwithFiles(...)
で並列にダウンロードしたものをくっつける処理を担当していそうです
もっとオプションの機能を使いたいとき
オプションの機能を使いたいときは、<repo>/pget.go
のReady()
が参考になりそうです。以下の変数pget
は上のコードではpg
に対応してます。
pg.Procs = 4
などとすれば、分割数を変更したりできそうです。
これらの設定はpg.Checking()
の上に記述すればいいと思います。
// Ready method define the variables required to Download.
func (pget *Pget) Ready() error {
if procs := os.Getenv("GOMAXPROCS"); procs == "" {
runtime.GOMAXPROCS(pget.Procs)
}
var opts Options
if err := pget.parseOptions(&opts, os.Args[1:]); err != nil {
return errors.Wrap(err, "failed to parse command line args")
}
if opts.Trace {
pget.Trace = opts.Trace
}
if opts.Procs > 2 {
pget.Procs = opts.Procs
}
if opts.Timeout > 0 {
pget.timeout = opts.Timeout
}
if err := pget.parseURLs(); err != nil {
return errors.Wrap(err, "failed to parse of url")
}
if opts.Output != "" {
pget.Utils.SetFileName(opts.Output)
}
if opts.UserAgent != "" {
pget.useragent = opts.UserAgent
}
if opts.Referer != "" {
pget.referer = opts.Referer
}
if opts.TargetDir != "" {
info, err := os.Stat(opts.TargetDir)
if err != nil {
if !os.IsNotExist(err) {
return errors.Wrap(err, "target dir is invalid")
}
if err := os.MkdirAll(opts.TargetDir, 0755); err != nil {
return errors.Wrapf(err, "failed to create diretory at %s", opts.TargetDir)
}
} else if !info.IsDir() {
return errors.New("target dir is not a valid directory")
}
opts.TargetDir = strings.TrimSuffix(opts.TargetDir, "/")
}
pget.TargetDir = opts.TargetDir
return nil
}
(from: https://github.com/Code-Hex/pget/blob/9294f7465fa777e5d9400500691e244a9a9ff225/pget.go#L88)
最後に
Goのプログラムからpget
を使って、高速にダウンロードできるようになりました。本来pget
はCLIツールだと思うので、ライブラリとして使うことが想定されているかはわかりません。プログレスバーを消せるようにしたり、アクセスできないフィールドにアクセスするためには、pgetのコード自体に変更をする必要があるかもしれません。
今後の変更によってなにか変わるかもしれません。使ったバージョンは0.0.6のrevisionは7bace10b201ad40c4d9a37f0155d479f369bb918です。