package storage import ( "fmt" "os" "path/filepath" "strings" "time" "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/drama-generator/backend/pkg/config" ) // OssStorage 阿里云 OSS 存储实现 type OssStorage struct { client *oss.Client bucket *oss.Bucket bucketName string customDomain string endpoint string } // NewOssStorage 创建 OSS 存储实例 func NewOssStorage(cfg *config.OssConfig) (*OssStorage, error) { if cfg.Endpoint == "" || cfg.AccessKeyID == "" || cfg.AccessKeySecret == "" || cfg.BucketName == "" { return nil, fmt.Errorf("OSS configuration is incomplete") } client, err := oss.New(cfg.Endpoint, cfg.AccessKeyID, cfg.AccessKeySecret) if err != nil { return nil, fmt.Errorf("failed to create OSS client: %w", err) } bucket, err := client.Bucket(cfg.BucketName) if err != nil { return nil, fmt.Errorf("failed to get OSS bucket: %w", err) } return &OssStorage{ client: client, bucket: bucket, bucketName: cfg.BucketName, customDomain: cfg.CustomDomain, endpoint: cfg.Endpoint, }, nil } // Upload 上传文件到 OSS func (s *OssStorage) Upload(localPath, category string) (string, error) { // 读取本地文件 file, err := os.Open(localPath) if err != nil { return "", fmt.Errorf("failed to open file: %w", err) } defer file.Close() // 生成 OSS 对象键 ext := filepath.Ext(localPath) timestamp := time.Now().Format("20060102_150405_000") objectKey := fmt.Sprintf("%s/%s%s", category, timestamp, ext) // 上传到 OSS err = s.bucket.PutObject(objectKey, file) if err != nil { return "", fmt.Errorf("failed to upload to OSS: %w", err) } // 构建访问 URL url := s.GetURL(objectKey) return url, nil } // UploadWithFilename 使用指定文件名上传文件到 OSS func (s *OssStorage) UploadWithFilename(localPath, category, filename string) (string, error) { file, err := os.Open(localPath) if err != nil { return "", fmt.Errorf("failed to open file: %w", err) } defer file.Close() objectKey := fmt.Sprintf("%s/%s", category, filename) err = s.bucket.PutObject(objectKey, file) if err != nil { return "", fmt.Errorf("failed to upload to OSS: %w", err) } return s.GetURL(objectKey), nil } // GetURL 获取 OSS 对象的访问 URL func (s *OssStorage) GetURL(objectKey string) string { if s.customDomain != "" { // 使用自定义域名(CDN) domain := strings.TrimSuffix(s.customDomain, "/") if !strings.HasPrefix(domain, "http") { domain = "https://" + domain } return fmt.Sprintf("%s/%s", domain, objectKey) } // 使用默认 OSS 域名 return fmt.Sprintf("https://%s.%s/%s", s.bucketName, s.endpoint, objectKey) } // Delete 删除 OSS 对象 func (s *OssStorage) Delete(objectKey string) error { err := s.bucket.DeleteObject(objectKey) if err != nil { return fmt.Errorf("failed to delete OSS object: %w", err) } return nil } // IsConfigured 检查 OSS 是否已配置 func IsOssConfigured(cfg *config.OssConfig) bool { return cfg != nil && cfg.Endpoint != "" && cfg.AccessKeyID != "" && cfg.AccessKeySecret != "" && cfg.BucketName != "" }