Original post

With the below code I can download a file from internet asking with monitoring the downloaded percentage.

How can I do something to upload file to internet as well as monitoring the upload progress. I want to upload executable file at github assets

package main

import (
        "fmt"
        "io"
        "net/http"
        "os"
        "strings"

        "github.com/dustin/-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
}

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  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
        // We use the humanize package to print the bytes in a meaningful way (e.g. 10 MB)
        fmt.Printf("rDownloading... %s complete", humanize.Bytes(wc.Total))
}

func main() {
        fmt.Println("Download Started")

        fileUrl := "https://upload.wikimedia.org/wikipedia/commons/d/d6/Wp-w4-big.jpg"
        err := DownloadFile("avatar.jpg", fileUrl)
        if err != nil {
                panic(err)
        }

        fmt.Println("Download Finished")
}

// 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, but give it a tmp file extension, this means we won't overwrite a
        // file until it's downloaded, but we'll remove the tmp extension once downloaded.
        out, err := os.Create(filepath + ".tmp")
        if err != nil {
                return err
        }

        // Get the data
        resp, err := http.Get(url)
        if err != nil {
                out.Close()
                return err
        }
        defer resp.Body.Close()

        // Create our progress reporter and pass it to be used alongside our 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 finished downloading
        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
}