mirror of
https://github.com/halejohn/Cloudreve.git
synced 2026-01-26 09:34:57 +08:00
Feat: file upload handler
This commit is contained in:
10
pkg/filesystem/errors.go
Normal file
10
pkg/filesystem/errors.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package filesystem
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
UnknownPolicyTypeError = errors.New("未知存储策略类型")
|
||||
FileSizeTooBigError = errors.New("单个文件尺寸太大")
|
||||
FileExtensionNotAllowedError = errors.New("不允许上传此类型的文件")
|
||||
InsufficientCapacityError = errors.New("容量空间不足")
|
||||
)
|
||||
@@ -3,7 +3,9 @@ package filesystem
|
||||
import (
|
||||
"context"
|
||||
"github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/filesystem/local"
|
||||
"io"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// FileData 上传来的文件数据处理器
|
||||
@@ -15,6 +17,11 @@ type FileData interface {
|
||||
GetFileName() string
|
||||
}
|
||||
|
||||
// Handler 存储策略适配器
|
||||
type Handler interface {
|
||||
Put(ctx context.Context, file io.ReadCloser, dst string) error
|
||||
}
|
||||
|
||||
// FileSystem 管理文件的文件系统
|
||||
type FileSystem struct {
|
||||
/*
|
||||
@@ -29,27 +36,58 @@ type FileSystem struct {
|
||||
BeforeUpload func(ctx context.Context, fs *FileSystem, file FileData) error
|
||||
// 上传文件后
|
||||
AfterUpload func(ctx context.Context, fs *FileSystem) error
|
||||
// 文件验证失败后
|
||||
// 文件保存成功,插入数据库验证失败后
|
||||
ValidateFailed func(ctx context.Context, fs *FileSystem) error
|
||||
|
||||
/*
|
||||
文件系统处理适配器
|
||||
*/
|
||||
|
||||
Handler Handler
|
||||
}
|
||||
|
||||
// NewFileSystem 初始化一个文件系统
|
||||
func NewFileSystem(user *model.User) *FileSystem {
|
||||
return &FileSystem{
|
||||
User: user,
|
||||
func NewFileSystem(user *model.User) (*FileSystem, error) {
|
||||
var handler Handler
|
||||
|
||||
// 根据存储策略类型分配适配器
|
||||
switch user.Policy.Type {
|
||||
case "local":
|
||||
handler = local.Handler{}
|
||||
default:
|
||||
return nil, UnknownPolicyTypeError
|
||||
}
|
||||
|
||||
// TODO 分配默认钩子
|
||||
return &FileSystem{
|
||||
User: user,
|
||||
Handler: handler,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Upload 上传文件
|
||||
func (fs *FileSystem) Upload(ctx context.Context, file FileData) (err error) {
|
||||
// 上传前的钩子
|
||||
err = fs.BeforeUpload(ctx, fs, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 生成文件名和路径
|
||||
savePath := fs.GenerateSavePath(file)
|
||||
|
||||
// 保存文件
|
||||
err = fs.Handler.Put(ctx, file, savePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateSavePath 生成要存放文件的路径
|
||||
func (fs *FileSystem) GenerateSavePath(file FileData) string {
|
||||
return filepath.Join(
|
||||
fs.User.Policy.GeneratePath(fs.User.Model.ID),
|
||||
fs.User.Policy.GenerateFileName(fs.User.Model.ID, file.GetFileName()),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,24 +2,23 @@ package filesystem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// GenericBeforeUpload 通用上传前处理钩子,包含数据库操作
|
||||
func GenericBeforeUpload(ctx context.Context, fs *FileSystem, file FileData) error {
|
||||
// 验证单文件尺寸
|
||||
if !fs.ValidateFileSize(ctx, file.GetSize()) {
|
||||
return errors.New("单个文件尺寸太大")
|
||||
}
|
||||
|
||||
// 验证并扣除容量
|
||||
if !fs.ValidateCapacity(ctx, file.GetSize()) {
|
||||
return errors.New("容量空间不足")
|
||||
return FileSizeTooBigError
|
||||
}
|
||||
|
||||
// 验证扩展名
|
||||
if !fs.ValidateExtension(ctx, file.GetFileName()) {
|
||||
return errors.New("不允许上传此类型的文件")
|
||||
return FileExtensionNotAllowedError
|
||||
}
|
||||
|
||||
// 验证并扣除容量
|
||||
if !fs.ValidateCapacity(ctx, file.GetSize()) {
|
||||
return InsufficientCapacityError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ type FileData struct {
|
||||
}
|
||||
|
||||
func (file FileData) Read(p []byte) (n int, err error) {
|
||||
return file.Read(p)
|
||||
return file.File.Read(p)
|
||||
}
|
||||
|
||||
func (file FileData) GetMIMEType() string {
|
||||
@@ -23,7 +23,7 @@ func (file FileData) GetSize() uint64 {
|
||||
}
|
||||
|
||||
func (file FileData) Close() error {
|
||||
return file.Close()
|
||||
return file.File.Close()
|
||||
}
|
||||
|
||||
func (file FileData) GetFileName() string {
|
||||
|
||||
37
pkg/filesystem/local/handler.go
Normal file
37
pkg/filesystem/local/handler.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/HFO4/cloudreve/pkg/util"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
}
|
||||
|
||||
// Put 将文件流保存到指定目录
|
||||
func (handler Handler) Put(ctx context.Context, file io.ReadCloser, dst string) error {
|
||||
defer file.Close()
|
||||
|
||||
// 如果目标目录不存在,创建
|
||||
basePath := filepath.Dir(dst)
|
||||
if !util.Exists(basePath) {
|
||||
fmt.Println("创建", basePath)
|
||||
err := os.MkdirAll(basePath, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, file)
|
||||
return err
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package local
|
||||
Reference in New Issue
Block a user