Skip to content

Commit c7259b1

Browse files
committed
fix(ota): downloads no longer fail on bluetooth
1 parent 0a05031 commit c7259b1

File tree

2 files changed

+177
-28
lines changed

2 files changed

+177
-28
lines changed

main.go

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -794,37 +794,22 @@ func main() {
794794
defer os.RemoveAll(tempDir)
795795

796796
imgPath := filepath.Join(tempDir, "update.tar.zst")
797-
imgResp, err := http.Get(requestData.ImageURL)
798-
if err != nil {
797+
if err := utils.DownloadWithResume(requestData.ImageURL, imgPath, func(complete, total int64, speed float64) {
798+
if total > 0 {
799+
percent := float64(complete) / float64(total) * 100
800+
broadcastProgress(utils.ProgressMessage{
801+
Type: "progress",
802+
Stage: "download",
803+
BytesComplete: complete,
804+
BytesTotal: total,
805+
Speed: float64(int(speed*10)) / 10,
806+
Percent: float64(int(percent*10)) / 10,
807+
})
808+
}
809+
}); err != nil {
799810
utils.SetUpdateStatus(false, "", fmt.Sprintf("Failed to download image: %v", err))
800811
return
801812
}
802-
defer imgResp.Body.Close()
803-
804-
imgFile, err := os.Create(imgPath)
805-
if err != nil {
806-
utils.SetUpdateStatus(false, "", fmt.Sprintf("Failed to create image file: %v", err))
807-
return
808-
}
809-
defer imgFile.Close()
810-
811-
contentLength := imgResp.ContentLength
812-
progressReader := utils.NewProgressReader(imgResp.Body, contentLength, func(complete, total int64, speed float64) {
813-
percent := float64(complete) / float64(total) * 100
814-
broadcastProgress(utils.ProgressMessage{
815-
Type: "progress",
816-
Stage: "download",
817-
BytesComplete: complete,
818-
BytesTotal: total,
819-
Speed: float64(int(speed*10)) / 10,
820-
Percent: float64(int(percent*10)) / 10,
821-
})
822-
})
823-
824-
if _, err := io.Copy(imgFile, progressReader); err != nil {
825-
utils.SetUpdateStatus(false, "", fmt.Sprintf("Failed to save image file: %v", err))
826-
return
827-
}
828813

829814
utils.SetUpdateStatus(true, "flash", "")
830815
if err := utils.UpdateSystem(imgPath, requestData.Sum, broadcastProgress); err != nil {

utils/downloader.go

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
"os"
8+
"strconv"
9+
"strings"
10+
"time"
11+
)
12+
13+
func parseTotalFromContentRange(header string) (int64, bool) {
14+
if header == "" {
15+
return 0, false
16+
}
17+
slash := strings.LastIndex(header, "/")
18+
if slash == -1 || slash == len(header)-1 {
19+
return 0, false
20+
}
21+
totalStr := header[slash+1:]
22+
if totalStr == "*" {
23+
return 0, false
24+
}
25+
total, err := strconv.ParseInt(totalStr, 10, 64)
26+
if err != nil || total <= 0 {
27+
return 0, false
28+
}
29+
return total, true
30+
}
31+
32+
func DownloadWithResume(url string, destPath string, onProgress func(int64, int64, float64)) error {
33+
client := &http.Client{}
34+
35+
var knownTotal int64 = -1
36+
if headReq, err := http.NewRequest("HEAD", url, nil); err == nil {
37+
if headResp, err := client.Do(headReq); err == nil {
38+
if headResp.Body != nil {
39+
headResp.Body.Close()
40+
}
41+
if headResp.StatusCode >= 200 && headResp.StatusCode < 300 {
42+
if headResp.ContentLength > 0 {
43+
knownTotal = headResp.ContentLength
44+
}
45+
if cr := headResp.Header.Get("Content-Range"); knownTotal <= 0 && cr != "" {
46+
if t, ok := parseTotalFromContentRange(cr); ok {
47+
knownTotal = t
48+
}
49+
}
50+
}
51+
}
52+
}
53+
54+
backoff := time.Second
55+
maxBackoff := 10 * time.Second
56+
57+
for {
58+
var offset int64 = 0
59+
if st, err := os.Stat(destPath); err == nil {
60+
offset = st.Size()
61+
} else if !os.IsNotExist(err) {
62+
return err
63+
}
64+
65+
req, err := http.NewRequest("GET", url, nil)
66+
if err != nil {
67+
return err
68+
}
69+
if offset > 0 {
70+
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
71+
}
72+
73+
resp, err := client.Do(req)
74+
if err != nil {
75+
time.Sleep(backoff)
76+
if backoff < maxBackoff {
77+
backoff *= 2
78+
if backoff > maxBackoff {
79+
backoff = maxBackoff
80+
}
81+
}
82+
continue
83+
}
84+
85+
if offset > 0 && resp.StatusCode == http.StatusOK {
86+
if resp.Body != nil {
87+
resp.Body.Close()
88+
}
89+
if err := os.Truncate(destPath, 0); err != nil {
90+
return err
91+
}
92+
offset = 0
93+
continue
94+
}
95+
96+
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
97+
b, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
98+
if resp.Body != nil {
99+
resp.Body.Close()
100+
}
101+
return fmt.Errorf("unexpected status %s: %s", resp.Status, strings.TrimSpace(string(b)))
102+
}
103+
104+
if knownTotal <= 0 {
105+
if resp.StatusCode == http.StatusPartialContent {
106+
if t, ok := parseTotalFromContentRange(resp.Header.Get("Content-Range")); ok {
107+
knownTotal = t
108+
}
109+
} else if resp.ContentLength > 0 {
110+
knownTotal = resp.ContentLength
111+
}
112+
}
113+
114+
f, err := os.OpenFile(destPath, os.O_CREATE|os.O_WRONLY, 0644)
115+
if err != nil {
116+
if resp.Body != nil {
117+
resp.Body.Close()
118+
}
119+
return err
120+
}
121+
if _, err := f.Seek(offset, io.SeekStart); err != nil {
122+
f.Close()
123+
if resp.Body != nil {
124+
resp.Body.Close()
125+
}
126+
return err
127+
}
128+
129+
pr := NewProgressReader(resp.Body, knownTotal, func(complete, total int64, speed float64) {
130+
onProgress(offset+complete, knownTotal, speed)
131+
})
132+
133+
_, err = io.Copy(f, pr)
134+
f.Close()
135+
if resp.Body != nil {
136+
resp.Body.Close()
137+
}
138+
if err != nil {
139+
time.Sleep(backoff)
140+
if backoff < maxBackoff {
141+
backoff *= 2
142+
if backoff > maxBackoff {
143+
backoff = maxBackoff
144+
}
145+
}
146+
continue
147+
}
148+
149+
if st, err := os.Stat(destPath); err == nil {
150+
if knownTotal > 0 && st.Size() >= knownTotal {
151+
onProgress(knownTotal, knownTotal, 0)
152+
return nil
153+
}
154+
}
155+
156+
time.Sleep(backoff)
157+
if backoff < maxBackoff {
158+
backoff *= 2
159+
if backoff > maxBackoff {
160+
backoff = maxBackoff
161+
}
162+
}
163+
}
164+
}

0 commit comments

Comments
 (0)