s3_client.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. package repository
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/aws/aws-sdk-go-v2/aws"
  6. v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
  7. awsconfig "github.com/aws/aws-sdk-go-v2/config"
  8. "github.com/aws/aws-sdk-go-v2/credentials"
  9. "github.com/aws/aws-sdk-go-v2/service/s3"
  10. )
  11. // s3ClientParams 描述构造 S3 兼容客户端所需的参数。
  12. type s3ClientParams struct {
  13. Endpoint string
  14. Region string
  15. AccessKeyID string
  16. SecretAccessKey string
  17. ForcePathStyle bool
  18. }
  19. // newS3Client 构造一个 S3 兼容客户端,兼容 AWS S3 / Cloudflare R2 / 阿里云 OSS / MinIO。
  20. //
  21. // 通过 SwapComputePayloadSHA256ForUnsignedPayloadMiddleware + RequestChecksumCalculationWhenRequired
  22. // 规避阿里云 OSS 不兼容 s3manager 分片签名的问题(backup 与 image storage 共用此构造)。
  23. func newS3Client(ctx context.Context, p s3ClientParams) (*s3.Client, error) {
  24. region := p.Region
  25. if region == "" {
  26. region = "auto" // Cloudflare R2 默认 region
  27. }
  28. awsCfg, err := awsconfig.LoadDefaultConfig(ctx,
  29. awsconfig.WithRegion(region),
  30. awsconfig.WithCredentialsProvider(
  31. credentials.NewStaticCredentialsProvider(p.AccessKeyID, p.SecretAccessKey, ""),
  32. ),
  33. )
  34. if err != nil {
  35. return nil, fmt.Errorf("load aws config: %w", err)
  36. }
  37. return s3.NewFromConfig(awsCfg, func(o *s3.Options) {
  38. if p.Endpoint != "" {
  39. o.BaseEndpoint = &p.Endpoint
  40. }
  41. if p.ForcePathStyle {
  42. o.UsePathStyle = true
  43. }
  44. o.APIOptions = append(o.APIOptions, v4.SwapComputePayloadSHA256ForUnsignedPayloadMiddleware)
  45. o.RequestChecksumCalculation = aws.RequestChecksumCalculationWhenRequired
  46. }), nil
  47. }