hiling_go/util/cloudfare/r2.go

58 lines
1.6 KiB
Go
Executable File

package cloudfare
import (
"context"
"fmt"
"mime/multipart"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
type R2Client struct {
s3Client *s3.Client
bucketName string
publicBaseURL string
}
func NewR2Client(accountID, accessKeyID, secretAccessKey, bucketName, publicApiID string) (*R2Client, error) {
r2Endpoint := fmt.Sprintf("https://%s.r2.cloudflarestorage.com", accountID)
cfg, err := config.LoadDefaultConfig(context.Background(),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, "")),
config.WithRegion("auto"),
)
if err != nil {
return nil, fmt.Errorf("failed to load R2 config: %w", err)
}
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String(r2Endpoint)
})
return &R2Client{
s3Client: client,
bucketName: bucketName,
publicBaseURL: fmt.Sprintf("https://pub-%s.r2.dev", publicApiID),
}, nil
}
// UploadFile uploads a multipart file to R2 and returns the public URL.
// key is the object path inside the bucket, e.g. "reviews/18/image.png"
func (r *R2Client) UploadFile(ctx context.Context, key string, file multipart.File, contentType string) (string, error) {
_, err := r.s3Client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(r.bucketName),
Key: aws.String(key),
Body: file,
ContentType: aws.String(contentType),
})
if err != nil {
return "", fmt.Errorf("failed to upload to R2: %w", err)
}
publicURL := fmt.Sprintf("%s/%s", r.publicBaseURL, key)
return publicURL, nil
}