diff --git a/fss/core/fsesnd.go b/fss/core/fsesnd.go new file mode 100644 index 0000000..63399cf --- /dev/null +++ b/fss/core/fsesnd.go @@ -0,0 +1,110 @@ +package core + +import ( + "fmt" + "fss/config" + "fss/util" + "io" + "mime" + "net/http" + "os" + "path/filepath" + "strings" + "time" +) + +// 接收发送来的文件 +func ReceiveHandler(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + // + fmt.Fprintf(w, "%s:接收文件中...", r.Host) + case http.MethodPost: + // receive file and save + file, header, err := r.FormFile("file") + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + defer file.Close() + + _, params, err := mime.ParseMediaType(header.Header.Get("Content-Disposition")) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + filename := filepath.FromSlash(params["filename"]) + + // fpath + bfpath := r.Header.Get("Fpath") + + //debug + // fmt.Printf("header params:%v\n", r.Header) + fmt.Printf("fpath is:%s,afbs64 is:%s\n", bfpath, util.Base64dec(bfpath)) + + fmt.Printf("Downloading [%s]...\n", filename) + // 拼装完整路径 + nfname := filepath.Join(config.G.FilePath, util.Base64dec(bfpath)) + dirPath := filepath.Dir(nfname) + //dirPath := filepath.Dir(filename) + err = os.MkdirAll(dirPath, os.ModePerm) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // 检查文件是否存在 + if util.IsFileExist(nfname) { + // 当前时间 + curtime := time.Now().Format("2006/01/02") + // 创建备份文件夹 + bkdir := filepath.Join(config.G.FilePath, "backup", curtime) + // 递归创建文件夹 + serr := os.MkdirAll(bkdir, os.ModePerm) + // 创建错误 返回空 + if serr != nil { + return + } + + // 文件重命名 + //ddname := filename + "_backup_" + time.Now().Format("20060102150405") + ddname := filename + "_backup_" + time.Now().Format("20060102150405") + // 文件移动到备份目录下,并做压缩包 + bkzip := filepath.Join(bkdir, ddname) + zfarr := []string{nfname} + util.ZipFiles(bkzip+".zip", zfarr, bkdir) + //渠道 + // 加上路径 + //fnewname := filepath.Join(bkdir, ddname) + //os.Rename(nfname, fnewname) + } + + out, err := os.Create(nfname) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer out.Close() + + _, err = io.Copy(out, file) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // 如果单文件,需要先备份 + + // 如果收到的是zip文件,自动给解压缩 + suf := strings.Split(filename, ".") + if suf[1] == "zip" { + // 传入实际路径 + go util.DecompressZip(nfname) + } + + fmt.Printf("[√] Download [%s] Success.\n", filename) + // + default: + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + } + + // 输出接收结果 + // fmt.Fprintf(w, "接收成功,并已经完成解压缩") +} diff --git a/fss/util/fsutil.go b/fss/util/fsutil.go index adb2c28..8a60a13 100644 --- a/fss/util/fsutil.go +++ b/fss/util/fsutil.go @@ -1,9 +1,11 @@ package util import ( + "archive/zip" "crypto/sha256" "encoding/base64" "fmt" + "fss/config" "io" "os" "path/filepath" @@ -70,3 +72,123 @@ func CalacHash(rfile string) string { hastString := fmt.Sprintf("%x", hashBytes) return hastString } + +// 判断文件是否存在 +func IsFileExist(filename string) bool { + if _, err := os.Stat(filename); err == nil { + return true + } + return false +} + +/* +* add file to zip + */ +func ZipFiles(zipname string, files []string, zippath string) error { + fmt.Printf("zipname:%s\n", zipname) + // 创建zip文件 + newZipFile, err := os.Create(zipname) + if err != nil { + return err + } + + defer newZipFile.Close() + // zip写头 + zipWriter := zip.NewWriter(newZipFile) + defer zipWriter.Close() + + // 把files添加到zip中 + for _, file := range files { + // + fmt.Printf("zipfiles in function :%s\n", file) + + // + zipfile, err := os.Open(file) + if err != nil { + return err + } + defer zipfile.Close() + + // + info, err := zipfile.Stat() + if err != nil { + return err + } + // + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + // 在zip存档中设置文件的相对路径 + header.Name, err = filepath.Rel(filepath.Dir(config.G.FilePath), file) + if err != nil { + return err + } + // 转换为Unix风格的路径分隔符 + header.Name = filepath.ToSlash(header.Name) + // 目录需要拼上一个 "/" ,否则会出现一个和目录一样的文件在压缩包中 + if info.IsDir() { + header.Name += "/" + } else { + // 将压缩方法设置为deflate + header.Method = zip.Deflate + } + // + fmt.Printf("header.name is %s\n", header.Name) + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + + if _, err = io.Copy(writer, zipfile); err != nil { + return err + } + } + return nil +} + +// 解压缩zip文件 +// 这个方法必须是首字母大写的,才能被注册 +// src: 需要解压的zip文件 +func DecompressZip(zpFname string) error { + // 下载文件 + archive, err := zip.OpenReader(zpFname) + if err != nil { + return err + } + // 取zip文件的绝对路径的文件夹。会默认解压到files下,暂停使用 + // dir := filepath.Dir(zpFname) + defer archive.Close() + // 遍历目录 + for _, f := range archive.File { + // zip 解压的时候,路径为监听的路径 + filePath := filepath.Join(config.G.FilePath, f.Name) + // 暂停原因 屏蔽解压到files 目录下 + //filePath := filepath.Join(dir, f.Name) + if f.FileInfo().IsDir() { + os.MkdirAll(filePath, os.ModePerm) + continue + } + // 父文件夹开始创建目录 + if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { + return fmt.Errorf("failed to make directory (%v)", err) + } + // 文件原有模式 + dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return fmt.Errorf("failed to create file (%v)", err) + } + fileInArchive, err := f.Open() + if err != nil { + return fmt.Errorf("failed to open file in zip (%v)", err) + } + if _, err := io.Copy(dstFile, fileInArchive); err != nil { + return fmt.Errorf("failed to copy file in zip (%v)", err) + } + dstFile.Close() + fileInArchive.Close() + } + return nil +}