BASIC User Group > Code Challenges

Programatically download the latest 64 bit version of Firefox for Windows.

<< < (11/11)

John:
I thought I would mention that one should reinitialize curl between commits. Curl was sending a previous POST buffer with a following GET.

AIR:
Go version:


--- Code: Go ---package main import (        "fmt"        "io"        "io/ioutil"        "net/http"        "os"        "regexp"        "strings"         "github.com/dustin/go-humanize") // WriteCounter counts the number of bytes written to it. It implements to the io.Writer// interface and we can pass this into io.TeeReader() which will report progress on each// write cycle.type WriteCounter struct {        Total    uint64        Filesize uint64} func main() {        clear()        fmt.Printf("Firefox Download Challenge (GO Version) by AIR.\n\n")        url := "https://mozilla.org/firefox/new"         // Retrieve the data from the url        resp, err := http.Get(url)        chkError(err)         // Auto close connection        defer resp.Body.Close()         // reads html as a slice (array) of bytes        html, err := ioutil.ReadAll(resp.Body)        chkError(err)         // regex to extract current version        re, err := regexp.Compile(`data-latest-firefox="([0-9]+\.[0-9]+?\.[0-9]+)"`)        chkError(err)         // Regex to extract the download link        re2, err := regexp.Compile(`.+href="(.+latest-ssl.+os=win64.+US).+`)        chkError(err)         // Perform search for version and download link        ffVersion := re.FindStringSubmatch(string(html))        ffLink := re2.FindStringSubmatch(string(html))         // Download the Windows installer        err = DownloadFile("Firefox Setup "+ffVersion[1]+".exe", ffLink[1])        chkError(err)         fmt.Println("\nDownload Complete.")} func chkError(e error) {        if e != nil {                panic(e)        }} // Clears screen (Linux/macOS)func clear() {        fmt.Print("\033[2J\033[H")} // DownloadFile will download a url to a local file. It's efficient because it will// write as it downloads and not load the whole file into memory. We pass an io.TeeReader// into Copy() to report progress on the download.func DownloadFile(filepath string, url string) error {         // Create the file        out, err := os.Create(filepath)        if err != nil {                return err        }        defer out.Close()         // Get the data        resp, err := http.Get(url)        if err != nil {                return err        }        defer resp.Body.Close()         // Create our progress reporter (with reported Filesize set) and pass it to be used alongside our writer        counter := &WriteCounter{Filesize: uint64(resp.ContentLength)}         _, err = io.Copy(out, io.TeeReader(resp.Body, counter))        if err != nil {                return err        }         // The progress outputs on a single line so print a new line once it's finished downloading        fmt.Print("\n")         return nil} // Callback used by WriteCounterfunc (wc *WriteCounter) Write(p []byte) (int, error) {        n := len(p)        wc.Total += uint64(n)         wc.PrintProgress()        return n, nil} // PrintProgress displays the download statusfunc (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(" ", 30))         // Return again and print current status of download        // We use the humanize package to print the status in a human-readable way (e.g. 10 MB)        fmt.Printf("\rDownloaded %s of %s", humanize.Bytes(wc.Total), humanize.Bytes(wc.Filesize)) } 
Output:
Firefox Download Challenge (GO Version) by AIR.

Downloaded 46 MB of 46 MB

Download Complete.

AIR.

Navigation

[0] Message Index

[*] Previous page

Go to full version