package service import ( "basic.com/valib/logger.git" "errors" "fmt" "io" "net/http" "os" "path" "strconv" "strings" "sync" "vamicro/extend/util" ) //正在安装列表 var insIngMap sync.Map //判断是否在安装中 func IsInstalling(id string) bool { _, ok := insIngMap.Load(id) return ok } //安装进度 type InsProgress struct { Status string `json:"status"` Progress int `json:"progress"` Size uint64 `json:"size"` IsDone bool `json:"isDone"` //不管成功或者失败,标志本次安装已完成 } const ( InsStatus_Downloading = "下载中..." InsStatus_Err = "安装包下载失败" InsStatus_UnPackErr = "安装包解压失败" InsStatus_PackageChecking = "安装包校验中..." InsStatus_CheckErr = "安装包校验失败" InsStatus_Installing = "安装中..." InsStatus_InstallErr = "安装失败" InsStatus_Done = "已安装" ) type WriteCounter struct { Total uint64 iPgs *InsProgress } func (wc *WriteCounter) PrintProgress() { logger.Info(strings.Repeat(" ", 35)) //logger.Info("Downloading... ",humanize.Bytes(wc.Total)," complete") percent := (wc.Total * 100) / wc.iPgs.Size wc.iPgs.Progress = int(percent) } func (wc *WriteCounter) Write(p []byte) (int, error) { n := len(p) wc.Total += uint64(n) wc.PrintProgress() return n, nil } //下载文件 func DownloadFile(fPath string, url string, iProgress *InsProgress) error { f, err := os.Create(fPath) if err != nil { return err } resp, err := http.Get(url) if err != nil { f.Close() return err } defer resp.Body.Close() counter := &WriteCounter{ iPgs: iProgress, } if _, err = io.Copy(f, io.TeeReader(resp.Body, counter)); err != nil { f.Close() return err } fmt.Printf("\n") f.Close() //if err = os.Rename(fPath, fPath);err != nil { // return err //} return nil } type downPara struct { URL string //待下载文件的url FileName string //待下载文件的名称 } //procPath 下载到目的文件夹 func downloadExtraFile(downloadDir string, extra downPara, fb func(length, downLen int64)) error { if extra.URL == "" { return nil } var ( fsize int64 buf = make([]byte, 32*1024) written int64 ) // 创建应用下载目录, 后续会直接剪切到编译环境 //downloadDir := path.Join(procPath, "pre-install-sdks") //err := dirPing(downloadDir) //if err != nil { // logger.Warn("pack error: can not create dir.", err) // return errors.New("can not create dir") //} downloadPath := path.Join(downloadDir, extra.FileName) tmpFilePath := downloadPath + ".download" logger.Debug(tmpFilePath) //创建一个http client client := new(http.Client) //client.Timeout = time.Second * 60 //设置超时时间 //get方法获取资源 resp, err := client.Get(extra.URL) if err != nil { logger.Error("client.Get err:", err) return err } //读取服务器返回的文件大小 fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32) if err != nil { logger.Error("读取服务器返回文件大小err: ", err) } if isFileExist(downloadPath, fsize) { return err } logger.Debug("fsize", fsize) //创建文件 file, err := os.Create(tmpFilePath) if err != nil { logger.Error("os.Create err: ", err) return err } defer file.Close() if resp.Body == nil { return errors.New("body is null") } defer resp.Body.Close() //下面是 io.copyBuffer() 的简化版本 for { //读取bytes nr, er := resp.Body.Read(buf) if nr > 0 { //写入bytes nw, ew := file.Write(buf[0:nr]) //数据长度大于0 if nw > 0 { written += int64(nw) } //写入出错 if ew != nil { err = ew break } //读取是数据长度不等于写入的数据长度 if nr != nw { err = io.ErrShortWrite break } } if er != nil { if er != io.EOF { err = er } break } //没有错误了快使用 callback if fb != nil { fb(fsize, written) } } logger.Debug(err) if err == nil { file.Close() err = os.Rename(tmpFilePath, downloadPath) logger.Debug(err) } return err } // 如果文件夹不存在就会创建 func dirPing(path string) error { if !util.DirExists(path) { e := os.MkdirAll(path, 00777) if e != nil { return e } } return nil } func isFileExist(filename string, filesize int64) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { logger.Debug(info) return false } if filesize == info.Size() { logger.Debug("安装包已存在!", info.Name(), info.Size(), info.ModTime()) return true } del := os.Remove(filename) if del != nil { logger.Error(del) } return false }