Feat: archive download and sign temp url

This commit is contained in:
HFO4
2019-12-13 11:41:22 +08:00
parent 012281c41f
commit cf9416ef88
7 changed files with 327 additions and 136 deletions

View File

@@ -3,11 +3,12 @@ package filesystem
import (
"archive/zip"
"context"
"fmt"
model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/util"
"io"
"net/http"
"os"
"path/filepath"
"time"
)
/* ===============
@@ -16,16 +17,16 @@ import (
*/
// Compress 创建给定目录和文件的压缩文件
func (fs *FileSystem) Compress(ctx context.Context, folderIDs, fileIDs []uint, writer http.ResponseWriter) error {
func (fs *FileSystem) Compress(ctx context.Context, folderIDs, fileIDs []uint) (string, error) {
// 查找待压缩目录
folders, err := model.GetFoldersByIDs(folderIDs, fs.User.ID)
if err != nil && len(folders) != 0 {
return ErrDBListObjects
return "", ErrDBListObjects
}
// 查找待压缩文件
files, err := model.GetFilesByIDs(fileIDs, fs.User.ID)
if err != nil && len(files) != 0 {
return ErrDBListObjects
return "", ErrDBListObjects
}
// 将顶级待处理对象的路径设为根路径
@@ -36,33 +37,32 @@ func (fs *FileSystem) Compress(ctx context.Context, folderIDs, fileIDs []uint, w
files[i].Position = ""
}
// 创建压缩文件
zipFile, err := os.Create("temp/archive.zip")
// 创建临时压缩文件
zipFilePath := filepath.Join(model.GetSettingByName("temp_path"), fmt.Sprintf("archive_%d.zip", time.Now().UnixNano()))
zipFile, err := util.CreatNestedFile(zipFilePath)
defer zipFile.Close()
if err != nil {
util.Log().Warning("%s", err)
return err
return "", err
}
defer zipFile.Close()
//writer.Header().Set("Content-Type", "application/zip")
//writer.Header().Set("Content-Disposition", "attachment; filename=\"archive.zip\"")
zipWriter := zip.NewWriter(writer)
// 创建压缩文件Writer
zipWriter := zip.NewWriter(zipFile)
defer zipWriter.Close()
ctx, _ = context.WithCancel(context.Background())
// 压缩各个目录及文件
for i := 0; i < len(folders); i++ {
fs.doCompress(ctx, nil, &folders[i], zipWriter)
fs.doCompress(ctx, nil, &folders[i], zipWriter, true)
}
for i := 0; i < len(files); i++ {
fs.doCompress(ctx, &files[i], nil, zipWriter)
fs.doCompress(ctx, &files[i], nil, zipWriter, true)
}
return nil
return zipFilePath, nil
}
func (fs *FileSystem) doCompress(ctx context.Context, file *model.File, folder *model.Folder, zipWriter *zip.Writer) {
func (fs *FileSystem) doCompress(ctx context.Context, file *model.File, folder *model.Folder, zipWriter *zip.Writer, isArchive bool) {
// 如果对象是文件
if file != nil {
// 切换上传策略
@@ -73,6 +73,7 @@ func (fs *FileSystem) doCompress(ctx context.Context, file *model.File, folder *
return
}
// 获取文件内容
fileToZip, err := fs.Handler.Get(ctx, file.SourceName)
if err != nil {
util.Log().Debug("Open%s%s", file.Name, err)
@@ -82,8 +83,18 @@ func (fs *FileSystem) doCompress(ctx context.Context, file *model.File, folder *
defer closer.Close()
}
// 创建压缩文件头
header := &zip.FileHeader{
Name: file.Name,
Name: file.Name,
Modified: file.UpdatedAt,
UncompressedSize64: file.Size,
}
// 指定是压缩还是归档
if isArchive {
header.Method = zip.Store
} else {
header.Method = zip.Deflate
}
writer, err := zipWriter.CreateHeader(header)
@@ -92,102 +103,5 @@ func (fs *FileSystem) doCompress(ctx context.Context, file *model.File, folder *
}
_, err = io.Copy(writer, fileToZip)
util.Log().Debug("开始压缩%s", file.Name)
//f, err := os.Open(file.SourceName)
//if err != nil {
// util.Log().Debug("Open%s%s", file.Name, err)
// return
//}
//
//info, err := f.Stat()
//if err != nil {
// util.Log().Debug("Stat%s%s", file.Name, err)
// return
//}
//
//header, err := zip.FileInfoHeader(info)
//if err != nil {
// util.Log().Debug("header%s%s", file.Name, err)
// return
//}
//
//writer, err := zipWriter.CreateHeader(header)
//if err != nil {
// util.Log().Debug("压缩出错%s%s", header.Name, err)
// return
//}
//
//_, err = io.Copy(writer, f)
//if err != nil {
// util.Log().Debug("压缩出错%s%s", header.Name, err)
// return
//}
//
//if true {
// f.Close()
//}
//
//util.Log().Debug("压缩完成%s", header.Name)
//pool.Submit(compressJob)
}
}
// ZipFiles compresses one or many files into a single zip archive file.
// Param 1: filename is the output zip file's name.
// Param 2: files is a list of files to add to the zip.
func ZipFiles(filename string, files []string) error {
newZipFile, err := os.Create(filename)
if err != nil {
return err
}
defer newZipFile.Close()
zipWriter := zip.NewWriter(newZipFile)
defer zipWriter.Close()
// Add files to zip
for _, file := range files {
if err = AddFileToZip(zipWriter, file); err != nil {
return err
}
}
return nil
}
func AddFileToZip(zipWriter *zip.Writer, filename string) error {
fileToZip, err := os.Open(filename)
if err != nil {
return err
}
defer fileToZip.Close()
// Get the file information
info, err := fileToZip.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// Using FileInfoHeader() above only uses the basename of the file. If we want
// to preserve the folder structure we can overwrite this with the full path.
header.Name = filename
// Change to deflate to gain better compression
// see http://golang.org/pkg/archive/zip/#pkg-constants
header.Method = zip.Deflate
writer, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
_, err = io.Copy(writer, fileToZip)
return err
}