package main import ( "bytes" "encoding/json" "fmt" "io" "os" "strconv" "strings" "time" "github.com/jlaffaye/ftp" ) type version struct { Version string Cdn_dir string } type fileInfo struct { fullPath string relPath string } const PthSep = string(os.PathSeparator) var totalFileUploaded int var failList []fileInfo var delta_root_path string var cdn_dir string func loadVersion() string { d, err := os.ReadFile(config.Version_file) if err != nil { fmt.Printf("loadVersion failed %v\n", err) return "" } var v version err = json.Unmarshal(d, &v) if err != nil { fmt.Printf("loadVersion Unmarshal failed %v\n", err) return "" } cdn_dir = v.Cdn_dir vs := strings.Split(v.Version, ".") if len(vs) != 3 { fmt.Printf("loadVersion split version failed %s\n", v.Version) return "" } lv, _ := strconv.ParseInt(vs[len(vs)-1], 10, 32) lv-- vs[len(vs)-1] = fmt.Sprintf("%d", lv) lastVersion := fmt.Sprintf("%v", vs[0]) for i := 1; i < len(vs); i++ { lastVersion = fmt.Sprintf("%v.%v", lastVersion, vs[i]) } fmt.Printf("loadVersion lastVersion = %s\n", lastVersion) return lastVersion } func doUpload() bool { totalFileUploaded = 0 c, err := ftp.Dial(config.Ftp_url, ftp.DialWithTimeout(5*time.Second)) if err != nil { fmt.Printf("doUpload 连接ftp服务器失败 %v\n", err) return false } err = c.Login(config.Ftp_user, config.Ftp_password) if err != nil { fmt.Printf("doUpload 登录ftp服务器失败 %v\n", err) return false } fmt.Printf("登录ftp完成\n") lastVersion := loadVersion() root_path := config.Delta_path + PthSep + lastVersion delta_root_path = root_path fmt.Printf("开始遍历delta目录 %s\n", root_path) uploadDir(root_path, "", c) loopCount := 0 for { if len(failList) == 0 { break } loopCount++ if loopCount > 10 { fmt.Printf("尝试上传失败文件达10次,退出 \n") return false } tmpFailed := make([]fileInfo, len(failList)) copy(tmpFailed, failList) failList = []fileInfo{} fmt.Printf("正在上传失败文件 总共失败 %d \n", len(tmpFailed)) for _, v := range tmpFailed { uploadFile(v.fullPath, v.relPath, c) } } fmt.Printf("上传完成,总共上传 %d 个文件 \n", totalFileUploaded) return totalFileUploaded > 0 } func uploadDir(fullPath string, relPath string, c *ftp.ServerConn) { dir, err := os.ReadDir(fullPath) if err != nil { return } if relPath != "" { err := c.MakeDir(relPath) if err != nil && !strings.Contains(err.Error(), "exists") { fmt.Printf("uploadDir make dir failed %v path = %s\n", err, relPath) } } for _, fi := range dir { if fi.IsDir() { // 忽略目录 uploadDir(fullPath+PthSep+fi.Name(), relPath+PthSep+fi.Name(), c) } else { uploadFile(fullPath+PthSep+fi.Name(), relPath+PthSep+fi.Name(), c) } } } func uploadFile(fullPath string, relPath string, c *ftp.ServerConn) { dat1, err1 := os.ReadFile(fullPath) if err1 != nil { fmt.Printf("uploadFile read file %s failed\n", fullPath) return } err := c.Stor(relPath, bytes.NewReader(dat1)) if err != nil { fmt.Printf("uploadFile store failed %v relPath=%s\n", err, relPath) failList = append(failList, fileInfo{fullPath: fullPath, relPath: relPath}) } else { fmt.Printf(" %s 已上传\n", relPath) totalFileUploaded++ } } func flushCdn() { if cdn_dir == "" { return } fmt.Printf("正在覆盖cdn目录,%s -> %s \n", delta_root_path, cdn_dir) copyDir(delta_root_path, cdn_dir) } func copyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { fmt.Println("copy file " + srcName + " error") return } defer src.Close() os.Remove(dstName) dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { fmt.Println("open file " + dstName + " error") return } defer dst.Close() //fmt.Println("copy file " + srcName + " to " + dstName) return io.Copy(dst, src) } func copyDir(srcPath string, destPath string) { os.MkdirAll(destPath, 0777) dir, err := os.ReadDir(srcPath) if err != nil { return } for _, fi := range dir { if fi.IsDir() { // 忽略目录 outPath := destPath + PthSep + fi.Name() copyDir(srcPath+PthSep+fi.Name(), outPath) } else { srcFile := srcPath + PthSep + fi.Name() destFile := destPath + PthSep + fi.Name() copyFile(destFile, srcFile) } } }