From 602790e2ca33ad7f22235bf2ae548cef7db8b814 Mon Sep 17 00:00:00 2001 From: Mitch Riedstra Date: Sat, 9 Jan 2021 15:22:27 -0500 Subject: Add a progress bar to the UI for installation via HTTP. Uses polling, but whatever. --- cmd/web/install.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) (limited to 'cmd/web/install.go') diff --git a/cmd/web/install.go b/cmd/web/install.go index 678037a..d9a2379 100644 --- a/cmd/web/install.go +++ b/cmd/web/install.go @@ -3,9 +3,11 @@ package main import ( "encoding/json" "fmt" + "io" "net/http" "net/url" "os" + "strconv" "strings" "sync" "time" @@ -36,6 +38,8 @@ func statsHandler(w http.ResponseWriter, r *http.Request) { status.m.RLock() defer status.m.RUnlock() + w.Header().Add("Content-type", "application/json") + enc := json.NewEncoder(w) err := enc.Encode(status.s) @@ -52,12 +56,57 @@ func installHttp(u string) error { return fmt.Errorf("Installer: getting %w", err) } - err = Lib.Extract(resp.Body) + estSize, err := strconv.ParseInt(resp.Header.Get("Estimated-size"), 10, 64) if err != nil { - return fmt.Errorf("Installer: extracting %w", err) + return fmt.Errorf("Failed to convert estimated size header: %w", err) } - resp.Body.Close() - return nil + + status.m.Lock() + status.s.Size = estSize + status.m.Unlock() + + rdr, wrtr := io.Pipe() + + go func() { + err = Lib.Extract(rdr) + if err != nil { + Logger.Printf("Installer: extracting %w", err) + } + resp.Body.Close() + }() + + var total int64 + start := time.Now() + status.m.Lock() + status.s.Start = &start + status.m.Unlock() + for { + var n int64 + n, err = io.CopyN(wrtr, resp.Body, 100*1024*1024) + if err == io.EOF { + break + } else if err != nil { + Logger.Printf("Error encountered read from response body in installer: %s", err) + break + } + + total += n + mb := float64(total / 1024 / 1024) + rate := mb / time.Since(start).Seconds() + + Logger.Printf("Downloading from %s, Size: %s, %0.1f%% Done, Rate: %.2f mb/s", + u, formatBytes(estSize), float64(total)/float64(estSize)*100, rate) + + status.m.Lock() + status.s.Transferred = total + status.m.Unlock() + } + + if err == io.EOF { + return nil + } + + return err } func installPath(p string) error { -- cgit v1.2.3