LoginSignup
5
4

More than 5 years have passed since last update.

Go製コマンドpgetをライブラリとして使いたい!

Last updated at Posted at 2018-06-11

やりたいこと

高速でダウンロードできるツールを 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.goReady()が参考になりそうです。以下の変数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です。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4