file-system/internal/api/handlers/file_meta_commands.go

109 lines
2.6 KiB
Go

package handlers
import (
"context"
"fmt"
"io"
"time"
"rag/file-system/internal/common"
"rag/file-system/internal/domain/model"
"rag/file-system/internal/domain/repository"
"github.com/google/uuid"
)
type UploadToFolderCommand struct {
FolderID string
FileName string
Data io.Reader
S3Bucket string
OwnerID string
Size int64
ContentType string
}
type MoveFileCommand struct {
FileID string
TargetFolderID string
OwnerID string
}
type UploadToFolderHandler struct {
FileMetaRepo repository.FileMetaRepository
FolderRepo repository.FolderRepository
S3Repo repository.FileRepository
}
func NewUploadToFolderHandler(
fileMetaRepo repository.FileMetaRepository,
folderRepo repository.FolderRepository,
s3Repo repository.FileRepository,
) *UploadToFolderHandler {
return &UploadToFolderHandler{
FileMetaRepo: fileMetaRepo,
FolderRepo: folderRepo,
S3Repo: s3Repo,
}
}
func (h *UploadToFolderHandler) Handle(ctx context.Context, cmd UploadToFolderCommand) (*model.FileMeta, error) {
folder, err := h.FolderRepo.GetByID(ctx, cmd.FolderID)
if err != nil {
return nil, err
}
if folder == nil || folder.OwnerID != cmd.OwnerID {
return nil, common.NewNotFoundError("目录不存在")
}
s3Key := uuid.New().String()
if err := h.S3Repo.UploadFile(ctx, cmd.S3Bucket, s3Key, cmd.Data); err != nil {
return nil, fmt.Errorf("S3 upload failed: %w", err)
}
contentType := cmd.ContentType
if contentType == "" {
contentType = "application/octet-stream"
}
now := time.Now()
fileMeta := &model.FileMeta{
ID: uuid.New().String(),
FolderID: cmd.FolderID,
Name: cmd.FileName,
S3Key: s3Key,
S3Bucket: cmd.S3Bucket,
Size: cmd.Size,
ContentType: contentType,
OwnerID: cmd.OwnerID,
CreatedAt: now,
UpdatedAt: now,
}
if err := h.FileMetaRepo.Create(ctx, fileMeta); err != nil {
if delErr := h.S3Repo.DeleteFile(ctx, cmd.S3Bucket, s3Key); delErr != nil {
common.Logger.Error("compensation failed: could not delete S3 object after PG write failure",
"s3_key", s3Key, "error", delErr)
}
return nil, fmt.Errorf("failed to save file metadata: %w", err)
}
return fileMeta, nil
}
type MoveFileHandler struct {
FileMetaRepo repository.FileMetaRepository
}
func NewMoveFileHandler(fileMetaRepo repository.FileMetaRepository) *MoveFileHandler {
return &MoveFileHandler{FileMetaRepo: fileMetaRepo}
}
func (h *MoveFileHandler) Handle(ctx context.Context, cmd MoveFileCommand) (string, error) {
if err := h.FileMetaRepo.Move(ctx, cmd.FileID, cmd.TargetFolderID, cmd.OwnerID); err != nil {
return "", err
}
return "文件移动成功", nil
}