mirror of
				https://github.com/cloudreve/cloudreve.git
				synced 2025-11-04 04:47:24 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			139 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package filesystem
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
 | 
						|
	"github.com/HFO4/cloudreve/pkg/util"
 | 
						|
)
 | 
						|
 | 
						|
// 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)
 | 
						|
	case "BeforeFileDownload":
 | 
						|
		fs.BeforeFileDownload = append(fs.BeforeFileDownload, hook)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// 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
 | 
						|
}
 | 
						|
 | 
						|
// HookIsFileExist 检查虚拟路径文件是否存在
 | 
						|
func HookIsFileExist(ctx context.Context, fs *FileSystem) error {
 | 
						|
	filePath := ctx.Value(fsctx.PathCtx).(string)
 | 
						|
	if ok, _ := fs.IsFileExist(filePath); ok {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	return ErrObjectNotExist
 | 
						|
}
 | 
						|
 | 
						|
// HookValidateFile 一系列对文件检验的集合
 | 
						|
func HookValidateFile(ctx context.Context, fs *FileSystem) error {
 | 
						|
	file := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
 | 
						|
 | 
						|
	// 验证单文件尺寸
 | 
						|
	if !fs.ValidateFileSize(ctx, file.GetSize()) {
 | 
						|
		return ErrFileSizeTooBig
 | 
						|
	}
 | 
						|
 | 
						|
	// 验证文件名
 | 
						|
	if !fs.ValidateLegalName(ctx, file.GetFileName()) {
 | 
						|
		return ErrIllegalObjectName
 | 
						|
	}
 | 
						|
 | 
						|
	// 验证扩展名
 | 
						|
	if !fs.ValidateExtension(ctx, file.GetFileName()) {
 | 
						|
		return ErrFileExtensionNotAllowed
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
// HookValidateCapacity 验证并扣除用户容量,包含数据库操作
 | 
						|
func HookValidateCapacity(ctx context.Context, fs *FileSystem) error {
 | 
						|
	file := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
 | 
						|
	// 验证并扣除容量
 | 
						|
	if !fs.ValidateCapacity(ctx, file.GetSize()) {
 | 
						|
		return ErrInsufficientCapacity
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// HookDeleteTempFile 删除已保存的临时文件
 | 
						|
func HookDeleteTempFile(ctx context.Context, fs *FileSystem) error {
 | 
						|
	filePath := ctx.Value(fsctx.SavePathCtx).(string)
 | 
						|
	// 删除临时文件
 | 
						|
	if util.Exists(filePath) {
 | 
						|
		_, err := fs.Handler.Delete(ctx, []string{filePath})
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// HookGiveBackCapacity 归还用户容量
 | 
						|
func HookGiveBackCapacity(ctx context.Context, fs *FileSystem) error {
 | 
						|
	file := ctx.Value(fsctx.FileHeaderCtx).(FileHeader)
 | 
						|
 | 
						|
	// 归还用户容量
 | 
						|
	if !fs.User.DeductionStorage(file.GetSize()) {
 | 
						|
		return errors.New("无法继续降低用户已用存储")
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// GenericAfterUpload 文件上传完成后,包含数据库操作
 | 
						|
func GenericAfterUpload(ctx context.Context, fs *FileSystem) error {
 | 
						|
	// 文件存放的虚拟路径
 | 
						|
	virtualPath := ctx.Value(fsctx.FileHeaderCtx).(FileHeader).GetVirtualPath()
 | 
						|
 | 
						|
	// 检查路径是否存在
 | 
						|
	isExist, folder := fs.IsPathExist(virtualPath)
 | 
						|
	if !isExist {
 | 
						|
		return ErrPathNotExist
 | 
						|
	}
 | 
						|
 | 
						|
	// 检查文件是否存在
 | 
						|
	if ok, _ := fs.IsChildFileExist(
 | 
						|
		folder,
 | 
						|
		ctx.Value(fsctx.FileHeaderCtx).(FileHeader).GetFileName(),
 | 
						|
	); ok {
 | 
						|
		return ErrFileExisted
 | 
						|
	}
 | 
						|
 | 
						|
	// 向数据库中插入记录
 | 
						|
	file, err := fs.AddFile(ctx, folder)
 | 
						|
	if err != nil {
 | 
						|
		return ErrInsertFileRecord
 | 
						|
	}
 | 
						|
 | 
						|
	// 异步尝试生成缩略图
 | 
						|
	go fs.GenerateThumbnail(ctx, file)
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |