CI / Env docs check (push) Successful in 14s
CI / Docker compose check (push) Successful in 20s
CI / Nginx config check (push) Successful in 20s
CI / Frontend major deps (push) Failing after 30s
CI / Frontend deps check (push) Successful in 31s
CI / Secrets scan (push) Successful in 38s
CI / Go build (push) Successful in 38s
CI / Frontend build (push) Successful in 42s
CI / Knip (push) Successful in 40s
CI / Frontend a11y check (push) Successful in 2m2s
CI / Go vet (prod) (push) Successful in 1m56s
CI / Go vet (dev) (push) Successful in 2m7s
CI / Staticcheck (prod) (push) Successful in 2m51s
CI / Staticcheck (dev) (push) Successful in 3m3s
CI / go mod tidy (push) Successful in 1m17s
CI / Frontend QC (audit) (push) Successful in 1m34s
CI / golangci-lint (push) Successful in 3m44s
CI / Go vulnerabilities (push) Successful in 2m10s
CI / Frontend QC (typecheck) (push) Successful in 1m29s
CI / Security scan (prod) (push) Successful in 4m3s
CI / Security scan (dev) (push) Successful in 4m37s
CI / Frontend QC (lint) (push) Successful in 1m40s
CI / Svelte strict check (push) Successful in 1m22s
CI / Tests (prod) (push) Successful in 3m12s
CI / Tests (dev) (push) Successful in 3m32s
CI / Race (prod) (push) Successful in 7m12s
CI / Race (dev) (push) Successful in 7m22s
- s3.go: restore error returns on prod Upload/Download/Delete stubs (silent nil was dangerous — callers would think writes succeeded) - CI: add -timeout 300s to tests, -timeout 480s to race, GO_TESTING to race env - handlers.go: gofmt indentation fix for GetCheckoutStatus struct literal - validators.go: fix comment to include A-F (matched the regex)
86 lines
2.3 KiB
Go
86 lines
2.3 KiB
Go
//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("not implemented: production S3 upload requires AWS SDK v2 (use RUSTFS in dev)")
|
|
}
|
|
|
|
func (s *S3Client) Download(ctx context.Context, bucket, key string, w io.Writer) error {
|
|
return fmt.Errorf("not implemented: production S3 download requires AWS SDK v2 (use RUSTFS in dev)")
|
|
}
|
|
|
|
func (s *S3Client) Delete(ctx context.Context, bucket, key string) error {
|
|
return fmt.Errorf("not implemented: production S3 delete requires AWS SDK v2 (use RUSTFS in dev)")
|
|
}
|
|
|
|
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)
|
|
}
|