package objectstore import ( "context" "errors" "fmt" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" "go.uber.org/zap" ) func (s *Store) ensureBucket(ctx context.Context, region string, chatExpireDays int) error { _, err := s.client.HeadBucket(ctx, &s3.HeadBucketInput{Bucket: aws.String(s.bucket)}) if err != nil { if !isMissingObject(err) { return fmt.Errorf("objectstore ping: %w", err) } if err := s.createBucket(ctx, region); err != nil { return err } } s.applyLifecycle(ctx, chatExpireDays) s.applyCORS(ctx) return nil } func (s *Store) createBucket(ctx context.Context, region string) error { in := &s3.CreateBucketInput{Bucket: aws.String(s.bucket)} if region != "" && region != defaultRegion { in.CreateBucketConfiguration = &types.CreateBucketConfiguration{ LocationConstraint: types.BucketLocationConstraint(region), } } if _, err := s.client.CreateBucket(ctx, in); err != nil { var owned *types.BucketAlreadyOwnedByYou var exists *types.BucketAlreadyExists if errors.As(err, &owned) || errors.As(err, &exists) { return nil } return fmt.Errorf("objectstore make bucket: %w", err) } return nil } func (s *Store) applyLifecycle(ctx context.Context, days int) { if days < 1 { return } _, err := s.client.PutBucketLifecycleConfiguration(ctx, &s3.PutBucketLifecycleConfigurationInput{ Bucket: aws.String(s.bucket), LifecycleConfiguration: &types.BucketLifecycleConfiguration{ Rules: []types.LifecycleRule{{ ID: aws.String("expire-chat"), Status: types.ExpirationStatusEnabled, Filter: &types.LifecycleRuleFilter{Prefix: aws.String("chat/")}, Expiration: &types.LifecycleExpiration{ Days: aws.Int32(int32(days)), }, }}, }, }) if err != nil { s.log.Warn("objectstore lifecycle", zap.Error(err)) } } func (s *Store) applyCORS(ctx context.Context) { _, err := s.client.PutBucketCors(ctx, &s3.PutBucketCorsInput{ Bucket: aws.String(s.bucket), CORSConfiguration: &types.CORSConfiguration{ CORSRules: []types.CORSRule{{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "PUT", "HEAD"}, AllowedHeaders: []string{"*"}, ExposeHeaders: []string{"ETag", "Content-Length"}, MaxAgeSeconds: aws.Int32(3600), }}, }, }) if err != nil { s.log.Warn("objectstore cors", zap.Error(err)) } }