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 (
"MacFastLookup/service"
"context"
"fmt"
"os"
"path/filepath"
@ -37,7 +38,8 @@ func (a *App) StartDownload() {
os.Mkdir(path, 0755)
}
service.DownloadFile("https://tools.taurusxin.com/macfastlookup/mac_vendors.sqlite3", dbFilePath, true, func(progress, total int64) {
runtime.EventsEmit(a.ctx, "download-progress", float32(progress / total))
service.EnhancedDownload("https://tools.taurusxin.com/macfastlookup/mac_vendors.sqlite3", dbFilePath, true, func(downloaded, total, rate int64, packageName string) {
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)
})
EventsOn('download-progress', (progress: number) => {
setDownloadProgress(progress * 100)
if (progress === 1) {
setDownloadProgress(progress)
if (progress === 100) {
props.onFinish()
setTitle('Completed')
setIsDisabled(false)

View File

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