Skip to content

Commit ad2a3ea

Browse files
Add arduino-flasher-cli download progress
1 parent f55a36c commit ad2a3ea

File tree

2 files changed

+40
-7
lines changed

2 files changed

+40
-7
lines changed

updater/download_image.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,36 @@ type Manifest struct {
2626
// DownloadConfirmCB is a function that is called when a Debian image is ready to be downloaded.
2727
type DownloadConfirmCB func(target string) (bool, error)
2828

29+
// PassThru wraps an existing io.Reader.
30+
//
31+
// It simply forwards the Read() call, while displaying
32+
// the results from individual calls to it.
33+
type PassThru struct {
34+
io.Reader
35+
total float64 // Total # of bytes transferred
36+
length int64 // Expected length
37+
progress float64
38+
progressCB func(f float64)
39+
}
40+
41+
// Read 'overrides' the underlying io.Reader's Read method.
42+
// This is the one that will be called by io.Copy(). We simply
43+
// use it to keep track of the progress and then forward the call.
44+
func (pt *PassThru) Read(p []byte) (int, error) {
45+
n, err := pt.Reader.Read(p)
46+
if err != nil {
47+
return 0, err
48+
}
49+
pt.total += float64(n)
50+
percentage := pt.total / float64(pt.length) * float64(100)
51+
if percentage-pt.progress > 1 {
52+
pt.progressCB(percentage)
53+
pt.progress = percentage
54+
}
55+
56+
return n, nil
57+
}
58+
2959
func DownloadImage(client *Client, targetVersion string, upgradeConfirmCb DownloadConfirmCB, forceYes bool) (string, string, error) {
3060
var err error
3161

@@ -52,9 +82,10 @@ func DownloadImage(client *Client, targetVersion string, upgradeConfirmCb Downlo
5282

5383
// Download the Debian image
5484
var download io.ReadCloser
85+
var size int64
5586
if targetVersion == manifest.Latest.Version {
5687
slog.Info("Downloading Debian image", "version", manifest.Latest.Version)
57-
download, err = client.FetchZip(manifest.Latest.Url)
88+
download, size, err = client.FetchZip(manifest.Latest.Url)
5889
if err != nil {
5990
return "", "", fmt.Errorf("could not fetch Debian image: %w", err)
6091
}
@@ -82,8 +113,10 @@ func DownloadImage(client *Client, targetVersion string, upgradeConfirmCb Downlo
82113
}
83114
defer tmpZipFile.Close()
84115

116+
// Download and keep track of the progress
117+
src := &PassThru{Reader: download, length: size, progressCB: func(f float64) { feedback.Printf("Download progress: %.2f %%", f) }}
85118
md5 := md5.New()
86-
if _, err := io.Copy(io.MultiWriter(md5, tmpZipFile), download); err != nil {
119+
if _, err := io.Copy(io.MultiWriter(md5, tmpZipFile), src); err != nil {
87120
return "", "", err
88121
}
89122
tmpZipFile.Close()

updater/http_client.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,20 +92,20 @@ func (c *Client) GetInfoManifest() (Manifest, error) {
9292
}
9393

9494
// FetchZip fetches the Debian image archive.
95-
func (c *Client) FetchZip(zipURL string) (io.ReadCloser, error) {
95+
func (c *Client) FetchZip(zipURL string) (io.ReadCloser, int64, error) {
9696
req, err := http.NewRequest("GET", zipURL, nil)
9797
if err != nil {
98-
return nil, fmt.Errorf("failed to create request: %w", err)
98+
return nil, 0, fmt.Errorf("failed to create request: %w", err)
9999
}
100100
c.addHeaders(req)
101101
// #nosec G107 -- zipURL is constructed from trusted config and parameters
102102
resp, err := c.HTTPClient.Do(req)
103103
if err != nil {
104-
return nil, fmt.Errorf("failed to GET zip: %w", err)
104+
return nil, 0, fmt.Errorf("failed to GET zip: %w", err)
105105
}
106106
if resp.StatusCode != http.StatusOK {
107107
resp.Body.Close()
108-
return nil, fmt.Errorf("bad http status from %s: %v", zipURL, resp.Status)
108+
return nil, 0, fmt.Errorf("bad http status from %s: %v", zipURL, resp.Status)
109109
}
110-
return resp.Body, nil
110+
return resp.Body, resp.ContentLength, nil
111111
}

0 commit comments

Comments
 (0)