Skip to content

Commit 5d3852b

Browse files
authored
Merge pull request #5 from abzcoding/bw-limit
added bandwidth limiting to hget
2 parents 44e2abc + 9aade6b commit 5d3852b

File tree

4 files changed

+47
-22
lines changed

4 files changed

+47
-22
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ deps:
99
go get -d gopkg.in/cheggaaa/pb.v1
1010
go get -d github.com/mattn/go-isatty
1111
go get -d github.com/imkira/go-task
12+
go get -d github.com/fujiwara/shapeio
13+
go get -d github.com/alecthomas/units
1214

1315
clean:
1416
@echo "====> Remove installed binary"

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ Binary file will be built at ./bin/hget, you can copy to /usr/bin or /usr/local/
1717
## Usage
1818

1919
```bash
20-
hget [-n parallel] [-skip-tls false] [-proxy proxy_server] [-file filename] [URL] # to download url, with n connections, and not skip tls certificate
20+
hget [-n parallel] [-skip-tls false] [-rate bwRate] [-proxy proxy_server] [-file filename] [URL] # to download url, with n connections, and not skip tls certificate
2121
hget tasks # get interrupted tasks
2222
hget resume [TaskName | URL] # to resume task
2323
hget -proxy "127.0.0.1:12345" URL # to download using socks5 proxy
2424
hget -proxy "http://sample-proxy.com:8080" URL # to download using http proxy
2525
hget -file sample.txt # to download a list of files
26+
hget -n 4 -rate 100KB URL # to download using 4 threads & limited to 100Kb per second
2627
```
2728

2829
### Help
@@ -37,6 +38,10 @@ Usage of hget:
3738
proxy for downloading, ex
3839
-proxy '127.0.0.1:12345' for socks5 proxy
3940
-proxy 'http://proxy.com:8080' for http proxy
41+
-rate string
42+
bandwidth limit to use while downloading, ex
43+
-rate 10kB
44+
-rate 10MiB
4045
-skip-tls
4146
skip verify certificate for https (default true)
4247
```

http.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import (
1313
"strings"
1414
"sync"
1515

16+
"github.com/alecthomas/units"
1617
"github.com/fatih/color"
18+
"github.com/fujiwara/shapeio"
1719
"golang.org/x/net/proxy"
1820
pb "gopkg.in/cheggaaa/pb.v1"
1921
)
@@ -30,8 +32,10 @@ var (
3032
contentLengthHeader = "Content-Length"
3133
)
3234

35+
// HttpDownloader holds the required configurations
3336
type HttpDownloader struct {
3437
proxy string
38+
rate int64
3539
url string
3640
file string
3741
par int64
@@ -42,11 +46,11 @@ type HttpDownloader struct {
4246
resumable bool
4347
}
4448

45-
func NewHttpDownloader(url string, par int, skipTls bool, socks5_proxy string) *HttpDownloader {
49+
func NewHttpDownloader(url string, par int, skipTls bool, proxy_server string, bwLimit string) *HttpDownloader {
4650
var resumable = true
47-
48-
client := ProxyAwareHttpClient(socks5_proxy)
49-
51+
52+
client := ProxyAwareHttpClient(proxy_server)
53+
5054
parsed, err := stdurl.Parse(url)
5155
FatalCheck(err)
5256

@@ -94,6 +98,12 @@ func NewHttpDownloader(url string, par int, skipTls bool, socks5_proxy string) *
9498

9599
file := filepath.Base(url)
96100
ret := new(HttpDownloader)
101+
ret.rate = 0
102+
bandwidthLimit, err := units.ParseStrictBytes(bwLimit)
103+
if err == nil {
104+
ret.rate = bandwidthLimit
105+
Printf("Download with bandwidth limit set to %s[%d]\n", bwLimit, ret.rate)
106+
}
97107
ret.url = url
98108
ret.file = file
99109
ret.par = int64(par)
@@ -102,7 +112,7 @@ func NewHttpDownloader(url string, par int, skipTls bool, socks5_proxy string) *
102112
ret.skipTls = skipTls
103113
ret.parts = partCalculate(int64(par), len, url)
104114
ret.resumable = resumable
105-
ret.proxy = socks5_proxy
115+
ret.proxy = proxy_server
106116

107117
return ret
108118
}
@@ -135,16 +145,16 @@ func partCalculate(par int64, len int64, url string) []Part {
135145
return ret
136146
}
137147

138-
func ProxyAwareHttpClient(socks5_proxy string) *http.Client {
148+
func ProxyAwareHttpClient(proxy_server string) *http.Client {
139149
// setup a http client
140150
httpTransport := &http.Transport{}
141151
httpClient := &http.Client{Transport: httpTransport}
142152
var dialer proxy.Dialer
143153
dialer = proxy.Direct
144-
145-
if len(socks5_proxy) > 0 {
146-
if strings.HasPrefix(socks5_proxy, "http") {
147-
proxyUrl, err := stdurl.Parse(socks5_proxy)
154+
155+
if len(proxy_server) > 0 {
156+
if strings.HasPrefix(proxy_server, "http") {
157+
proxyUrl, err := stdurl.Parse(proxy_server)
148158
if err != nil {
149159
fmt.Fprintln(os.Stderr, "invalid proxy: ", err)
150160
}
@@ -155,12 +165,12 @@ func ProxyAwareHttpClient(socks5_proxy string) *http.Client {
155165
}
156166
} else {
157167
// create a socks5 dialer
158-
dialer, err := proxy.SOCKS5("tcp", socks5_proxy, nil, proxy.Direct)
168+
dialer, err := proxy.SOCKS5("tcp", proxy_server, nil, proxy.Direct)
159169
if err == nil {
160170
httpTransport.Dial = dialer.Dial
161171
}
162172
}
163-
173+
164174
}
165175
return httpClient
166176
}
@@ -247,7 +257,14 @@ func (d *HttpDownloader) Do(doneChan chan bool, fileChan chan string, errorChan
247257
finishDownloadChan := make(chan bool)
248258

249259
go func() {
250-
written, _ := io.Copy(writer, resp.Body)
260+
var written int64
261+
if d.rate != 0 {
262+
reader := shapeio.NewReader(resp.Body)
263+
reader.SetRateLimit(float64(d.rate))
264+
written, _ = io.Copy(writer, reader)
265+
} else {
266+
written, _ = io.Copy(writer, resp.Body)
267+
}
251268
current += written
252269
fileChan <- part.Path
253270
finishDownloadChan <- true

main.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ var displayProgress = true
1717

1818
func main() {
1919
var err error
20-
var proxy, filepath string
20+
var proxy, filepath, bwLimit string
2121

2222
conn := flag.Int("n", runtime.NumCPU(), "connection")
2323
skiptls := flag.Bool("skip-tls", true, "skip verify certificate for https")
2424
flag.StringVar(&proxy, "proxy", "", "proxy for downloading, ex \n\t-proxy '127.0.0.1:12345' for socks5 proxy\n\t-proxy 'http://proxy.com:8080' for http proxy")
2525
flag.StringVar(&filepath, "file", "", "filepath that contains links in each line")
26+
flag.StringVar(&bwLimit, "rate", "", "bandwidth limit to use while downloading, ex\n\t -rate 10kB\n\t-rate 10MiB")
2627

2728
flag.Parse()
2829
args := flag.Args()
@@ -46,7 +47,7 @@ func main() {
4647
break
4748
}
4849

49-
g1.AddChild(downloadTask(string(line), nil, *conn, *skiptls, proxy))
50+
g1.AddChild(downloadTask(string(line), nil, *conn, *skiptls, proxy, bwLimit))
5051
}
5152
g1.Run(nil)
5253
return
@@ -79,26 +80,26 @@ func main() {
7980

8081
state, err := Resume(task)
8182
FatalCheck(err)
82-
Execute(state.Url, state, *conn, *skiptls, proxy)
83+
Execute(state.Url, state, *conn, *skiptls, proxy, bwLimit)
8384
return
8485
} else {
8586
if ExistDir(FolderOf(command)) {
8687
Warnf("Downloading task already exist, remove first \n")
8788
err := os.RemoveAll(FolderOf(command))
8889
FatalCheck(err)
8990
}
90-
Execute(command, nil, *conn, *skiptls, proxy)
91+
Execute(command, nil, *conn, *skiptls, proxy, bwLimit)
9192
}
9293
}
9394

94-
func downloadTask(url string, state *State, conn int, skiptls bool, proxy string) task.Task {
95+
func downloadTask(url string, state *State, conn int, skiptls bool, proxy string, bwLimit string) task.Task {
9596
run := func(t task.Task, ctx task.Context) {
96-
Execute(url, state, conn, skiptls, proxy)
97+
Execute(url, state, conn, skiptls, proxy, bwLimit)
9798
}
9899
return task.NewTaskWithFunc(run)
99100
}
100101

101-
func Execute(url string, state *State, conn int, skiptls bool, proxy string) {
102+
func Execute(url string, state *State, conn int, skiptls bool, proxy string, bwLimit string) {
102103
//otherwise is hget <URL> command
103104

104105
signal_chan := make(chan os.Signal, 1)
@@ -122,7 +123,7 @@ func Execute(url string, state *State, conn int, skiptls bool, proxy string) {
122123

123124
var downloader *HttpDownloader
124125
if state == nil {
125-
downloader = NewHttpDownloader(url, conn, skiptls, proxy)
126+
downloader = NewHttpDownloader(url, conn, skiptls, proxy, bwLimit)
126127
} else {
127128
downloader = &HttpDownloader{url: state.Url, file: filepath.Base(state.Url), par: int64(len(state.Parts)), parts: state.Parts, resumable: true}
128129
}

0 commit comments

Comments
 (0)