enhanced: download progress
This commit is contained in:
parent
97b18d8c5c
commit
7380574143
6
app.go
6
app.go
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
|
|
||||||
// Check server response
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return fmt.Errorf("bad status: %s", resp.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查文件是否已存在
|
||||||
|
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()
|
||||||
|
|
||||||
|
// 创建一个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
|
||||||
|
}
|
Loading…
Reference in New Issue