116 lines
3.3 KiB
Go
116 lines
3.3 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"kra/internal/biz/system"
|
|
"path"
|
|
"strings"
|
|
|
|
"kra/internal/conf"
|
|
|
|
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
|
)
|
|
|
|
type aliyunStorage struct {
|
|
bucket *oss.Bucket
|
|
baseURL, prefix string
|
|
}
|
|
|
|
func newAliyunStorage(config *conf.AdminBackend_ObjectStore) (system.FileStorage, error) {
|
|
if config == nil || config.Endpoint == "" || config.Bucket == "" || config.AccessKey == "" || config.SecretKey == "" {
|
|
return nil, fmt.Errorf("aliyun-oss storage configuration is incomplete")
|
|
}
|
|
client, err := oss.New(config.Endpoint, config.AccessKey, config.SecretKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bucket, err := client.Bucket(config.Bucket)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &aliyunStorage{bucket: bucket, baseURL: strings.TrimSuffix(config.BaseUrl, "/"), prefix: strings.Trim(config.PathPrefix, "/")}, nil
|
|
}
|
|
func (s *aliyunStorage) key(name string) string {
|
|
if s.prefix == "" {
|
|
return strings.TrimPrefix(name, "/")
|
|
}
|
|
return path.Join(s.prefix, strings.TrimPrefix(name, "/"))
|
|
}
|
|
func (s *aliyunStorage) unkey(key string) string {
|
|
return strings.TrimPrefix(strings.TrimPrefix(key, s.prefix), "/")
|
|
}
|
|
func (s *aliyunStorage) file(key string, size int64) *system.StoredFile {
|
|
name := s.unkey(key)
|
|
url := s.baseURL + "/" + key
|
|
return &system.StoredFile{Name: path.Base(name), Path: name, URL: url, Size: size}
|
|
}
|
|
func (s *aliyunStorage) Put(_ context.Context, name string, reader io.Reader) (*system.StoredFile, error) {
|
|
key := s.key(name)
|
|
if err := s.bucket.PutObject(key, reader); err != nil {
|
|
return nil, err
|
|
}
|
|
meta, err := s.bucket.GetObjectDetailedMeta(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
size := int64(0)
|
|
_, _ = fmt.Sscan(meta.Get("Content-Length"), &size)
|
|
return s.file(key, size), nil
|
|
}
|
|
func (s *aliyunStorage) Open(_ context.Context, name string) (io.ReadCloser, error) {
|
|
return s.bucket.GetObject(s.key(name))
|
|
}
|
|
func (s *aliyunStorage) Delete(_ context.Context, name string) error {
|
|
return s.bucket.DeleteObject(s.key(name))
|
|
}
|
|
func (s *aliyunStorage) Compose(ctx context.Context, names []string, destination string) (*system.StoredFile, string, error) {
|
|
return composeFiles(ctx, s, names, destination)
|
|
}
|
|
func (s *aliyunStorage) DeletePrefix(ctx context.Context, prefix string) error {
|
|
prefix, err := normalizeDeletePrefix(prefix)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cursor := ""
|
|
for {
|
|
items, next, more, err := s.List(ctx, prefix+"/", cursor, 1000)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, item := range items {
|
|
if err = s.Delete(ctx, item.Path); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if !more {
|
|
return nil
|
|
}
|
|
cursor, err = advanceDeletePrefixCursor(cursor, next, more)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
func (s *aliyunStorage) List(_ context.Context, prefix, cursor string, limit int) ([]*system.StoredFile, string, bool, error) {
|
|
if limit <= 0 {
|
|
limit = 100
|
|
}
|
|
result, err := s.bucket.ListObjects(oss.Prefix(boundedPrefix(s.key(prefix), prefix)), oss.Marker(cursor), oss.MaxKeys(limit))
|
|
if err != nil {
|
|
return nil, "", false, err
|
|
}
|
|
items := make([]*system.StoredFile, 0, len(result.Objects))
|
|
for _, object := range result.Objects {
|
|
item := s.file(object.Key, object.Size)
|
|
item.LastModified = object.LastModified
|
|
items = append(items, item)
|
|
}
|
|
next := ""
|
|
if result.IsTruncated {
|
|
next = result.NextMarker
|
|
}
|
|
return items, next, result.IsTruncated, nil
|
|
}
|