//go:build !dev package s3 import ( "context" "fmt" "io" "log" "os" ) var Client Uploader type Uploader interface { Upload(ctx context.Context, bucket, key string, body io.Reader, contentType string) error Download(ctx context.Context, bucket, key string, w io.Writer) error Delete(ctx context.Context, bucket, key string) error GetURL(ctx context.Context, bucket, key string) (string, error) HealthCheck(ctx context.Context) error } type S3Client struct { bucket string endpoint string region string accessKey string secretKey string publicURL string } func Connect() error { endpoint := os.Getenv("R2_ENDPOINT") if endpoint == "" { log.Println("WARNING: R2_ENDPOINT not set, S3 client not initialized") return nil } Client = &S3Client{ endpoint: endpoint, bucket: getEnv("R2_BUCKET", ""), region: getEnv("AWS_REGION", "auto"), accessKey: getEnv("R2_ACCESS_KEY", ""), secretKey: getEnv("R2_SECRET_KEY", ""), publicURL: getEnv("R2_PUBLIC_URL", ""), } log.Printf("Connected to R2: bucket=%s, endpoint=%s", Client.(*S3Client).bucket, endpoint) return nil } func (s *S3Client) Upload(ctx context.Context, bucket, key string, body io.Reader, contentType string) error { return fmt.Errorf("S3 Upload not implemented: add AWS SDK v2 dependency") } func (s *S3Client) Download(ctx context.Context, bucket, key string, w io.Writer) error { return fmt.Errorf("S3 Download not implemented: add AWS SDK v2 dependency") } func (s *S3Client) Delete(ctx context.Context, bucket, key string) error { return fmt.Errorf("S3 Delete not implemented: add AWS SDK v2 dependency") } func (s *S3Client) GetURL(ctx context.Context, bucket, key string) (string, error) { return fmt.Sprintf("%s/%s/%s", s.publicURL, bucket, key), nil } func (s *S3Client) HealthCheck(_ context.Context) error { if s.endpoint == "" { return fmt.Errorf("S3 client not initialized: R2_ENDPOINT not set") } // Production stub — can't perform a real check without the SDK. // Actual operations (Upload, Download, Delete) will return errors. return nil } func getEnv(key, fallback string) string { if val := os.Getenv(key); val != "" { return val } if fallback != "" { return fallback } panic("Environment variable not set: " + key) }