github.com/sandwich-go/boost@v1.3.29/misc/cloud/storage.go (about) 1 package cloud 2 3 import ( 4 "bytes" 5 "context" 6 "github.com/minio/minio-go/v7" 7 "github.com/minio/minio-go/v7/pkg/credentials" 8 "github.com/sandwich-go/boost/xpanic" 9 "io" 10 "net/url" 11 "strings" 12 ) 13 14 var ( 15 creators = map[StorageType]storageCreator{} 16 emptyObjectInfo = ObjectInfo{} 17 ) 18 19 func register(st StorageType, creator storageCreator) { creators[st] = creator } 20 21 type ( 22 // StorageType 存储器类型 23 StorageType string 24 // storageCreator 存储器创建 25 storageCreator = func(accessKeyID string, secretAccessKey string, bucket string, opts ...StorageOption) (Storage, error) 26 // endpointGetter endpoint 获取器 27 endpointGetter = func(*StorageOptions) (ep string, err error) 28 // objectNameResolver 解析 object name 29 objectNameResolver = func(*url.URL) (string, error) 30 ) 31 32 // New 新建 Storage 33 func New(st StorageType, accessKeyID string, secretAccessKey string, bucket string, opts ...StorageOption) (Storage, error) { 34 creator, ok := creators[st] 35 if !ok { 36 return nil, ErrUnknownStorageType 37 } 38 return creator(accessKeyID, secretAccessKey, bucket, opts...) 39 } 40 41 // MustNew 新建 Storage,失败会 panic 42 func MustNew(st StorageType, accessKeyID string, secretAccessKey string, bucket string, opts ...StorageOption) Storage { 43 s, err := New(st, accessKeyID, secretAccessKey, bucket, opts...) 44 xpanic.WhenError(err) 45 return s 46 } 47 48 type baseStorage struct { 49 cli *minio.Client 50 bucket string 51 resolver objectNameResolver 52 spec *StorageOptions 53 } 54 55 func newBaseBucket(accessKeyID string, secretAccessKey string, bucket string, getter endpointGetter, opts ...StorageOption) (*baseStorage, error) { 56 spec := NewStorageOptions(opts...) 57 ep, err := getter(spec) 58 if err != nil { 59 return nil, err 60 } 61 var cli *minio.Client 62 cli, err = minio.New(ep, &minio.Options{ 63 Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), 64 Secure: false, 65 }) 66 if err != nil { 67 return nil, err 68 } 69 return &baseStorage{cli: cli, bucket: bucket, spec: spec}, nil 70 } 71 72 func (c *baseStorage) setObjectNameResolver(resolver objectNameResolver) { 73 c.resolver = resolver 74 } 75 76 func (c baseStorage) ResolveObjectName(rawUrl string) (string, error) { 77 u, err := url.Parse(rawUrl) 78 if err != nil { 79 return "", err 80 } 81 if c.resolver != nil { 82 return c.resolver(u) 83 } 84 return strings.Trim(u.Path, "/"), nil 85 } 86 87 func (c baseStorage) String() string { return c.bucket } 88 func (c baseStorage) DelObject(ctx context.Context, objName string) error { 89 return c.cli.RemoveObject(ctx, c.bucket, objName, minio.RemoveObjectOptions{}) 90 } 91 92 func (c baseStorage) PutObject(ctx context.Context, objName string, reader io.Reader, objSize int, opts ...PutOption) (err error) { 93 spec := NewPutOptions(opts...) 94 op := minio.PutObjectOptions{ 95 ContentType: spec.ContentType, 96 ContentDisposition: spec.ContentDisposition, 97 CacheControl: spec.CacheControl, 98 } 99 if objSize == 0 { 100 op.DisableMultipart = true 101 } 102 _, err = c.cli.PutObject(ctx, c.bucket, objName, reader, int64(objSize), op) 103 return 104 } 105 106 func (c baseStorage) StatObject(ctx context.Context, objName string) (ObjectInfo, error) { 107 info, err := c.cli.StatObject(ctx, c.bucket, objName, minio.StatObjectOptions{}) 108 if err != nil { 109 return emptyObjectInfo, err 110 } 111 return ObjectInfo{ 112 ETag: info.ETag, 113 Key: info.Key, 114 LastModified: info.LastModified, 115 Size: info.Size, 116 ContentType: info.ContentType, 117 }, nil 118 } 119 120 func (c baseStorage) ListObjects(ctx context.Context, prefix string) <-chan ObjectInfo { 121 ch0 := c.cli.ListObjects(ctx, c.bucket, minio.ListObjectsOptions{ 122 Prefix: prefix, 123 }) 124 ch1 := make(chan ObjectInfo) 125 go func() { 126 defer close(ch1) 127 for info := range ch0 { 128 ch1 <- ObjectInfo{ 129 ETag: info.ETag, 130 Key: info.Key, 131 LastModified: info.LastModified, 132 Size: info.Size, 133 ContentType: info.ContentType, 134 } 135 } 136 }() 137 return ch1 138 } 139 140 func (c baseStorage) GetObject(ctx context.Context, objName string) (io.Reader, error) { 141 obj, err := c.cli.GetObject(ctx, c.bucket, objName, minio.GetObjectOptions{}) 142 if err != nil { 143 return nil, err 144 } 145 defer func(o io.ReadCloser) { 146 _ = o.Close() 147 }(obj) 148 buf := new(bytes.Buffer) 149 _, err = io.Copy(buf, obj) 150 if err != nil { 151 return nil, err 152 } 153 return buf, nil 154 } 155 156 func (c baseStorage) CopyObject(ctx context.Context, destObjName, srcObjName string) error { 157 _, err := c.cli.CopyObject(ctx, minio.CopyDestOptions{ 158 Bucket: c.bucket, 159 Object: destObjName, 160 }, minio.CopySrcOptions{ 161 Bucket: c.bucket, 162 Object: srcObjName, 163 }) 164 return err 165 }