Files
go-common/storage/minio.go

165 lines
4.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package storage
import (
"context"
"fmt"
"io"
"strings"
"time"
"git.toowon.com/jimmy/go-common/config"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
// MinIOStorage MinIO存储实现
type MinIOStorage struct {
config *config.MinIOConfig
client *minio.Client
bucket string
domain string
protocol string
}
// NewMinIOStorage 创建MinIO存储实例
func NewMinIOStorage(cfg *config.MinIOConfig) (*MinIOStorage, error) {
if cfg == nil {
return nil, fmt.Errorf("MinIO config is nil")
}
// 创建MinIO客户端
client, err := minio.New(cfg.Endpoint, &minio.Options{
Creds: credentials.NewStaticV4(cfg.AccessKeyID, cfg.SecretAccessKey, ""),
Secure: cfg.UseSSL,
})
if err != nil {
return nil, fmt.Errorf("failed to create MinIO client: %w", err)
}
// 检查bucket是否存在不存在则创建
ctx := context.Background()
exists, err := client.BucketExists(ctx, cfg.Bucket)
if err != nil {
// 如果检查失败,可能是网络问题,但不阻止客户端创建
// 继续创建客户端,后续上传时会再次检查
} else if !exists {
err = client.MakeBucket(ctx, cfg.Bucket, minio.MakeBucketOptions{})
if err != nil {
// 不阻止客户端创建,后续上传时会再次尝试
}
}
protocol := "http"
if cfg.UseSSL {
protocol = "https"
}
return &MinIOStorage{
config: cfg,
client: client,
bucket: cfg.Bucket,
domain: cfg.Domain,
protocol: protocol,
}, nil
}
// Upload 上传文件到MinIO
func (s *MinIOStorage) Upload(ctx context.Context, objectKey string, reader io.Reader, contentType ...string) error {
if s.client == nil {
return fmt.Errorf("MinIO client is not initialized")
}
ct := "application/octet-stream"
if len(contentType) > 0 && contentType[0] != "" {
ct = contentType[0]
}
opts := minio.PutObjectOptions{
ContentType: ct,
}
_, err := s.client.PutObject(ctx, s.bucket, objectKey, reader, -1, opts)
if err != nil {
return fmt.Errorf("failed to upload object: %w", err)
}
return nil
}
// GetURL 获取MinIO文件访问URL
func (s *MinIOStorage) GetURL(objectKey string, expires int64) (string, error) {
if s.client == nil {
return "", fmt.Errorf("MinIO client is not initialized")
}
// 如果设置了过期时间生成预签名URL
if expires > 0 {
ctx := context.Background()
expiry := time.Duration(expires) * time.Second
presignedURL, err := s.client.PresignedGetObject(ctx, s.bucket, objectKey, expiry, nil)
if err != nil {
return "", fmt.Errorf("failed to generate presigned URL: %w", err)
}
return presignedURL.String(), nil
}
// 使用自定义域名或默认域名
if s.domain != "" {
// 使用自定义域名
if strings.HasSuffix(s.domain, "/") {
return fmt.Sprintf("%s://%s%s/%s", s.protocol, s.domain, s.bucket, objectKey), nil
}
return fmt.Sprintf("%s://%s/%s/%s", s.protocol, s.domain, s.bucket, objectKey), nil
}
// 使用MinIO默认域名
// 格式: http://endpoint/bucket/objectKey
return fmt.Sprintf("%s://%s/%s/%s", s.protocol, s.config.Endpoint, s.bucket, objectKey), nil
}
// Delete 删除MinIO文件
func (s *MinIOStorage) Delete(ctx context.Context, objectKey string) error {
if s.client == nil {
return fmt.Errorf("MinIO client is not initialized")
}
err := s.client.RemoveObject(ctx, s.bucket, objectKey, minio.RemoveObjectOptions{})
if err != nil {
return fmt.Errorf("failed to delete object: %w", err)
}
return nil
}
// Exists 检查MinIO文件是否存在
func (s *MinIOStorage) Exists(ctx context.Context, objectKey string) (bool, error) {
if s.client == nil {
return false, fmt.Errorf("MinIO client is not initialized")
}
_, err := s.client.StatObject(ctx, s.bucket, objectKey, minio.StatObjectOptions{})
if err != nil {
errResp := minio.ToErrorResponse(err)
if errResp.Code == "NoSuchKey" {
return false, nil
}
return false, fmt.Errorf("failed to check object existence: %w", err)
}
return true, nil
}
// GetObject 获取MinIO文件内容
func (s *MinIOStorage) GetObject(ctx context.Context, objectKey string) (io.ReadCloser, error) {
if s.client == nil {
return nil, fmt.Errorf("MinIO client is not initialized")
}
obj, err := s.client.GetObject(ctx, s.bucket, objectKey, minio.GetObjectOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get object: %w", err)
}
return obj, nil
}