package storage import ( "context" "fmt" "io" "log" "strings" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "gotest/internal/config" ) // MinIOStorage MinIO 对象存储实现 type MinIOStorage struct { client *minio.Client bucket string publicURL string } // NewMinIOStorage 创建 MinIO 存储实例 // 当 AutoCreateBucket 为 true 时自动创建 bucket func NewMinIOStorage(cfg *config.MinIOConfig) (*MinIOStorage, error) { client, err := minio.New(cfg.Endpoint, &minio.Options{ Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""), Secure: cfg.UseSSL, }) if err != nil { return nil, fmt.Errorf("创建 MinIO 客户端失败: %w", err) } // 自动创建 bucket if cfg.AutoCreateBucket { ctx := context.Background() exists, err := client.BucketExists(ctx, cfg.Bucket) if err != nil { return nil, fmt.Errorf("检查 bucket 是否存在失败: %w", err) } if !exists { if err := client.MakeBucket(ctx, cfg.Bucket, minio.MakeBucketOptions{}); err != nil { return nil, fmt.Errorf("创建 bucket 失败: %w", err) } log.Printf("MinIO bucket %s 已自动创建\n", cfg.Bucket) } } return &MinIOStorage{ client: client, bucket: cfg.Bucket, publicURL: cfg.PublicURL, }, nil } // Upload 上传文件到 MinIO func (s *MinIOStorage) Upload(key string, reader io.Reader, contentType string) (string, error) { ctx := context.Background() _, err := s.client.PutObject(ctx, s.bucket, key, reader, -1, minio.PutObjectOptions{ ContentType: contentType, }) if err != nil { return "", fmt.Errorf("上传文件到 MinIO 失败: %w", err) } return s.GetURL(key), nil } // Delete 删除 MinIO 中的文件 func (s *MinIOStorage) Delete(key string) error { ctx := context.Background() return s.client.RemoveObject(ctx, s.bucket, key, minio.RemoveObjectOptions{}) } // GetURL 获取 MinIO 文件访问 URL // 优先使用 PublicURL 拼接,为空时回退到 endpoint func (s *MinIOStorage) GetURL(key string) string { base := strings.TrimRight(s.publicURL, "/") if base == "" { base = strings.TrimRight(s.client.EndpointURL().String(), "/") } return base + "/" + s.bucket + "/" + key }