feat(storage): add S3/R2 abstraction with local Rustfs dev
- Add backend/internal/s3/ with build-tag pattern (dev vs prod) - Dev: Uses local Rustfs container (S3-compatible) - Prod: Stub for R2 Cloudflare (add AWS SDK to implement) - Add S3 env vars to .env.example and .env - Add Rustfs service to compose.yml - Add Rustfs reset to local-dev-2.sh (wipes data on each run)
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
//go:build !dev
|
||||
// +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) 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)
|
||||
}
|
||||
|
||||
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) 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 getEnv(key, fallback string) string {
|
||||
if val := os.Getenv(key); val != "" {
|
||||
return val
|
||||
}
|
||||
if fallback != "" {
|
||||
return fallback
|
||||
}
|
||||
log.Fatal("FATAL: Environment variable not set:", key)
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user