Cloudreve/pkg/filesystem/hooks.go

265 lines
7 KiB
Go
Raw Normal View History

2019-11-16 16:05:10 +08:00
package filesystem
2019-11-16 20:31:34 +08:00
import (
"context"
"errors"
2019-12-15 14:01:37 +08:00
model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/conf"
2019-12-10 17:10:34 +08:00
"github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
2019-12-29 17:04:08 +08:00
"github.com/HFO4/cloudreve/pkg/request"
2019-12-27 21:15:05 +08:00
"github.com/HFO4/cloudreve/pkg/serializer"
"github.com/HFO4/cloudreve/pkg/util"
2019-12-15 14:01:37 +08:00
"io/ioutil"
"strings"
2019-11-16 20:31:34 +08:00
)
2019-11-16 16:05:10 +08:00
2019-11-26 11:42:26 +08:00
// Hook 钩子函数
type Hook func(ctx context.Context, fs *FileSystem) error
// Use 注入钩子
func (fs *FileSystem) Use(name string, hook Hook) {
switch name {
case "BeforeUpload":
fs.BeforeUpload = append(fs.BeforeUpload, hook)
case "AfterUpload":
fs.AfterUpload = append(fs.AfterUpload, hook)
case "AfterValidateFailed":
fs.AfterValidateFailed = append(fs.AfterValidateFailed, hook)
case "AfterUploadCanceled":
fs.AfterUploadCanceled = append(fs.AfterUploadCanceled, hook)
2019-11-26 20:59:57 +08:00
case "BeforeFileDownload":
fs.BeforeFileDownload = append(fs.BeforeFileDownload, hook)
2019-11-26 11:42:26 +08:00
}
}
// Trigger 触发钩子,遇到第一个错误时
// 返回错误,后续钩子不会继续执行
func (fs *FileSystem) Trigger(ctx context.Context, hooks []Hook) error {
for _, hook := range hooks {
err := hook(ctx, fs)
if err != nil {
util.Log().Warning("钩子执行失败:%s", err)
return err
}
}
return nil
}
2019-11-26 20:59:57 +08:00
// HookIsFileExist 检查虚拟路径文件是否存在
func HookIsFileExist(ctx context.Context, fs *FileSystem) error {
2019-12-10 17:10:34 +08:00
filePath := ctx.Value(fsctx.PathCtx).(string)
2019-11-26 20:59:57 +08:00
if ok, _ := fs.IsFileExist(filePath); ok {
return nil
}
return ErrObjectNotExist
}
2019-12-27 21:15:05 +08:00
// HookSlaveUploadValidate Slave模式下对文件上传的一系列验证
func HookSlaveUploadValidate(ctx context.Context, fs *FileSystem) error {
file := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
policy := ctx.Value(fsctx.UploadPolicyCtx).(serializer.UploadPolicy)
// 验证单文件尺寸
if file.GetSize() > policy.MaxSize {
return ErrFileSizeTooBig
}
// 验证文件名
if !fs.ValidateLegalName(ctx, file.GetFileName()) {
return ErrIllegalObjectName
}
// 验证扩展名
if len(policy.AllowedExtension) > 0 && !IsInExtensionList(policy.AllowedExtension, file.GetFileName()) {
return ErrFileExtensionNotAllowed
}
return nil
}
2019-11-26 11:42:26 +08:00
// HookValidateFile 一系列对文件检验的集合
func HookValidateFile(ctx context.Context, fs *FileSystem) error {
2019-12-10 17:10:34 +08:00
file := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
2019-11-18 19:09:56 +08:00
2019-11-16 16:05:10 +08:00
// 验证单文件尺寸
2019-11-16 20:31:34 +08:00
if !fs.ValidateFileSize(ctx, file.GetSize()) {
return ErrFileSizeTooBig
2019-11-16 16:05:10 +08:00
}
// 验证文件名
if !fs.ValidateLegalName(ctx, file.GetFileName()) {
return ErrIllegalObjectName
}
2019-11-16 16:05:10 +08:00
// 验证扩展名
2019-11-16 20:31:34 +08:00
if !fs.ValidateExtension(ctx, file.GetFileName()) {
return ErrFileExtensionNotAllowed
2019-11-17 13:50:14 +08:00
}
2019-11-26 11:42:26 +08:00
return nil
}
// HookResetPolicy 重设存储策略为上下文已有文件
2019-12-15 14:01:37 +08:00
func HookResetPolicy(ctx context.Context, fs *FileSystem) error {
originFile, ok := ctx.Value(fsctx.FileModelCtx).(model.File)
if !ok {
return ErrObjectNotExist
}
fs.Policy = originFile.GetPolicy()
return fs.dispatchHandler()
}
2019-11-26 11:42:26 +08:00
// HookValidateCapacity 验证并扣除用户容量,包含数据库操作
func HookValidateCapacity(ctx context.Context, fs *FileSystem) error {
2019-12-10 17:10:34 +08:00
file := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
2019-11-17 13:50:14 +08:00
// 验证并扣除容量
if !fs.ValidateCapacity(ctx, file.GetSize()) {
return ErrInsufficientCapacity
2019-11-16 16:05:10 +08:00
}
return nil
}
2019-12-15 14:01:37 +08:00
// HookChangeCapacity 根据原有文件和新文件的大小更新用户容量
func HookChangeCapacity(ctx context.Context, fs *FileSystem) error {
newFile := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
originFile := ctx.Value(fsctx.FileModelCtx).(model.File)
if newFile.GetSize() > originFile.Size {
if !fs.ValidateCapacity(ctx, newFile.GetSize()-originFile.Size) {
return ErrInsufficientCapacity
}
return nil
}
fs.User.DeductionStorage(originFile.Size - newFile.GetSize())
return nil
}
2019-11-26 11:42:26 +08:00
// HookDeleteTempFile 删除已保存的临时文件
func HookDeleteTempFile(ctx context.Context, fs *FileSystem) error {
2019-12-10 17:10:34 +08:00
filePath := ctx.Value(fsctx.SavePathCtx).(string)
// 删除临时文件
2019-12-15 14:01:37 +08:00
// TODO 其他策略。Exists
if util.Exists(filePath) {
_, err := fs.Handler.Delete(ctx, []string{filePath})
if err != nil {
return err
}
}
2019-11-26 11:42:26 +08:00
return nil
}
2019-12-15 14:01:37 +08:00
// HookCleanFileContent 清空文件内容
func HookCleanFileContent(ctx context.Context, fs *FileSystem) error {
filePath := ctx.Value(fsctx.SavePathCtx).(string)
// 清空内容
return fs.Handler.Put(ctx, ioutil.NopCloser(strings.NewReader("")), filePath, 0)
}
// HookClearFileSize 将原始文件的尺寸设为0
func HookClearFileSize(ctx context.Context, fs *FileSystem) error {
originFile, ok := ctx.Value(fsctx.FileModelCtx).(model.File)
if !ok {
return ErrObjectNotExist
}
return originFile.UpdateSize(0)
}
2019-11-26 11:42:26 +08:00
// HookGiveBackCapacity 归还用户容量
func HookGiveBackCapacity(ctx context.Context, fs *FileSystem) error {
2019-12-10 17:10:34 +08:00
file := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
2019-11-26 11:42:26 +08:00
// 归还用户容量
if !fs.User.DeductionStorage(file.GetSize()) {
return errors.New("无法继续降低用户已用存储")
}
return nil
}
2019-11-18 19:09:56 +08:00
2019-12-15 14:01:37 +08:00
// GenericAfterUpdate 文件内容更新后
func GenericAfterUpdate(ctx context.Context, fs *FileSystem) error {
// 更新文件尺寸
originFile, ok := ctx.Value(fsctx.FileModelCtx).(model.File)
if !ok {
return ErrObjectNotExist
}
fs.SetTargetFile(&[]model.File{originFile})
2019-12-15 14:01:37 +08:00
newFile, ok := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
if !ok {
return ErrObjectNotExist
}
err := originFile.UpdateSize(newFile.GetSize())
if err != nil {
return err
}
// 尝试清空原有缩略图并重新生成
2019-12-15 14:01:37 +08:00
go func() {
if originFile.PicInfo != "" {
_, _ = fs.Handler.Delete(ctx, []string{originFile.SourceName + conf.ThumbConfig.FileSuffix})
fs.GenerateThumbnail(ctx, &originFile)
}
}()
return nil
}
2019-12-28 13:14:00 +08:00
// SlaveAfterUpload Slave模式下上传完成钩子
// TODO 测试
func SlaveAfterUpload(ctx context.Context, fs *FileSystem) error {
fileHeader := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
2019-12-29 17:04:08 +08:00
policy := ctx.Value(fsctx.UploadPolicyCtx).(serializer.UploadPolicy)
2019-12-28 13:14:00 +08:00
// 构造一个model.File用于生成缩略图
file := model.File{
Name: fileHeader.GetFileName(),
SourceName: ctx.Value(fsctx.SavePathCtx).(string),
}
fs.GenerateThumbnail(ctx, &file)
2019-12-29 17:04:08 +08:00
// 发送回调请求
callbackBody := serializer.UploadCallback{
Name: file.Name,
SourceName: file.SourceName,
PicInfo: file.PicInfo,
}
return request.RemoteCallback(policy.CallbackURL, callbackBody)
2019-12-28 13:14:00 +08:00
}
2019-11-18 19:09:56 +08:00
// GenericAfterUpload 文件上传完成后,包含数据库操作
func GenericAfterUpload(ctx context.Context, fs *FileSystem) error {
// 文件存放的虚拟路径
2019-12-10 17:10:34 +08:00
virtualPath := ctx.Value(fsctx.FileHeaderCtx).(FileHeader).GetVirtualPath()
2019-11-18 19:09:56 +08:00
// 检查路径是否存在
isExist, folder := fs.IsPathExist(virtualPath)
if !isExist {
return ErrPathNotExist
2019-11-18 19:09:56 +08:00
}
// 检查文件是否存在
if ok, _ := fs.IsChildFileExist(
folder,
2019-12-10 17:10:34 +08:00
ctx.Value(fsctx.FileHeaderCtx).(FileHeader).GetFileName(),
); ok {
return ErrFileExisted
}
// 向数据库中插入记录
file, err := fs.AddFile(ctx, folder)
if err != nil {
return ErrInsertFileRecord
}
fs.SetTargetFile(&[]model.File{*file})
2019-11-20 15:24:26 +08:00
// 异步尝试生成缩略图
go fs.GenerateThumbnail(ctx, file)
2019-11-20 15:24:26 +08:00
2019-11-18 19:09:56 +08:00
return nil
}