58 lines
1.6 KiB
Go
Executable File
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
|
|
}
|