Enhance Download Functionality with Proxy and Progress Tracking
- Implemented advanced download utility with proxy support for SOCKS5 and HTTP protocols - Added progress tracking with human-readable file size and download percentage - Updated go.mod and go.sum to include new dependencies for proxy and networking - Created flexible proxy client generation for different proxy types - Improved error handling and logging in download process
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -14,35 +15,94 @@ func DownloadFile(url string, path string) (bool, string) {
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
// 发送GET请求
|
||||
return DownloadFileWithClient(client, url, path)
|
||||
}
|
||||
|
||||
func DownloadFileWithClient(client *http.Client, url string, path string) (bool, string) {
|
||||
return downloadWithProgress(client, url, path)
|
||||
}
|
||||
|
||||
// 带进度显示的下载函数
|
||||
func downloadWithProgress(client *http.Client, url, dest string) (bool, string) {
|
||||
// 创建目标文件
|
||||
file, err := os.Create(dest)
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("创建文件失败: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 发起请求
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("下载文件失败: %v", err)
|
||||
return false, fmt.Sprintf("HTTP请求失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 检查响应状态码
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return false, fmt.Sprintf("下载文件失败,HTTP状态码: %d", resp.StatusCode)
|
||||
return false, fmt.Sprintf("服务器返回错误状态码: %s", resp.Status)
|
||||
}
|
||||
|
||||
// 创建目标文件
|
||||
out, err := os.Create(path)
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("创建文件失败: %v", err)
|
||||
}
|
||||
defer out.Close()
|
||||
// 获取文件大小
|
||||
size := resp.ContentLength
|
||||
var downloaded int64
|
||||
|
||||
// 将响应内容写入文件
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("写入文件失败: %v", err)
|
||||
// 创建带进度跟踪的Reader
|
||||
progressReader := &progressReader{
|
||||
Reader: resp.Body,
|
||||
Reporter: func(r int64) {
|
||||
downloaded += r
|
||||
printProgress(downloaded, size)
|
||||
},
|
||||
}
|
||||
|
||||
// 检查文件是否存在
|
||||
if !FileExistAndNotNull(path) {
|
||||
return false, fmt.Sprintf("文件下载失败: 文件为空 => %s", path)
|
||||
// 执行拷贝
|
||||
if _, err := io.Copy(file, progressReader); err != nil {
|
||||
return false, fmt.Sprintf("文件拷贝失败: %w", err)
|
||||
}
|
||||
|
||||
return true, fmt.Sprintf("文件下载成功: %s", path)
|
||||
fmt.Print("\n") // 保持最后进度显示的完整性
|
||||
return true, fmt.Sprintf("文件下载成功: %s", dest)
|
||||
}
|
||||
|
||||
// 进度跟踪Reader
|
||||
type progressReader struct {
|
||||
io.Reader
|
||||
Reporter func(r int64)
|
||||
}
|
||||
|
||||
func (pr *progressReader) Read(p []byte) (int, error) {
|
||||
n, err := pr.Reader.Read(p)
|
||||
if n > 0 {
|
||||
pr.Reporter(int64(n))
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// 打印进度信息
|
||||
func printProgress(downloaded, total int64) {
|
||||
const barLength = 40
|
||||
percent := float64(downloaded) / float64(total) * 100
|
||||
|
||||
// 生成进度条
|
||||
filled := int(barLength * downloaded / total)
|
||||
bar := fmt.Sprintf("[%s%s]",
|
||||
strings.Repeat("=", filled),
|
||||
strings.Repeat(" ", barLength-filled))
|
||||
|
||||
// 格式化为人类可读大小
|
||||
humanSize := func(bytes int64) string {
|
||||
const unit = 1024
|
||||
if bytes < unit {
|
||||
return fmt.Sprintf("%d B", bytes)
|
||||
}
|
||||
div, exp := int64(unit), 0
|
||||
for n := bytes / unit; n >= unit; n /= unit {
|
||||
div *= unit
|
||||
exp++
|
||||
}
|
||||
return fmt.Sprintf("%.1f %ciB", float64(bytes)/float64(div), "KMGTPE"[exp])
|
||||
}
|
||||
|
||||
fmt.Printf("\r%-45s %6.2f%% %s/%s", bar, percent,
|
||||
humanSize(downloaded), humanSize(total))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user