|
|
|
package objstorage
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"github.com/minio/minio-go"
|
|
|
|
"net/url"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func NewMinio() Interface {
|
|
|
|
return &minioImpl{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type minioImpl struct {
|
|
|
|
uploadBucket string // 上传桶
|
|
|
|
permanentBucket string // 永久桶
|
|
|
|
clearBucket string // 自动清理桶
|
|
|
|
client *minio.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) Init() error {
|
|
|
|
client, err := minio.New("127.0.0.1:9000", "minioadmin", "minioadmin", false)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("minio client error: %w", err)
|
|
|
|
}
|
|
|
|
m.client = client
|
|
|
|
m.uploadBucket = "upload"
|
|
|
|
m.permanentBucket = "permanent"
|
|
|
|
m.clearBucket = "clear"
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) Name() string {
|
|
|
|
return "minio"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) MinMultipartSize() int64 {
|
|
|
|
return 1024 * 1024 * 5 // minio.absMinPartSize
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) UploadBucket() string {
|
|
|
|
return m.uploadBucket
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) PermanentBucket() string {
|
|
|
|
return m.permanentBucket
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) ClearBucket() string {
|
|
|
|
return m.clearBucket
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) urlReplace(u *url.URL) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) ApplyPut(ctx context.Context, args *ApplyPutArgs) (*PutRes, error) {
|
|
|
|
if args.Effective <= 0 {
|
|
|
|
return nil, errors.New("EffectiveTime <= 0")
|
|
|
|
}
|
|
|
|
_, err := m.GetObjectInfo(ctx, &BucketFile{
|
|
|
|
Bucket: m.uploadBucket,
|
|
|
|
Name: args.Name,
|
|
|
|
})
|
|
|
|
if err == nil {
|
|
|
|
return nil, fmt.Errorf("minio bucket %s name %s already exists", args.Bucket, args.Name)
|
|
|
|
} else if !m.IsNotFound(err) {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
effective := time.Now().Add(args.Effective)
|
|
|
|
u, err := m.client.PresignedPutObject(m.uploadBucket, args.Name, args.Effective)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("minio apply error: %w", err)
|
|
|
|
}
|
|
|
|
m.urlReplace(u)
|
|
|
|
return &PutRes{
|
|
|
|
URL: u.String(),
|
|
|
|
Bucket: m.uploadBucket,
|
|
|
|
Name: args.Name,
|
|
|
|
EffectiveTime: effective,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) GetObjectInfo(ctx context.Context, args *BucketFile) (*ObjectInfo, error) {
|
|
|
|
info, err := m.client.StatObject(args.Bucket, args.Name, minio.StatObjectOptions{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &ObjectInfo{
|
|
|
|
URL: "", // todo
|
|
|
|
Size: info.Size,
|
|
|
|
Hash: info.ETag,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) CopyObjetInfo(ctx context.Context, src *BucketFile, dst *BucketFile) error {
|
|
|
|
destination, err := minio.NewDestinationInfo(dst.Bucket, dst.Name, nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return m.client.CopyObject(destination, minio.NewSourceInfo(src.Bucket, src.Name, nil))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) DeleteObjetInfo(ctx context.Context, info *BucketFile) error {
|
|
|
|
return m.client.RemoveObject(info.Bucket, info.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) MoveObjetInfo(ctx context.Context, src *BucketFile, dst *BucketFile) error {
|
|
|
|
if err := m.CopyObjetInfo(ctx, src, dst); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return m.DeleteObjetInfo(ctx, src)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) MergeObjectInfo(ctx context.Context, src []BucketFile, dst *BucketFile) error {
|
|
|
|
switch len(src) {
|
|
|
|
case 0:
|
|
|
|
return errors.New("src empty")
|
|
|
|
case 1:
|
|
|
|
return m.CopyObjetInfo(ctx, &src[0], dst)
|
|
|
|
}
|
|
|
|
destination, err := minio.NewDestinationInfo(dst.Bucket, dst.Name, nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sources := make([]minio.SourceInfo, len(src))
|
|
|
|
for i, s := range src {
|
|
|
|
sources[i] = minio.NewSourceInfo(s.Bucket, s.Name, nil)
|
|
|
|
}
|
|
|
|
return m.client.ComposeObject(destination, sources) // todo
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *minioImpl) IsNotFound(err error) bool {
|
|
|
|
if err == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
switch e := err.(type) {
|
|
|
|
case minio.ErrorResponse:
|
|
|
|
return e.StatusCode == 404 && e.Code == "NoSuchKey"
|
|
|
|
case *minio.ErrorResponse:
|
|
|
|
return e.StatusCode == 404 && e.Code == "NoSuchKey"
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|