package main //import ( // "bufio" // "context" // "encoding/json" // "fmt" // "gopkg.in/yaml.v3" // "io" // "io/ioutil" // "net" // "net/http" // "os" // "os/exec" // "path/filepath" // "strings" // "syscall" // "time" // "unsafe" //) // //// 颜色代码常量 //const ( // ColorReset = "\033[0m" // ColorRed = "\033[31m" // ColorGreen = "\033[32m" // ColorYellow = "\033[33m" // ColorBlue = "\033[34m" // ColorMagenta = "\033[35m" // ColorCyan = "\033[36m" // ColorWhite = "\033[37m" // ColorGray = "\033[90m" // // // 加粗 // ColorBoldRed = "\033[1;31m" // ColorBoldGreen = "\033[1;32m" // ColorBoldYellow = "\033[1;33m" // ColorBoldBlue = "\033[1;34m" // // // 背景色 // ColorBgRed = "\033[41m" // ColorBgGreen = "\033[42m" //) // //// 定义结构体来映射 YAML 数据 //type VersionConfig struct { // CsvVersion string `json:"csv"` // KongfzVersion string `json:"kongfz"` // LoggerVersion string `json:"logger"` // ModuleErpVersion string `json:"module-erp"` // ModuleKongfzVersion string `json:"module-kongfz"` // ModuleTaskPoolVersion string `json:"module-taskPool"` // ModuleVerifyPriceVersion string `json:"module-verifyPrice"` // ModuleCenterBookVersion string `json:"module-centerBook"` // ModuleLoginVersion string `json:"module-login"` // PicToolVersion string `json:"picTool"` // ProxyVersion string `json:"proxy"` //} // //type VerifyPriceYAML struct { // VerifyPriceLatestVersion string `yaml:"verifyPriceLatestVersion"` //} // //// 自定义日志函数,添加颜色 //func printInfo(format string, v ...interface{}) { // fmt.Printf(ColorCyan+"[信息] "+format+ColorReset+"\n", v...) //} // //func printSuccess(format string, v ...interface{}) { // fmt.Printf(ColorGreen+"[成功] "+format+ColorReset+"\n", v...) //} // //func printWarning(format string, v ...interface{}) { // fmt.Printf(ColorYellow+"[警告] "+format+ColorReset+"\n", v...) //} // //func printError(format string, v ...interface{}) { // fmt.Printf(ColorRed+"[错误] "+format+ColorReset+"\n", v...) //} // //func printDebug(format string, v ...interface{}) { // fmt.Printf(ColorGray+"[调试] "+format+ColorReset+"\n", v...) //} // //func printBanner(format string, v ...interface{}) { // fmt.Printf(ColorBoldBlue+"== "+format+" ==\n"+ColorReset, v...) //} // //func printDownload(format string, v ...interface{}) { // fmt.Printf(ColorBoldGreen+"[下载] "+format+ColorReset+"\n", v...) //} // //func printVersionInfo(label, version string) { // fmt.Printf(ColorBoldYellow+"%-30s: "+ColorCyan+"%s"+ColorReset+"\n", label, version) //} // //func main() { // // 打印彩色横幅 // fmt.Printf(ColorBoldBlue + "================================================\n") // fmt.Printf(" 核价软件更新器\n") // fmt.Printf("================================================\n" + ColorReset) // printWarning("更新时请勿操作!!!") // // 获取当前工作目录 // currentDir, err := os.Getwd() // if err != nil { // printError("获取当前目录失败: %v", err) // } // printInfo("当前目录: %v", currentDir) // // // 获取选品中心中verify_price_version_test.json // printInfo("正在检查核价软件版本...") // verifyPriceVersionJSON, err := getVerifyPriceVersionJSON() // if err != nil { // printError("读取核价软件版本信息失败: %v", err) // } // // // 直接读取yaml文件 // yamlPath := filepath.Join(currentDir, "version.yaml") // // 读取 YAML 文件 // data, err := ioutil.ReadFile(yamlPath) // if err != nil { // printError("读取YAML配置文件失败: %v", err) // } // // // 解析 YAML // var config VerifyPriceYAML // err = yaml.Unmarshal(data, &config) // if err != nil { // printError("解析 YAML 配置失败: %v", err) // } // printVersionInfo("当前核价软件版本号", config.VerifyPriceLatestVersion) // // // 检查并下载核价软件主程序 // printInfo("检查核价软件主程序...") // if _, err := os.Stat(filepath.Join(currentDir, "VerifyPriceApp.exe")); os.IsNotExist(err) { // printDownload("发现核价软件缺失,开始下载...") // url := fmt.Sprintf("https://newverifyprice.buzhiyushu.cn/exe/VerifyPriceApp_%s.exe", verifyPriceVersionJSON.VerifyPriceLatestVersion) // err = downloadEXE(url, currentDir, "VerifyPriceApp.exe") // if err != nil { // if err.Error() == "The process cannot access the file because it is being used by another process." { // printWarning("文件被占用,请重新启动与书同行.exe软件") // } else { // printError("下载核价软件失败: %v", err) // } // } else { // printSuccess("核价软件下载完成") // } // //修改yaml文件 // config.VerifyPriceLatestVersion = verifyPriceVersionJSON.VerifyPriceLatestVersion // err = writeYAML(yamlPath, config) // if err != nil { // printError("更新YAML配置文件失败: %v", err) // } // } else { // if verifyPriceVersionJSON.VerifyPriceLatestVersion != config.VerifyPriceLatestVersion || config.VerifyPriceLatestVersion == "" { // printDownload("发现新版本核价软件,开始更新...") // url := fmt.Sprintf("https://newverifyprice.buzhiyushu.cn/exe/VerifyPriceApp_%s.exe", verifyPriceVersionJSON.VerifyPriceLatestVersion) // err = downloadEXE(url, currentDir, "VerifyPriceApp.exe") // if err != nil { // if err.Error() == "The process cannot access the file because it is being used by another process." { // printWarning("文件被占用,请重新启动与书同行.exe软件") // } else { // printError("下载核价软件失败: %v", err) // } // } else { // printSuccess("核价软件更新完成") // } // //修改yaml文件 // config.VerifyPriceLatestVersion = verifyPriceVersionJSON.VerifyPriceLatestVersion // err = writeYAML(yamlPath, config) // if err != nil { // printError("更新YAML配置文件失败: %v", err) // } // } else { // printSuccess("核价软件已是最新版本") // } // } // // // 获取ES2中version.json // printInfo("正在检查DLL组件版本...") // versionsJSON, err := getVersionsJSON() // if err != nil { // printError("读取DLL版本信息失败: %v", err) // } // // // 打印版本信息标题 // printBanner("版本信息") // // // 打印所有版本信息 // printVersionInfo("最新核价软件版本", verifyPriceVersionJSON.VerifyPriceLatestVersion) // printVersionInfo("csv.dll版本号:", versionsJSON.CsvVersion) // printVersionInfo("kongfz.dll版本号:", versionsJSON.KongfzVersion) // printVersionInfo("logger.dll版本号:", versionsJSON.LoggerVersion) // printVersionInfo("module-centerBook.dll版本号:", versionsJSON.ModuleCenterBookVersion) // printVersionInfo("module-login.dll版本号:", versionsJSON.ModuleLoginVersion) // printVersionInfo("module-erp.dll版本号:", versionsJSON.ModuleErpVersion) // printVersionInfo("module-kongfz.dll版本号:", versionsJSON.ModuleKongfzVersion) // printVersionInfo("module-taskPool.dll版本号:", versionsJSON.ModuleTaskPoolVersion) // printVersionInfo("module-verifyPrice.dll版本号:", versionsJSON.ModuleVerifyPriceVersion) // printVersionInfo("picTool.dll版本号:", versionsJSON.PicToolVersion) // printVersionInfo("proxy.dll版本号:", versionsJSON.ProxyVersion) // // // 验证并更新DLL文件 // printBanner("组件检查与更新") // // // 验证csv.dll文件版本 // printInfo("检查csv.dll...") // csvVersion, err := csvDllVersion(currentDir) // if err != nil { // printWarning("获取csv.dll版本失败: %v", err) // } // if versionsJSON.CsvVersion != csvVersion && csvVersion != "" { // printDownload("csv.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "csv.dll"), "csv.dll", "") // if err != nil { // printError("下载csv.dll失败: %v", err) // } else { // printSuccess("csv.dll更新完成") // } // } else { // printSuccess("csv.dll已是最新版本") // } // // // 验证kongfz.dll文件版本 // printInfo("检查kongfz.dll...") // kongfzVersion, err := kongfzDllVersion(currentDir) // if err != nil { // printWarning("获取kongfz.dll版本失败: %v", err) // } // if versionsJSON.KongfzVersion != kongfzVersion && kongfzVersion != "" { // printDownload("kongfz.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "kongfz.dll"), "kongfz.dll", "") // if err != nil { // printError("下载kongfz.dll失败: %v", err) // } else { // printSuccess("kongfz.dll更新完成") // } // } else { // printSuccess("kongfz.dll已是最新版本") // } // // // 验证logger.dll文件版本 // printInfo("检查logger.dll...") // loggerVersion, err := loggerDllVersion(currentDir) // if err != nil { // printWarning("获取logger.dll版本失败: %v", err) // } // if versionsJSON.LoggerVersion != loggerVersion && loggerVersion != "" { // printDownload("logger.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "logger.dll"), "logger.dll", "") // if err != nil { // printError("下载logger.dll失败: %v", err) // } else { // printSuccess("logger.dll更新完成") // } // } else { // printSuccess("logger.dll已是最新版本") // } // // // 验证module-centerBook.dll文件版本 // printInfo("检查module-centerBook.dll...") // moduleCenterBookVersion, err := moduleCenterBookDllVersion(currentDir) // if err != nil { // printWarning("获取module-centerBook.dll版本失败: %v", err) // } // if versionsJSON.ModuleCenterBookVersion != moduleCenterBookVersion && moduleCenterBookVersion != "" { // printDownload("module-centerBook.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "module-centerBook.dll"), "module-centerBook.dll", "") // if err != nil { // printError("下载module-centerBook.dll失败: %v", err) // } else { // printSuccess("module-centerBook.dll更新完成") // } // } else { // printSuccess("module-centerBook.dll已是最新版本") // } // // // 验证module-login.dll文件版本 // printInfo("检查module-login.dll...") // moduleLoginVersion, err := moduleLoginDllVersion(currentDir) // if err != nil { // printWarning("获取module-login.dll版本失败: %v", err) // } // if versionsJSON.ModuleLoginVersion != moduleLoginVersion && moduleLoginVersion != "" { // printDownload("module-login.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "module-login.dll"), "module-login.dll", "") // if err != nil { // printError("下载module-login.dll失败: %v", err) // } else { // printSuccess("module-login.dll更新完成") // } // } else { // printSuccess("module-login.dll已是最新版本") // } // // // 验证module-erp.dll文件版本 // printInfo("检查module-erp.dll...") // moduleErpVersion, err := moduleErpDllVersion(currentDir) // if err != nil { // printWarning("获取module-erp.dll版本失败: %v", err) // } // if versionsJSON.ModuleErpVersion != moduleErpVersion && moduleErpVersion != "" { // printDownload("module-erp.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "module-erp.dll"), "module-erp.dll", "") // if err != nil { // printError("下载module-erp.dll失败: %v", err) // } else { // printSuccess("module-erp.dll更新完成") // } // } else { // printSuccess("module-erp.dll已是最新版本") // } // // // 验证module-kongfz.dll文件版本 // printInfo("检查module-kongfz.dll...") // moduleKongfzVersion, err := moduleKongfzDllVersion(currentDir) // if err != nil { // printWarning("获取module-kongfz.dll版本失败: %v", err) // } // if versionsJSON.ModuleKongfzVersion != moduleKongfzVersion && moduleKongfzVersion != "" { // printDownload("module-kongfz.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "module-kongfz.dll"), "module-kongfz.dll", "") // if err != nil { // printError("下载module-kongfz.dll失败: %v", err) // } else { // printSuccess("module-kongfz.dll更新完成") // } // } else { // printSuccess("module-kongfz.dll已是最新版本") // } // // // 验证module-taskPool.dll文件版本 // printInfo("检查module-taskPool.dll...") // moduleTaskPoolVersion, err := moduleTaskPoolDllVersion(currentDir) // if err != nil { // printWarning("获取module-taskPool.dll版本失败: %v", err) // } // if versionsJSON.ModuleTaskPoolVersion != moduleTaskPoolVersion && moduleTaskPoolVersion != "" { // printDownload("module-taskPool.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "module-taskPool.dll"), "module-taskPool.dll", "") // if err != nil { // printError("下载module-taskPool.dll失败: %v", err) // } else { // printSuccess("module-taskPool.dll更新完成") // } // } else { // printSuccess("module-taskPool.dll已是最新版本") // } // // // 验证module-verifyPrice.dll文件版本 // printInfo("检查module-verifyPrice.dll...") // moduleVerifyPriceVersion, err := moduleVerifyPriceDllVersion(currentDir) // if err != nil { // printWarning("获取module-verifyPrice.dll版本失败: %v", err) // } // if versionsJSON.ModuleVerifyPriceVersion != moduleVerifyPriceVersion && moduleVerifyPriceVersion != "" { // printDownload("module-verifyPrice.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "module-verifyPrice.dll"), "module-verifyPrice.dll", "") // if err != nil { // printError("下载module-verifyPrice.dll失败: %v", err) // } else { // printSuccess("module-verifyPrice.dll更新完成") // } // } else { // printSuccess("module-verifyPrice.dll已是最新版本") // } // // // 验证picTool.dll文件版本 // printInfo("检查picTool.dll...") // picToolVersion, err := picToolDllVersion(currentDir) // if err != nil { // printWarning("获取picTool.dll版本失败: %v", err) // } // if versionsJSON.PicToolVersion != picToolVersion && picToolVersion != "" { // printDownload("picTool.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "picTool.dll"), "picTool.dll", "") // if err != nil { // printError("下载picTool.dll失败: %v", err) // } else { // printSuccess("picTool.dll更新完成") // } // } else { // printSuccess("picTool.dll已是最新版本") // } // // // 验证proxy.dll文件版本 // printInfo("检查proxy.dll...") // proxyVersion, err := proxyDllVersion(currentDir) // if err != nil { // printWarning("获取proxy.dll版本失败: %v", err) // } // if versionsJSON.ProxyVersion != proxyVersion && proxyVersion != "" { // printDownload("proxy.dll需要更新") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", filepath.Join(currentDir, "dll", "proxy.dll"), "proxy.dll", "") // if err != nil { // printError("下载proxy.dll失败: %v", err) // } else { // printSuccess("proxy.dll更新完成") // } // } else { // printSuccess("proxy.dll已是最新版本") // } // // printWarning("更新时请勿操作!!!出现:立即按回车键打开核价软件,可以点击 回车键") // // // 启动提示 // printBanner("启动核价软件") // fmt.Printf("\n" + ColorBoldGreen + "立即按回车键打开核价软件..." + ColorReset) // fmt.Printf(ColorGray + "(或30秒后自动打开)\n" + ColorReset) // // // 创建带超时的输入读取器 // inputCh := make(chan bool, 1) // // // 启动一个goroutine等待用户输入 // go func() { // bufio.NewReader(os.Stdin).ReadBytes('\n') // inputCh <- true // }() // // 设置30秒超时 // timeout := 30 * time.Second // // select { // case <-inputCh: // printSuccess("用户按下了回车键,立即打开核价软件") // case <-time.After(timeout): // printWarning("等待超时(30秒),自动打开核价软件") // } // // // 尝试打开 VerifyPriceApp.exe // verifyPriceAppPath := filepath.Join(currentDir, "VerifyPriceApp.exe") // printInfo("正在启动核价软件: %s", verifyPriceAppPath) // // // 检查文件是否存在 --- TODO 存在问题,有可能打不开 VerifyPriceApp.exe // if _, err := os.Stat(verifyPriceAppPath); os.IsNotExist(err) { // printError("核价软件主程序不存在: %s", verifyPriceAppPath) // } else { // // 启动 VerifyPriceApp.exe // cmd := exec.Command(verifyPriceAppPath) // // // 设置工作目录为当前目录 // cmd.Dir = currentDir // // // 启动进程(不等待它完成) // err := cmd.Start() // if err != nil { // printError("启动核价软件失败: %v", err) // } else { // printSuccess("核价软件已启动 (PID: %d)", cmd.Process.Pid) // // // 给新进程一点时间启动(可选) // time.Sleep(100 * time.Millisecond) // } // } // // printBanner("程序执行完毕") //} // //// 将结构体写回YAML文件 //func writeYAML(filePath string, config VerifyPriceYAML) error { // // 将结构体序列化为YAML // yamlData, err := yaml.Marshal(config) // if err != nil { // return fmt.Errorf("序列化YAML失败: %v", err) // } // // // 创建备份文件(可选) // backupFilePath := filePath + ".bak" // err = backupFile(filePath, backupFilePath) // if err != nil { // printDebug("创建备份文件失败: %v", err) // } // // // 写回文件 // err = ioutil.WriteFile(filePath, yamlData, 0755) // if err != nil { // return fmt.Errorf("写入文件失败: %v", err) // } // // return nil //} // //// 备份原文件 //func backupFile(originalPath, backupPath string) error { // // 读取原文件 // data, err := ioutil.ReadFile(originalPath) // if err != nil { // return err // } // // // 写入备份文件 // return ioutil.WriteFile(backupPath, data, 0755) //} // //func downloadEXE(url, folderPath, filename string) error { // // 确保文件夹存在 // if err := os.MkdirAll(folderPath, 0755); err != nil { // return fmt.Errorf("创建文件夹失败: %v", err) // } // // // 拼接完整文件路径 // filePath := filepath.Join(folderPath, filename) // // printDebug("下载到: %s", filePath) // // // 发送HTTP请求 // resp, err := http.Get(url) // if err != nil { // return fmt.Errorf("请求失败: %v", err) // } // defer resp.Body.Close() // // // 检查响应状态 // if resp.StatusCode != http.StatusOK { // return fmt.Errorf("下载失败,状态码: %d", resp.StatusCode) // } // // // 创建文件 // file, err := os.Create(filePath) // if err != nil { // return fmt.Errorf("创建文件失败: %v", err) // } // defer file.Close() // // // 下载文件 // _, err = io.Copy(file, resp.Body) // if err != nil { // return fmt.Errorf("写入文件失败: %v", err) // } // // return nil //} // //// VersionInfo 定义 JSON 结构体 //type VersionInfo struct { // LatestVersion string `json:"latestVersion"` // HistoricalVersions []string `json:"historicalVersions"` // VerifyPriceLatestVersion string `json:"verifyPriceLatestVersion"` //} // //// 读取选品中心中verify_price_version_test.json文件 //func getVerifyPriceVersionJSON() (*VersionInfo, error) { // // 目标 URL // url := "https://newverifyprice.buzhiyushu.cn/verify_price_version.json" // // // 创建 HTTP 客户端,设置超时时间 // client := &http.Client{ // Timeout: 30 * time.Second, // } // // // 发送 GET 请求 // resp, err := client.Get(url) // if err != nil { // return nil, fmt.Errorf("请求失败: %v", err) // } // defer resp.Body.Close() // // // 检查响应状态码 // if resp.StatusCode != http.StatusOK { // return nil, fmt.Errorf("HTTP 请求失败,状态码: %d", resp.StatusCode) // } // // // 读取响应体 // body, err := io.ReadAll(resp.Body) // if err != nil { // return nil, fmt.Errorf("读取响应失败: %v", err) // } // // // 解析 JSON 数据 // var versionInfo VersionInfo // err = json.Unmarshal(body, &versionInfo) // if err != nil { // return nil, fmt.Errorf("解析 JSON 失败: %v", err) // } // return &versionInfo, nil //} // //// 读取ES2中versions.json文件 //func getVersionsJSON() (*VersionConfig, error) { // // 目标 URL // url := "http://36.212.20.113:53300/version.json" // // // 创建 HTTP 客户端,设置超时时间 // client := &http.Client{ // Timeout: 30 * time.Second, // } // // // 发送 GET 请求 // resp, err := client.Get(url) // if err != nil { // return nil, fmt.Errorf("请求失败: %v", err) // } // defer resp.Body.Close() // // // 检查响应状态码 // if resp.StatusCode != http.StatusOK { // return nil, fmt.Errorf("HTTP 请求失败,状态码: %d", resp.StatusCode) // } // // // 读取响应体 // body, err := io.ReadAll(resp.Body) // if err != nil { // return nil, fmt.Errorf("读取响应失败: %v", err) // } // // // 解析 JSON 数据 // var versionConfig VersionConfig // err = json.Unmarshal(body, &versionConfig) // if err != nil { // return nil, fmt.Errorf("解析 JSON 失败: %v", err) // } // return &versionConfig, nil //} // //// cStr 将 C 字符串指针转换为 Go 字符串 //func cStr(ptr uintptr) string { // if ptr == 0 { // return "" // } // var b []byte // for { // c := *(*byte)(unsafe.Pointer(ptr)) // if c == 0 { // break // } // b = append(b, c) // ptr++ // } // return string(b) //} // //// 查询csv.dll版本号 //func csvDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "csv.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("csv.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "csv.dll", "") // if err != nil { // return "", fmt.Errorf("下载 csv.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载csv.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找csv.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用csv.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询kongfz.dll版本号 //func kongfzDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "kongfz.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("kongfz.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "kongfz.dll", "") // if err != nil { // return "", fmt.Errorf("下载 kongfz.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载kongfz.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找kongfz.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用kongfz.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询logger.dll版本号 //func loggerDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "logger.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("logger.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "logger.dll", "") // if err != nil { // return "", fmt.Errorf("下载 logger.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载logger.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找logger.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用logger.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询module_centerBook.dll版本号 //func moduleCenterBookDllVersion(currentDir string) (string, error) { // // 方案1:使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "module-centerBook.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("module-centerBook.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "module-centerBook.dll", "") // if err != nil { // return "", fmt.Errorf("下载 module-centerBook.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载module-centerBook.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找module-centerBook.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用module-centerBook.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询module_login.dll版本号 //func moduleLoginDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "module-login.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("module-login.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "module-login.dll", "") // if err != nil { // return "", fmt.Errorf("下载 module-login.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载module-login.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找module-login.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用module-login.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询module-erp.dll版本号 //func moduleErpDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "module-erp.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("module-erp.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "module-erp.dll", "") // if err != nil { // return "", fmt.Errorf("下载 module-erp.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载module-erp.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找module-erp.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用module-erp.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询module-kongfz.dll版本号 //func moduleKongfzDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "module-kongfz.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("module-kongfz.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "module-kongfz.dll", "") // if err != nil { // return "", fmt.Errorf("下载 module-kongfz.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载module-kongfz.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找module-kongfz.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用module-kongfz.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询module-taskPool.dll版本号 //func moduleTaskPoolDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "module-taskPool.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("module-taskPool.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "module-taskPool.dll", "") // if err != nil { // return "", fmt.Errorf("下载 module-taskPool.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载module-taskPool.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找module-taskPool.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用module-taskPool.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询module-verifyPrice.dll版本号 //func moduleVerifyPriceDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "module-verifyPrice.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("module-verifyPrice.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "module-verifyPrice.dll", "") // if err != nil { // return "", fmt.Errorf("下载 module-verifyPrice.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载module-verifyPrice.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找module-verifyPrice.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用module-verifyPrice.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询picTool.dll版本号 //func picToolDllVersion(currentDir string) (string, error) { // // 使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "picTool.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("picTool.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "picTool.dll", "") // if err != nil { // return "", fmt.Errorf("下载 picTool.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载picTool.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // 你的函数名 // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找picTool.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用picTool.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // //// 查询proxy.dll版本号 //func proxyDllVersion(currentDir string) (string, error) { // // 方案1:使用绝对路径 // dllPath := filepath.Join(currentDir, "dll", "proxy.dll") // // // 判断dll文件是否存在,不存在下载新版本 // _, err := os.Stat(dllPath) // if err != nil { // if os.IsNotExist(err) { // printDownload("proxy.dll文件缺失,开始下载...") // err = downloadDLL("http://36.212.20.113:53300/api/downLoad", dllPath, "proxy.dll", "") // if err != nil { // return "", fmt.Errorf("下载 proxy.dll 文件失败: %v", err) // } // return "", nil // } // } // // // 加载DLL // dll, err := syscall.LoadDLL(dllPath) // if err != nil { // return "", fmt.Errorf("加载proxy.dll文件失败: %v", err) // } // // // 查找函数 // funcName := "GetVersion" // 你的函数名 // proc, err := dll.FindProc(funcName) // if err != nil { // return "", fmt.Errorf("查找proxy.dll GetVersion 函数失败: %v", err) // } // // // 调用函数(无参数版本) // ret, _, err := proc.Call() // if err != nil && err.Error() != "The operation completed successfully." { // return "", fmt.Errorf("调用proxy.dll GetVersion 函数失败: %v", err) // } // str := cStr(ret) // // 释放C字符串 // if proc, err = dll.FindProc("FreeCString"); err == nil { // defer proc.Call(ret) // } // return str, nil //} // ////func downloadDLL(url, outputPath, filename, version string) error { //// // 1. 确保目录存在 //// dir := filepath.Dir(outputPath) //// if err := os.MkdirAll(dir, 0755); err != nil { //// return fmt.Errorf("创建目录失败: %v", err) //// } //// //// // 2. 创建临时文件路径(避免直接操作目标文件) //// tempPath := outputPath + ".tmp" //// //// // 清理可能存在的旧临时文件 //// if _, err := os.Stat(tempPath); err == nil { //// os.Remove(tempPath) //// } //// //// // 3. 检查目标文件是否存在 //// if _, err := os.Stat(outputPath); err == nil { //// // 尝试重命名原文件(而不是直接删除) //// backupPath := outputPath + ".bak" //// if err := os.Rename(outputPath, backupPath); err != nil { //// // 重命名失败,尝试直接删除 //// for i := 0; i < 3; i++ { // 重试3次 //// if err := os.Remove(outputPath); err == nil { //// break //// } //// if i == 2 { // 最后一次尝试 //// if strings.Contains(err.Error(), "Access is denied") { //// return fmt.Errorf("文件被其他程序占用,请关闭可能使用此文件的程序后再试: %s", outputPath) //// } //// return fmt.Errorf("无法删除已存在的文件: %v", err) //// } //// time.Sleep(1 * time.Second) //// } //// } else { //// // 异步清理备份文件 //// go func() { //// time.Sleep(30 * time.Second) // 30秒后清理 //// if _, err := os.Stat(backupPath); err == nil { //// os.Remove(backupPath) //// } //// }() //// } //// } //// //// // 4. 创建HTTP客户端 //// client := &http.Client{ //// Timeout: 30 * time.Minute, //// } //// //// // 5. 发送GET请求下载文件 //// // 注意:这里先打印下载开始信息,这行会在主函数打印版本号信息之后立即执行 //// if version == "" { //// printDownload("正在下载: %s (版本: %s)", filename, "最新版本") //// } else { //// printDownload("正在下载: %s (版本: %s)", filename, version) //// } //// //// // 添加查询参数 //// req, err := http.NewRequest("GET", url, nil) //// if err != nil { //// return fmt.Errorf("创建请求失败: %v", err) //// } //// //// q := req.URL.Query() //// q.Add("filename", filename) //// if version != "" { //// q.Add("version", version) //// } //// req.URL.RawQuery = q.Encode() //// //// resp, err := client.Do(req) //// if err != nil { //// return fmt.Errorf("请求失败: %v", err) //// } //// defer resp.Body.Close() //// //// if resp.StatusCode != http.StatusOK { //// return fmt.Errorf("服务器返回错误状态码: %d", resp.StatusCode) //// } //// //// // 6. 获取文件大小 //// totalSize := resp.ContentLength //// if totalSize > 0 { //// fmt.Printf(ColorGray+"文件大小: %.2f MB\n"+ColorReset, float64(totalSize)/1024/1024) //// } //// //// // 7. 创建临时文件 //// out, err := os.OpenFile(tempPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) //// if err != nil { //// return fmt.Errorf("创建临时文件失败: %v", err) //// } //// defer out.Close() //// //// // 8. 确保下载失败时清理临时文件 //// downloadSuccess := false //// defer func() { //// if !downloadSuccess { //// os.Remove(tempPath) //// } //// }() //// //// // 9. 手动进度显示 //// startTime := time.Now() //// var downloaded int64 = 0 //// var lastUpdate time.Time //// lastUpdate = time.Now() //// //// // 10. 创建缓冲区读取 //// buf := make([]byte, 32*1024) //// for { //// n, err := resp.Body.Read(buf) //// if n > 0 { //// // 写入临时文件 //// if _, writeErr := out.Write(buf[:n]); writeErr != nil { //// return fmt.Errorf("写入文件失败: %v", writeErr) //// } //// //// // 更新下载量 //// downloaded += int64(n) //// //// // 每500ms更新一次进度 //// if time.Since(lastUpdate) > 500*time.Millisecond || err != nil { //// if totalSize > 0 { //// percent := float64(downloaded) / float64(totalSize) * 100 //// fmt.Printf("\r"+ColorCyan+"下载进度: %.2f%% (%.2f/%.2f MB)"+ColorReset, //// percent, //// float64(downloaded)/1024/1024, //// float64(totalSize)/1024/1024) //// } else { //// fmt.Printf("\r"+ColorCyan+"已下载: %.2f MB"+ColorReset, float64(downloaded)/1024/1024) //// } //// lastUpdate = time.Now() //// } //// } //// //// if err != nil { //// if err != io.EOF { //// return fmt.Errorf("读取失败: %v", err) //// } //// break //// } //// } //// //// // 下载完成,确保进度显示100% //// if totalSize > 0 && downloaded < totalSize { //// downloaded = totalSize //// } //// fmt.Printf("\r"+ColorGreen+"下载进度: 100.00%% (%.2f/%.2f MB)\n"+ColorReset, //// float64(downloaded)/1024/1024, //// float64(totalSize)/1024/1024) //// //// // 11. 关闭临时文件 //// out.Close() //// //// // 12. 验证下载的文件大小 //// if totalSize > 0 { //// if fi, err := os.Stat(tempPath); err == nil { //// if fi.Size() != totalSize { //// return fmt.Errorf("文件大小不匹配: 期望 %d, 实际 %d", totalSize, fi.Size()) //// } //// } //// } //// //// // 13. 将临时文件重命名为目标文件 //// for i := 0; i < 3; i++ { //// if err := os.Rename(tempPath, outputPath); err == nil { //// downloadSuccess = true //// break //// } //// //// if i == 2 { //// // 尝试直接复制 //// if err := copyFile(tempPath, outputPath); err != nil { //// return fmt.Errorf("保存文件失败: %v", err) //// } //// downloadSuccess = true //// } //// //// time.Sleep(500 * time.Millisecond) //// } //// //// elapsed := time.Since(startTime) //// printSuccess("下载完成: %s (耗时: %v)", filepath.Base(outputPath), elapsed.Round(time.Second)) //// //// // 14. 验证最终文件 //// if _, err := os.Stat(outputPath); err != nil { //// return fmt.Errorf("最终文件验证失败: %v", err) //// } //// //// return nil ////} // //// 主下载函数 //func downloadDLL(url, outputPath, filename, version string) error { // // 1. 确保目录存在 // dir := filepath.Dir(outputPath) // if err := os.MkdirAll(dir, 0755); err != nil { // return fmt.Errorf("创建目录失败: %v", err) // } // // // 2. 创建临时文件路径 // tempPath := outputPath + ".tmp" // // // 3. 清理可能存在的旧临时文件 // if _, err := os.Stat(tempPath); err == nil { // os.Remove(tempPath) // } // // // 4. 检查目标文件是否存在 // if _, err := os.Stat(outputPath); err == nil { // backupPath := outputPath + ".bak" // if err := os.Rename(outputPath, backupPath); err != nil { // // 重命名失败,尝试直接删除 // for i := 0; i < 3; i++ { // if err := os.Remove(outputPath); err == nil { // break // } // if i == 2 { // if strings.Contains(err.Error(), "Access is denied") { // return fmt.Errorf("文件被其他程序占用,请关闭可能使用此文件的程序后再试: %s", outputPath) // } // return fmt.Errorf("无法删除已存在的文件: %v", err) // } // time.Sleep(1 * time.Second) // } // } else { // // 异步清理备份文件 // go func() { // time.Sleep(30 * time.Second) // if _, err := os.Stat(backupPath); err == nil { // os.Remove(backupPath) // } // }() // } // } // // // 5. 打印下载信息 // if version == "" { // printDownload("正在下载: %s (版本: 最新版本)", filename) // } else { // printDownload("正在下载: %s (版本: %s)", filename, version) // } // // // 6. 首先尝试获取文件大小信息(HEAD请求) // headClient := &http.Client{ // Timeout: 10 * time.Second, // } // // headReq, err := http.NewRequest("HEAD", url, nil) // if err != nil { // printError("创建HEAD请求失败,使用默认超时设置: %v", err) // } else { // // 添加查询参数 // q := headReq.URL.Query() // q.Add("filename", filename) // if version != "" { // q.Add("version", version) // } // headReq.URL.RawQuery = q.Encode() // headReq.Header.Set("User-Agent", "DLL-Downloader/1.0") // // resp, err := headClient.Do(headReq) // if err == nil && resp.StatusCode == http.StatusOK { // if contentLength := resp.ContentLength; contentLength > 0 { // fmt.Printf(ColorGray+"获取到文件大小: %.2f MB\n"+ColorReset, // float64(contentLength)/1024/1024) // } // resp.Body.Close() // } // } // // // 7. 创建长时间下载的HTTP客户端 // // 使用自定义Transport,不设置Client.Timeout,改用context控制 // transport := &http.Transport{ // Proxy: http.ProxyFromEnvironment, // DialContext: (&net.Dialer{ // Timeout: 30 * time.Second, // KeepAlive: 30 * time.Second, // DualStack: true, // }).DialContext, // ForceAttemptHTTP2: true, // MaxIdleConns: 100, // MaxIdleConnsPerHost: 10, // IdleConnTimeout: 90 * time.Second, // TLSHandshakeTimeout: 15 * time.Second, // ExpectContinueTimeout: 5 * time.Second, // ResponseHeaderTimeout: 30 * time.Second, // ReadBufferSize: 128 * 1024, // 128KB // WriteBufferSize: 128 * 1024, // // 禁用读写超时,通过活动检测控制 // } // // client := &http.Client{ // Transport: transport, // // 重要:不设置Timeout,使用context控制 // } // // // 8. 创建下载请求 // // 使用3小时的context超时,但通过活动检测防止死连接 // ctx, cancel := context.WithTimeout(context.Background(), 3*time.Hour) // defer cancel() // // req, err := http.NewRequestWithContext(ctx, "GET", url, nil) // if err != nil { // return fmt.Errorf("创建请求失败: %v", err) // } // // // 添加查询参数 // q := req.URL.Query() // q.Add("filename", filename) // if version != "" { // q.Add("version", version) // } // req.URL.RawQuery = q.Encode() // // // 添加请求头 // req.Header.Set("User-Agent", "DLL-Downloader/1.0") // req.Header.Set("Accept", "*/*") // req.Header.Set("Accept-Encoding", "gzip, deflate") // req.Header.Set("Connection", "keep-alive") // // // 9. 发送请求 // resp, err := client.Do(req) // if err != nil { // if strings.Contains(err.Error(), "context deadline exceeded") { // return fmt.Errorf("连接超时,请检查网络连接: %v", err) // } // return fmt.Errorf("请求失败: %v", err) // } // defer resp.Body.Close() // // if resp.StatusCode != http.StatusOK { // body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) // return fmt.Errorf("服务器返回错误: %d - %s", resp.StatusCode, string(body)) // } // // // 10. 获取文件大小 // totalSize := resp.ContentLength // if totalSize > 0 { // fmt.Printf(ColorGray+"文件大小: %.2f MB\n"+ColorReset, float64(totalSize)/1024/1024) // // // 根据文件大小提供预估时间 // // 假设最低速度 50KB/s // minSpeed := 50.0 * 1024 // estimatedTime := time.Duration(float64(totalSize)/minSpeed) * time.Second // if estimatedTime > 30*time.Second { // fmt.Printf(ColorGray+"预估下载时间: %v (基于50KB/s最低速度)\n"+ColorReset, // estimatedTime.Round(time.Second)) // } // } else { // fmt.Println(ColorGray + "文件大小: 未知" + ColorReset) // } // // // 11. 创建临时文件 // out, err := os.OpenFile(tempPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755) // if err != nil { // return fmt.Errorf("创建临时文件失败: %v", err) // } // defer out.Close() // // // 12. 确保下载失败时清理临时文件 // downloadSuccess := false // defer func() { // if !downloadSuccess { // os.Remove(tempPath) // } // }() // // // 13. 活动检测机制 // activityCh := make(chan time.Time, 100) // 缓冲通道,避免阻塞 // var lastActivity time.Time // lastActivity = time.Now() // // // 创建活动检测的reader // activityReader := &activityReader{ // reader: resp.Body, // activityCh: activityCh, // activityPtr: &lastActivity, // } // // // 启动活动检测goroutine // activityCtx, activityCancel := context.WithCancel(context.Background()) // defer activityCancel() // // go func() { // ticker := time.NewTicker(30 * time.Second) // 每30秒检查一次活动 // defer ticker.Stop() // // for { // select { // case <-activityCtx.Done(): // return // case activityTime := <-activityCh: // lastActivity = activityTime // case <-ticker.C: // // 检查最近60秒内是否有活动 // if time.Since(lastActivity) > 60*time.Second { // printError("下载活动超时,60秒内没有收到数据") // cancel() // 取消主context // return // } // } // } // }() // // // 14. 下载进度显示 // startTime := time.Now() // var downloaded int64 = 0 // var lastUpdate time.Time // lastUpdate = time.Now() // // // 15. 创建缓冲区 // buf := make([]byte, 128*1024) // 128KB缓冲区 // // // 显示初始进度 // fmt.Print(ColorCyan + "下载进度: 0.00% (0.00/0.00 MB)" + ColorReset) // // for { // // 检查context是否被取消 // select { // case <-ctx.Done(): // return fmt.Errorf("下载被取消: %v", ctx.Err()) // default: // // 继续下载 // } // // n, err := activityReader.Read(buf) // if n > 0 { // // 写入临时文件 // if _, writeErr := out.Write(buf[:n]); writeErr != nil { // return fmt.Errorf("写入文件失败: %v", writeErr) // } // // // 更新下载量 // downloaded += int64(n) // // // 更新进度显示(每秒最多更新一次) // if time.Since(lastUpdate) > 1*time.Second || err != nil { // if totalSize > 0 { // percent := float64(downloaded) / float64(totalSize) * 100 // elapsed := time.Since(startTime).Seconds() // speed := 0.0 // if elapsed > 0 { // speed = float64(downloaded) / elapsed / 1024 / 1024 // } // // // 计算剩余时间 // remaining := time.Duration(0) // if speed > 0 && downloaded > 0 { // remainingSecs := float64(totalSize-downloaded) / (float64(downloaded) / elapsed) // remaining = time.Duration(remainingSecs) * time.Second // } // // // 清除当前行并显示进度 // fmt.Printf("\r\033[K"+ColorCyan+"下载进度: %.2f%% (%.2f/%.2f MB) 速度: %.2f MB/s 剩余: %v"+ColorReset, // percent, // float64(downloaded)/1024/1024, // float64(totalSize)/1024/1024, // speed, // remaining.Round(time.Second)) // } else { // // 未知文件大小的情况 // elapsed := time.Since(startTime).Seconds() // speed := 0.0 // if elapsed > 0 { // speed = float64(downloaded) / elapsed / 1024 / 1024 // } // fmt.Printf("\r\033[K"+ColorCyan+"已下载: %.2f MB 速度: %.2f MB/s"+ColorReset, // float64(downloaded)/1024/1024, // speed) // } // lastUpdate = time.Now() // } // } // // if err != nil { // if err == io.EOF { // break // } // // 检查是否是context取消的错误 // if ctx.Err() != nil { // return fmt.Errorf("下载中断: %v", ctx.Err()) // } // return fmt.Errorf("读取数据失败: %v", err) // } // } // // // 16. 下载完成,显示最终进度 // if totalSize > 0 && downloaded < totalSize { // downloaded = totalSize // 确保显示100% // } // // if totalSize > 0 { // fmt.Printf("\r\033[K"+ColorGreen+"下载完成: 100.00%% (%.2f/%.2f MB)\n"+ColorReset, // float64(downloaded)/1024/1024, // float64(totalSize)/1024/1024) // } else { // fmt.Printf("\r\033[K"+ColorGreen+"下载完成: %.2f MB\n"+ColorReset, // float64(downloaded)/1024/1024) // } // // // 停止活动检测 // activityCancel() // // // 17. 验证下载的文件大小 // if totalSize > 0 { // fi, err := os.Stat(tempPath) // if err != nil { // return fmt.Errorf("无法验证下载文件: %v", err) // } // if fi.Size() != totalSize { // return fmt.Errorf("文件大小不匹配: 期望 %d 字节, 实际 %d 字节", totalSize, fi.Size()) // } // } // // // 18. 将临时文件重命名为目标文件 // maxRetries := 5 // for i := 0; i < maxRetries; i++ { // if err := os.Rename(tempPath, outputPath); err == nil { // downloadSuccess = true // break // } // // if i == maxRetries-1 { // // 最后一次尝试:使用复制方式 // if err := copyFile(tempPath, outputPath); err != nil { // return fmt.Errorf("保存文件失败: %v", err) // } // downloadSuccess = true // } else { // // 等待后重试 // time.Sleep(500 * time.Millisecond * time.Duration(i+1)) // } // } // // // 19. 验证最终文件 // fi, err := os.Stat(outputPath) // if err != nil { // return fmt.Errorf("最终文件验证失败: %v", err) // } // // elapsed := time.Since(startTime) // speed := float64(fi.Size()) / elapsed.Seconds() / 1024 / 1024 // printSuccess("下载完成: %s (大小: %.2f MB, 耗时: %v, 平均速度: %.2f MB/s)", // filepath.Base(outputPath), // float64(fi.Size())/1024/1024, // elapsed.Round(time.Second), // speed) // // return nil //} // //// 活动检测读取器 //type activityReader struct { // reader io.Reader // activityCh chan<- time.Time // activityPtr *time.Time //} // //func (r *activityReader) Read(p []byte) (n int, err error) { // n, err = r.reader.Read(p) // if n > 0 { // now := time.Now() // r.activityCh <- now // if r.activityPtr != nil { // *r.activityPtr = now // } // } // return //} // //// 辅助函数:复制文件 //func copyFile(src, dst string) error { // source, err := os.Open(src) // if err != nil { // return err // } // defer source.Close() // // destination, err := os.Create(dst) // if err != nil { // return err // } // defer destination.Close() // // _, err = io.Copy(destination, source) // return err //} // //// 辅助函数:检查文件是否被占用 //func isFileLocked(filepath string) bool { // file, err := os.OpenFile(filepath, os.O_RDWR, 0666) // if err != nil { // return strings.Contains(err.Error(), "The process cannot access the file") // } // file.Close() // return false //}