From 29def0248935c13b9bcc24af90ac63762d88a579 Mon Sep 17 00:00:00 2001 From: HFO4 <912394456@qq.com> Date: Wed, 27 Nov 2019 12:49:31 +0800 Subject: [PATCH] Fix: upload was marked canceled when small file uploaded --- pkg/filesystem/errors.go | 1 + pkg/filesystem/file.go | 15 ++++++++++----- pkg/filesystem/filesystem.go | 4 ++++ pkg/filesystem/local/handler.go | 26 ++++++++++++++++++++++++++ pkg/filesystem/upload.go | 26 +++++++++++++------------- pkg/serializer/error.go | 6 ++++++ routers/controllers/file.go | 4 +++- service/explorer/file.go | 10 ++++++++-- 8 files changed, 71 insertions(+), 21 deletions(-) diff --git a/pkg/filesystem/errors.go b/pkg/filesystem/errors.go index 98aa8c8..913fe82 100644 --- a/pkg/filesystem/errors.go +++ b/pkg/filesystem/errors.go @@ -15,4 +15,5 @@ var ( ErrFileExisted = errors.New("同名文件已存在") ErrPathNotExist = serializer.NewError(404, "路径不存在", nil) ErrObjectNotExist = serializer.NewError(404, "文件不存在", nil) + ErrIO = serializer.NewError(serializer.CodeIOFailed, "无法读取文件数据", nil) ) diff --git a/pkg/filesystem/file.go b/pkg/filesystem/file.go index 99943cd..c1be240 100644 --- a/pkg/filesystem/file.go +++ b/pkg/filesystem/file.go @@ -2,9 +2,7 @@ package filesystem import ( "context" - "errors" model "github.com/HFO4/cloudreve/models" - "github.com/HFO4/cloudreve/pkg/serializer" "github.com/HFO4/cloudreve/pkg/util" "io" ) @@ -37,9 +35,9 @@ func (fs *FileSystem) AddFile(ctx context.Context, parent *model.Folder) (*model return &newFile, nil } -// Download 处理下载文件请求,path为虚拟路径 +// GetContent 获取文件内容,path为虚拟路径 // TODO:测试 -func (fs *FileSystem) Download(ctx context.Context, path string) (io.ReadCloser, error) { +func (fs *FileSystem) GetContent(ctx context.Context, path string) (io.ReadSeeker, error) { // 触发`下载前`钩子 err := fs.Trigger(ctx, fs.BeforeFileDownload) if err != nil { @@ -52,6 +50,7 @@ func (fs *FileSystem) Download(ctx context.Context, path string) (io.ReadCloser, if !exist { return nil, ErrObjectNotExist } + fs.Target = &file // 将当前存储策略重设为文件使用的 fs.Policy = file.GetPolicy() @@ -60,5 +59,11 @@ func (fs *FileSystem) Download(ctx context.Context, path string) (io.ReadCloser, return nil, err } - return nil, serializer.NewError(serializer.CodeEncryptError, "人都的", errors.New("不是人都的")) + // 获取文件流 + rs, err := fs.Handler.Get(ctx, file.SourceName) + if err != nil { + return nil, ErrIO.WithError(err) + } + + return rs, nil } diff --git a/pkg/filesystem/filesystem.go b/pkg/filesystem/filesystem.go index bec6f50..9375a04 100644 --- a/pkg/filesystem/filesystem.go +++ b/pkg/filesystem/filesystem.go @@ -25,6 +25,8 @@ type Handler interface { Put(ctx context.Context, file io.ReadCloser, dst string, size uint64) error // 删除一个或多个文件 Delete(ctx context.Context, files []string) ([]string, error) + // 获取文件 + Get(ctx context.Context, path string) (io.ReadSeeker, error) } // FileSystem 管理文件的文件系统 @@ -33,6 +35,8 @@ type FileSystem struct { User *model.User // 操作文件使用的上传策略 Policy *model.Policy + // 当前正在处理的文件对象 + Target *model.File /* 钩子函数 diff --git a/pkg/filesystem/local/handler.go b/pkg/filesystem/local/handler.go index 19d27cd..13dd555 100644 --- a/pkg/filesystem/local/handler.go +++ b/pkg/filesystem/local/handler.go @@ -2,6 +2,7 @@ package local import ( "context" + "fmt" "github.com/HFO4/cloudreve/pkg/util" "io" "os" @@ -11,6 +12,31 @@ import ( // Handler 本地策略适配器 type Handler struct{} +// Get 获取文件内容 +// TODO:测试 +func (handler Handler) Get(ctx context.Context, path string) (io.ReadSeeker, error) { + // 打开文件 + file, err := os.Open(path) + if err != nil { + util.Log().Debug("无法打开文件:%s", err) + return nil, err + } + + // 开启一个协程,用于请求结束后关闭reader + go closeReader(ctx, file) + + return file, nil +} + +// closeReader 用于在请求结束后关闭reader +func closeReader(ctx context.Context, closer io.Closer) { + select { + case <-ctx.Done(): + err := closer.Close() + fmt.Println("关闭reader", err) + } +} + // Put 将文件流保存到指定目录 func (handler Handler) Put(ctx context.Context, file io.ReadCloser, dst string, size uint64) error { defer file.Close() diff --git a/pkg/filesystem/upload.go b/pkg/filesystem/upload.go index d658527..eb0ba18 100644 --- a/pkg/filesystem/upload.go +++ b/pkg/filesystem/upload.go @@ -2,7 +2,6 @@ package filesystem import ( "context" - "fmt" "github.com/HFO4/cloudreve/pkg/util" "github.com/gin-gonic/gin" "path/filepath" @@ -73,19 +72,20 @@ func (fs *FileSystem) GenerateSavePath(ctx context.Context, file FileHeader) str func (fs *FileSystem) CancelUpload(ctx context.Context, path string, file FileHeader) { ginCtx := ctx.Value(GinCtx).(*gin.Context) select { - case <-ctx.Done(): - // 客户端正常关闭,不执行操作 - fmt.Println("正常") case <-ginCtx.Request.Context().Done(): - // 客户端取消了上传 - fmt.Println("取消") - if fs.AfterUploadCanceled == nil { - return - } - ctx = context.WithValue(ctx, SavePathCtx, path) - err := fs.Trigger(ctx, fs.AfterUploadCanceled) - if err != nil { - util.Log().Debug("执行 AfterUploadCanceled 钩子出错,%s", err) + select { + case <-ctx.Done(): + // 客户端正常关闭,不执行操作 + default: + if fs.AfterUploadCanceled == nil { + return + } + ctx = context.WithValue(ctx, SavePathCtx, path) + err := fs.Trigger(ctx, fs.AfterUploadCanceled) + if err != nil { + util.Log().Debug("执行 AfterUploadCanceled 钩子出错,%s", err) + } } + } } diff --git a/pkg/serializer/error.go b/pkg/serializer/error.go index b57177a..8621a36 100644 --- a/pkg/serializer/error.go +++ b/pkg/serializer/error.go @@ -26,6 +26,12 @@ func NewError(code int, msg string, err error) AppError { } } +// WithError 将应用error携带标准库中的error +func (err *AppError) WithError(raw error) AppError { + err.RawError = raw + return *err +} + // Error 返回业务代码确定的可读错误信息 func (err AppError) Error() string { return err.Msg diff --git a/routers/controllers/file.go b/routers/controllers/file.go index faf31b4..d304def 100644 --- a/routers/controllers/file.go +++ b/routers/controllers/file.go @@ -22,7 +22,9 @@ func Download(c *gin.Context) { var service explorer.FileDownloadService if err := c.ShouldBindQuery(&service); err == nil { res := service.Download(ctx, c) - c.JSON(200, res) + if res.Code != 0 { + c.JSON(200, res) + } } else { c.JSON(200, ErrorResponse(err)) } diff --git a/service/explorer/file.go b/service/explorer/file.go index 00079c8..bad8af1 100644 --- a/service/explorer/file.go +++ b/service/explorer/file.go @@ -5,6 +5,8 @@ import ( "github.com/HFO4/cloudreve/pkg/filesystem" "github.com/HFO4/cloudreve/pkg/serializer" "github.com/gin-gonic/gin" + "net/http" + "time" ) // FileDownloadService 文件下载服务,path为文件完整路径 @@ -22,12 +24,16 @@ func (service *FileDownloadService) Download(ctx context.Context, c *gin.Context // 开始处理下载 ctx = context.WithValue(ctx, filesystem.GinCtx, c) - _, err = fs.Download(ctx, service.Path) - + rs, err := fs.GetContent(ctx, service.Path) if err != nil { return serializer.Err(serializer.CodeNotSet, err.Error(), err) } + // 设置文件名 + c.Header("Content-Disposition", "attachment; filename=\""+fs.Target.Name+"\"") + // 发送文件 + http.ServeContent(c.Writer, c.Request, "", time.Time{}, rs) + return serializer.Response{ Code: 0, }