This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / spindle / storage / s3.go
2.3 kB 102 lines
1package storage 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 "strings" 9 10 awsconfig "github.com/aws/aws-sdk-go-v2/config" 11 "github.com/aws/aws-sdk-go-v2/service/s3" 12 "github.com/aws/aws-sdk-go-v2/service/s3/types" 13) 14 15type S3 struct { 16 bucket string 17 prefix string 18 client *s3.Client 19} 20 21func NewS3(ctx context.Context, bucket, prefix string) (*S3, error) { 22 if bucket == "" { 23 return nil, fmt.Errorf("storage: s3 backend requires a bucket") 24 } 25 sdkConfig, err := awsconfig.LoadDefaultConfig(ctx) 26 if err != nil { 27 return nil, fmt.Errorf("storage: load s3 config: %w", err) 28 } 29 client := s3.NewFromConfig(sdkConfig) 30 versioning, err := client.GetBucketVersioning(ctx, &s3.GetBucketVersioningInput{ 31 Bucket: &bucket, 32 }) 33 if err != nil { 34 return nil, fmt.Errorf("storage: check s3 bucket versioning: %w", err) 35 } 36 if versioning.Status != "" { 37 return nil, fmt.Errorf("storage: s3 cache bucket must not use versioning") 38 } 39 return &S3{ 40 bucket: bucket, 41 prefix: strings.Trim(prefix, "/"), 42 client: client, 43 }, nil 44} 45 46func (s *S3) fullKey(key string) (string, error) { 47 if err := ValidateKey(key); err != nil { 48 return "", err 49 } 50 if s.prefix == "" { 51 return key, nil 52 } 53 return s.prefix + "/" + key, nil 54} 55 56func (s *S3) Get(ctx context.Context, key string) (io.ReadCloser, error) { 57 full, err := s.fullKey(key) 58 if err != nil { 59 return nil, err 60 } 61 res, err := s.client.GetObject(ctx, &s3.GetObjectInput{ 62 Bucket: &s.bucket, 63 Key: &full, 64 }) 65 if err != nil { 66 var nsk *types.NoSuchKey 67 if errors.As(err, &nsk) { 68 return nil, ErrNotExist 69 } 70 return nil, fmt.Errorf("storage: get %q: %w", key, err) 71 } 72 return res.Body, nil 73} 74 75func (s *S3) Put(ctx context.Context, key string, r io.Reader) error { 76 full, err := s.fullKey(key) 77 if err != nil { 78 return err 79 } 80 if _, err := s.client.PutObject(ctx, &s3.PutObjectInput{ 81 Bucket: &s.bucket, 82 Key: &full, 83 Body: r, 84 }); err != nil { 85 return fmt.Errorf("storage: put %q: %w", key, err) 86 } 87 return nil 88} 89 90func (s *S3) Delete(ctx context.Context, key string) error { 91 full, err := s.fullKey(key) 92 if err != nil { 93 return err 94 } 95 if _, err := s.client.DeleteObject(ctx, &s3.DeleteObjectInput{ 96 Bucket: &s.bucket, 97 Key: &full, 98 }); err != nil { 99 return fmt.Errorf("storage: delete %q: %w", key, err) 100 } 101 return nil 102}