enhanced: download progress

This commit is contained in:
TaurusXin 2024-07-25 10:06:09 +08:00
parent 97b18d8c5c
commit 7380574143
3 changed files with 79 additions and 76 deletions

6
app.go
View File

@ -3,6 +3,7 @@ package main
import ( import (
"MacFastLookup/service" "MacFastLookup/service"
"context" "context"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
@ -37,7 +38,8 @@ func (a *App) StartDownload() {
os.Mkdir(path, 0755) os.Mkdir(path, 0755)
} }
service.DownloadFile("https://tools.taurusxin.com/macfastlookup/mac_vendors.sqlite3", dbFilePath, true, func(progress, total int64) { service.EnhancedDownload("https://tools.taurusxin.com/macfastlookup/mac_vendors.sqlite3", dbFilePath, true, func(downloaded, total, rate int64, packageName string) {
runtime.EventsEmit(a.ctx, "download-progress", float32(progress / total)) fmt.Printf("\rDownloading[%s][ %d%% ][%d/%d]", packageName, rate, downloaded, total)
runtime.EventsEmit(a.ctx, "download-progress", rate)
}) })
} }

View File

@ -27,8 +27,8 @@ const Download = (props: { onFinish: () => void }) => {
console.log(res) console.log(res)
}) })
EventsOn('download-progress', (progress: number) => { EventsOn('download-progress', (progress: number) => {
setDownloadProgress(progress * 100) setDownloadProgress(progress)
if (progress === 1) { if (progress === 100) {
props.onFinish() props.onFinish()
setTitle('Completed') setTitle('Completed')
setIsDisabled(false) setIsDisabled(false)

View File

@ -1,83 +1,84 @@
package service package service
import ( import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"os" "os"
"strconv" "path/filepath"
) )
// ProgressWriter is a custom writer to track progress and execute a callback // Counter 接口定义了进度追踪器应实现的方法
type ProgressWriter struct { type Counter interface {
io.Writer Write(p []byte) (int, error)
Total int64 SetTotal(total int64)
Progress int64
Callback func(progress int64, total int64)
} }
func (pw *ProgressWriter) Write(p []byte) (int, error) { // WriteCounter 实现了 Counter 接口
n, err := pw.Writer.Write(p) type WriteCounter struct {
if err != nil { Total int64
return n, err Current int64
} Rate int64
pw.Progress += int64(n) Package string
pw.Callback(pw.Progress, pw.Total) ProgressCb ProgressCallback
return n, nil
} }
func DownloadFile(url string, filePath string, overwrite bool, callback func(progress int64, total int64)) error { // ProgressCallback 是用于报告下载进度的函数类型
// Check if the file exists type ProgressCallback func(bytesDownloaded, totalBytes int64, rate int64, packageName string)
if _, err := os.Stat(filePath); err == nil {
if overwrite {
// Overwrite the file if it exists
if err := os.Remove(filePath); err != nil {
return err
}
} else {
return fmt.Errorf("file %s already exists", filePath)
}
}
// Create the file func (w *WriteCounter) Write(p []byte) (int, error) {
out, err := os.Create(filePath) n := len(p)
if err != nil { w.Current += int64(n)
return err w.Rate = w.Current * 100 / w.Total
} if w.ProgressCb != nil {
defer out.Close() w.ProgressCb(w.Current, w.Total, w.Rate, w.Package)
}
// Get the data return n, nil
resp, err := http.Get(url) }
if err != nil {
return err func (w *WriteCounter) SetTotal(total int64) {
} w.Total = total
defer resp.Body.Close() }
// EnhancedDownload 下载文件并报告进度
// Check server response func EnhancedDownload(url string, path string, overwrite bool, progressCb ProgressCallback) error {
if resp.StatusCode != http.StatusOK { // 如果路径为空,使用URL中的文件名
return fmt.Errorf("bad status: %s", resp.Status) if path == "" {
} path = filepath.Base(url)
}
// Get the size
size, err := strconv.Atoi(resp.Header.Get("Content-Length")) // 检查文件是否已存在
if err != nil { if _, err := os.Stat(path); err == nil && !overwrite {
return err return fmt.Errorf("文件 %s 已存在且未设置覆盖", path)
} }
// Create progress writer // 创建HTTP请求
pw := &ProgressWriter{ resp, err := http.Get(url)
Writer: out, if err != nil {
Total: int64(size), return fmt.Errorf("request %s error: %v", url, err)
Callback: callback, }
} defer resp.Body.Close()
// Write the body to file with progress // 创建输出文件
_, err = io.Copy(pw, resp.Body) out, err := os.Create(path)
if err != nil { if err != nil {
return err return err
} }
defer out.Close()
fmt.Println("\nDownload complete")
return nil // 创建一个WriteCounter来跟踪进度
counter := &WriteCounter{
Total: resp.ContentLength,
Package: filepath.Base(path),
ProgressCb: progressCb,
}
// 使用TeeReader来同时写入文件和更新进度
_, err = io.Copy(out, io.TeeReader(resp.Body, counter))
if err != nil {
return fmt.Errorf("write error: %v", err)
}
fmt.Printf("\ndownload [ %v ] -> [ %s ] success\n", url, path)
return nil
} }