106 lines
2.7 KiB
Go
106 lines
2.7 KiB
Go
/*
|
|
Download Manager In Go
|
|
|
|
This is a download manager I'm making all withing go, right now all of
|
|
func DownloadFile() is from the following url:
|
|
https://golangcode.com/download-a-file-from-a-url/
|
|
|
|
I'm wanting to add more onto this, but this right now is just so I can have a
|
|
jumping off point for *my* code.
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
)
|
|
|
|
// WriteCounter counts the number of bytes written to it. It implements to the
|
|
// io.Writer interface and we pass this into io.TeeReader() which will report
|
|
// progress on each write cycle.
|
|
type WriteCounter struct {
|
|
Total uint64
|
|
}
|
|
|
|
func (wc *WriteCounter) Write(p []byte) (int, error) {
|
|
n := len(p)
|
|
wc.Total += uint64(n)
|
|
wc.PrintProgress()
|
|
return n, nil
|
|
}
|
|
|
|
func (wc WriteCounter) PrintProgress() {
|
|
// Clear the line by using a character return to go back to the start and
|
|
// remove the remaining characters by filling it with spaces
|
|
fmt.Printf("\r%s", strings.Repeat(" ", 35))
|
|
|
|
// Return again and print current status of download
|
|
// Humanize package used so the amount is in a human readable way (ex: 100MB)
|
|
fmt.Printf("\rDownloading... %s complete", humanize.Bytes(wc.Total))
|
|
}
|
|
|
|
func main() {
|
|
// Asks the user what the url to the file is.
|
|
// Input will be below the following text.
|
|
fmt.Println("Url you would like to download from: ")
|
|
|
|
// var then variable name then the type.
|
|
var fileUrl string
|
|
|
|
// Takes input from user.
|
|
fmt.Scanln(&fileUrl)
|
|
fmt.Println("File name: ")
|
|
var fileName string
|
|
fmt.Scanln(&fileName)
|
|
|
|
// Stuff from the older main function.
|
|
err := DownloadFile(fileName, fileUrl)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
fmt.Println("Downloaded: " + fileName)
|
|
}
|
|
|
|
// DownloadedFile will download a url to a local file. It's efficient because it
|
|
// write as it downloads and not load the whole file into memory
|
|
func DownloadFile(filepath string, url string) error {
|
|
|
|
// Create the file, but give it a tmp file extension, this means we won't
|
|
// overwrite a file unless it's downloaded, the .tmp will be removed when
|
|
// download completes.
|
|
out, err := os.Create(filepath + ".tmp")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get the data
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// Create progress report and pass it to be used alongside the writer
|
|
counter := &WriteCounter{}
|
|
if _, err = io.Copy(out, io.TeeReader(resp.Body, counter)); err != nil {
|
|
out.Close()
|
|
return err
|
|
}
|
|
|
|
// The progress use the same line so print a new line once it's done.
|
|
fmt.Print("\n")
|
|
|
|
// Close the file without defer so it can happen before Rename()
|
|
out.Close()
|
|
|
|
if err = os.Rename(filepath+".tmp", filepath); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
} |