Files
ProjectOctopus/agent-wdd/utils/DownloadUtils.go
zeaslity 5c39bd7594 Enhance Docker Installation and Management Commands
- Improved Docker installation process for Ubuntu systems
- Added support for dynamic Docker version detection
- Enhanced Docker local and online installation commands
- Implemented more robust Docker removal functionality
- Updated Docker installation to use system-specific package sources
- Added better error handling and logging for Docker operations
- Refined Docker service startup and configuration checks
2025-02-28 17:45:12 +08:00

153 lines
3.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package utils
import (
"agent-wdd/log"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
func DownloadFile(url string, path string) (bool, string) {
// 创建HTTP客户端
client := &http.Client{
Timeout: 5 * time.Second,
}
return DownloadFileWithClient(client, url, path)
}
// DownloadFileWithClient 使用http客户端下载文件
func DownloadFileWithClient(client *http.Client, url string, path string) (bool, string) {
// path如果是一个目录则需要获取文件名
// 获取url使用 / 分割最后的一部分
// 如果path是目录则需要获取文件名
if IsDirOrFile(path) {
fileName := strings.Split(url, "/")[len(strings.Split(url, "/"))-1]
path = filepath.Join(path, fileName)
log.Info("path是目录自动获取文件名为 => : %s", path)
}
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("创建文件失败: %s", err.Error())
}
defer file.Close()
// 发起请求
resp, err := client.Get(url)
if err != nil {
return false, fmt.Sprintf("HTTP请求失败: %s", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return false, fmt.Sprintf("服务器返回错误状态码: %s", resp.Status)
}
// 获取文件大小
size := resp.ContentLength
var downloaded int64
// 不支持下载超过10GB的文件
if size > 10*1024*1024*1024 || size < 0 {
log.Error("文件大小超过10GB或者文件大小未知不支持高级下载方式! 尝试使用wget下载")
return downloadFileByWget(url, dest)
}
// 打印下载信息
fmt.Printf("开始下载: %s 大小: %s\n", url, HumanSizeInt(size))
// 创建带进度跟踪的Reader
progressReader := &progressReader{
Reader: resp.Body,
Reporter: func(r int64) {
downloaded += r
printProgress(downloaded, size)
},
}
// 执行拷贝
if _, err := io.Copy(file, progressReader); err != nil {
return false, fmt.Sprintf("文件拷贝失败: %s", err.Error())
}
fmt.Print("\n") // 保持最后进度显示的完整性
return true, fmt.Sprintf("文件下载成功: %s", dest)
}
// 使用wget下载文件
func downloadFileByWget(url, dest string) (bool, string) {
log.Info("使用wget下载文件: %s", fmt.Sprintf("wget %s -qO %s", url, dest))
cmd := exec.Command("wget", url, "-qO", dest)
_, err := cmd.CombinedOutput()
if err != nil {
return false, fmt.Sprintf("wget下载失败: %s", err.Error())
}
// 检查文件是否存在且不为空
fileInfo, err := os.Stat(dest)
if err != nil || fileInfo.Size() == 0 {
return false, fmt.Sprintf("wget下载失败 文件不存在或为空: %s", dest)
}
return true, fmt.Sprintf("wget下载成功: %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))
}