Skip to content

Instantly share code, notes, and snippets.

@ivanvza
Created March 4, 2017 16:19
Show Gist options
  • Save ivanvza/54feb0eb0e242a6d412853108d515f92 to your computer and use it in GitHub Desktop.
Save ivanvza/54feb0eb0e242a6d412853108d515f92 to your computer and use it in GitHub Desktop.
Concurrent Downloader
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"runtime"
"strconv"
"strings"
"sync"
"github.com/cheggaaa/pb"
)
var wg sync.WaitGroup
func main() {
if len(os.Args) <= 1 {
fmt.Println("Usage:", os.Args[0], "<File URL>")
os.Exit(1)
}
baseURL, err := url.Parse(os.Args[1])
if err != nil {
panic(err)
}
str := baseURL.RequestURI()
i := strings.LastIndex(str, "/")
name := str[i+1:]
res, _ := http.Head(os.Args[1])
maps := res.Header
length, _ := strconv.Atoi(maps["Content-Length"][0])
limit := 250
lenSub := length / limit
diff := length % limit
bar := pb.New(length).SetUnits(pb.U_BYTES)
bar.ShowSpeed = true
bar.Start()
for i := 0; i < limit; i++ {
wg.Add(1)
min := lenSub * i // Min range
max := lenSub * (i + 1) // Max range
if i == limit-1 {
max += diff
}
go func(min int, max int, i int) {
client := &http.Client{}
req, _ := http.NewRequest("GET", os.Args[1], nil)
rangeHeader := "bytes=" + strconv.Itoa(min) + "-" + strconv.Itoa(max-1)
req.Header.Add("Range", rangeHeader)
resp, _ := client.Do(req)
defer resp.Body.Close()
r := io.Reader(resp.Body)
w, err := os.OpenFile(name+strconv.Itoa(i)+".tmp", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println("[-] Can't Create File")
}
writer := io.MultiWriter(w, bar)
io.Copy(writer, r)
wg.Done()
}(min, max, i)
}
wg.Wait()
concatFiles(limit, name)
}
func concatFiles(counter int, name string) {
bar := pb.StartNew(counter)
f, err := os.OpenFile(name, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
panic(err)
}
defer f.Close()
for i := 0; i < counter; i++ {
bar.Increment()
filename := name + strconv.Itoa(i) + ".tmp"
b, err := ioutil.ReadFile(filename)
f.Write(b)
if err != nil {
panic(err)
}
os.Remove(filename)
runtime.GC()
}
bar.FinishPrint(name + " Complete!")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment