// Copyright 2022 ROC. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file. package storage import ( "context" "io" "net/url" "strings" "time" "github.com/Masterminds/semver/v3" "github.com/minio/minio-go/v7" "github.com/rocboss/paopao-ce/internal/core" "github.com/sirupsen/logrus" ) var ( _ core.ObjectStorageService = (*minioServant)(nil) _ core.OssCreateService = (*minioCreateServant)(nil) _ core.OssCreateService = (*minioCreateRetentionServant)(nil) _ core.OssCreateService = (*minioCreateTempDirServant)(nil) _ core.VersionInfo = (*minioServant)(nil) ) type minioCreateServant struct { client *minio.Client bucket string domain string } type minioCreateRetentionServant struct { client *minio.Client bucket string domain string retainInDays time.Duration retainUntilDate time.Time } type minioCreateTempDirServant struct { client *minio.Client bucket string domain string tempDir string } type minioServant struct { core.OssCreateService client *minio.Client bucket string domain string } type s3Servant = minioServant func (s *minioCreateServant) PutObject(objectKey string, reader io.Reader, objectSize int64, contentType string, _persistance bool) (string, error) { opts := minio.PutObjectOptions{ContentType: contentType} _, err := s.client.PutObject(context.Background(), s.bucket, objectKey, reader, objectSize, opts) if err != nil { return "", err } return s.domain + objectKey, nil } func (s *minioCreateServant) PersistObject(_objectKey string) error { // empty return nil } func (s *minioCreateRetentionServant) PutObject(objectKey string, reader io.Reader, objectSize int64, contentType string, persistance bool) (string, error) { opts := minio.PutObjectOptions{ContentType: contentType} if !persistance { opts.Mode = minio.Governance opts.RetainUntilDate = time.Now().Add(s.retainInDays) } _, err := s.client.PutObject(context.Background(), s.bucket, objectKey, reader, objectSize, opts) if err != nil { return "", err } return s.domain + objectKey, nil } func (s *minioCreateRetentionServant) PersistObject(objectKey string) error { retentionMode := minio.Governance return s.client.PutObjectRetention(context.Background(), s.bucket, objectKey, minio.PutObjectRetentionOptions{ Mode: &retentionMode, RetainUntilDate: &s.retainUntilDate, }) } func (s *minioCreateTempDirServant) PutObject(objectKey string, reader io.Reader, objectSize int64, contentType string, persistance bool) (string, error) { opts := minio.PutObjectOptions{ContentType: contentType} objectName := objectKey if !persistance { objectName = s.tempDir + objectKey } _, err := s.client.PutObject(context.Background(), s.bucket, objectName, reader, objectSize, opts) if err != nil { return "", err } return s.domain + objectKey, nil } func (s *minioCreateTempDirServant) PersistObject(objectKey string) error { _, err := s.client.StatObject(context.Background(), s.bucket, objectKey, minio.StatObjectOptions{}) if err == nil { logrus.Debugf("object exist so do nothing objectKey: %s", objectKey) return nil } tmpObjKey := s.tempDir + objectKey src := minio.CopySrcOptions{ Bucket: s.bucket, Object: tmpObjKey, } dst := minio.CopyDestOptions{ Bucket: s.bucket, Object: objectKey, } if _, err = s.client.CopyObject(context.Background(), dst, src); err != nil { return err } return s.client.RemoveObject(context.Background(), s.bucket, tmpObjKey, minio.RemoveObjectOptions{ForceDelete: true}) } func (s *minioServant) DeleteObject(objectKey string) error { return s.client.RemoveObject(context.Background(), s.bucket, objectKey, minio.RemoveObjectOptions{ForceDelete: true}) } func (s *minioServant) DeleteObjects(objectKeys []string) (err error) { objectsCh := make(chan minio.ObjectInfo, len(objectKeys)) resCh := s.client.RemoveObjects(context.Background(), s.bucket, objectsCh, minio.RemoveObjectsOptions{}) for _, objectKey := range objectKeys { objectsCh <- minio.ObjectInfo{ Key: objectKey, } } // 记得一定要close,否则会被卡死,退出不了函数,造成资源泄露!!! close(objectsCh) // 宽松处理所有错误,只记录最后一次发生的错误 for result := range resCh { if result.Err != nil { err = result.Err } } return } func (s *minioServant) IsObjectExist(objectKey string) (bool, error) { _, err := s.client.StatObject(context.Background(), s.bucket, objectKey, minio.StatObjectOptions{}) if err != nil { return false, err } return true, nil } func (s *minioServant) SignURL(objectKey string, expiredInSec int64) (string, error) { // TODO: Set request parameters for content-disposition. reqParams := make(url.Values) signedURL, err := s.client.PresignedGetObject(context.Background(), s.bucket, objectKey, time.Duration(expiredInSec)*time.Second, reqParams) if err != nil { return "", err } return signedURL.String(), nil } func (s *minioServant) ObjectURL(objetKey string) string { return s.domain + objetKey } func (s *minioServant) ObjectKey(objectUrl string) string { return strings.Replace(objectUrl, s.domain, "", -1) } func (s *minioServant) Name() string { return "MinIO" } func (s *minioServant) Version() *semver.Version { return semver.MustParse("v0.2.0") }