create project

This commit is contained in:
2026-01-16 17:30:40 +08:00
commit effac6b017
157 changed files with 45997 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
package services
import (
"fmt"
"io"
"os"
"path/filepath"
"time"
"github.com/drama-generator/backend/pkg/config"
"github.com/drama-generator/backend/pkg/logger"
"github.com/google/uuid"
)
type UploadService struct {
storagePath string
baseURL string
log *logger.Logger
}
func NewUploadService(cfg *config.Config, log *logger.Logger) (*UploadService, error) {
// 确保存储目录存在
if err := os.MkdirAll(cfg.Storage.LocalPath, 0755); err != nil {
return nil, fmt.Errorf("failed to create storage directory: %w", err)
}
return &UploadService{
storagePath: cfg.Storage.LocalPath,
baseURL: cfg.Storage.BaseURL,
log: log,
}, nil
}
// UploadFile 上传文件到本地存储
func (s *UploadService) UploadFile(file io.Reader, fileName, contentType string, category string) (string, error) {
// 创建分类目录
categoryPath := filepath.Join(s.storagePath, category)
if err := os.MkdirAll(categoryPath, 0755); err != nil {
return "", fmt.Errorf("failed to create category directory: %w", err)
}
// 生成唯一文件名
ext := filepath.Ext(fileName)
uniqueID := uuid.New().String()
timestamp := time.Now().Format("20060102_150405")
newFileName := fmt.Sprintf("%s_%s%s", timestamp, uniqueID, ext)
filePath := filepath.Join(categoryPath, newFileName)
// 创建文件
dst, err := os.Create(filePath)
if err != nil {
s.log.Errorw("Failed to create file", "error", err, "path", filePath)
return "", fmt.Errorf("创建文件失败: %w", err)
}
defer dst.Close()
// 写入文件
if _, err := io.Copy(dst, file); err != nil {
s.log.Errorw("Failed to write file", "error", err, "path", filePath)
return "", fmt.Errorf("写入文件失败: %w", err)
}
// 构建访问URL
fileURL := fmt.Sprintf("%s/%s/%s", s.baseURL, category, newFileName)
s.log.Infow("File uploaded successfully", "path", filePath, "url", fileURL)
return fileURL, nil
}
// UploadCharacterImage 上传角色图片
func (s *UploadService) UploadCharacterImage(file io.Reader, fileName, contentType string) (string, error) {
return s.UploadFile(file, fileName, contentType, "characters")
}
// DeleteFile 删除本地文件
func (s *UploadService) DeleteFile(fileURL string) error {
// 从URL中提取相对路径
// URL格式: http://localhost:8080/static/characters/20060102_150405_uuid.jpg
relPath := s.extractRelativePathFromURL(fileURL)
if relPath == "" {
return fmt.Errorf("invalid file URL")
}
filePath := filepath.Join(s.storagePath, relPath)
err := os.Remove(filePath)
if err != nil {
s.log.Errorw("Failed to delete file", "error", err, "path", filePath)
return fmt.Errorf("删除文件失败: %w", err)
}
s.log.Infow("File deleted successfully", "path", filePath)
return nil
}
// extractRelativePathFromURL 从URL中提取相对路径
func (s *UploadService) extractRelativePathFromURL(fileURL string) string {
// 从baseURL后面提取路径
// 例如: http://localhost:8080/static/characters/xxx.jpg -> characters/xxx.jpg
if len(fileURL) <= len(s.baseURL) {
return ""
}
return fileURL[len(s.baseURL)+1:] // +1 for the '/'
}
// GetPresignedURL 本地存储不需要预签名URL直接返回原URL
func (s *UploadService) GetPresignedURL(objectName string, expiry time.Duration) (string, error) {
// 本地存储通过静态文件服务直接访问,不需要预签名
return fmt.Sprintf("%s/%s", s.baseURL, objectName), nil
}