mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-11 08:06:13 +00:00
One Store interface (Get/Put/Delete/Has/PresignedGetURL/Name) covers both the AWS S3 client (now exposes high-level methods alongside the legacy embedded *s3.Client) and a new FilesystemStore for self-hosters. FilesystemStore writes atomically via temp-file + rename, rejects '..' in keys before path normalization, returns ErrUnsupported from PresignedGetURL. The S3 impl works against AWS S3, MinIO, Cloudflare R2, Backblaze B2, and Hetzner Object Storage via standard AWS endpoint-URL config. Factory NewFromEnv selects via BLOB_PROVIDER (defaults to s3). 14 tests cover round-trip, ErrNotFound, atomic-write cleanup, traversal rejection, factory env-selection paths.
58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
)
|
|
|
|
// NewFromEnv constructs the active blob store from environment variables.
|
|
//
|
|
// BLOB_PROVIDER=s3 -> existing S3 client (works for AWS / MinIO /
|
|
// R2 / B2 / Hetzner Object Storage)
|
|
// BLOB_PROVIDER=filesystem -> NewFilesystem at BLOB_FS_ROOT
|
|
// (unset) -> defaults to "s3" for backwards compatibility
|
|
//
|
|
// awscfg + defaultBucket are only consulted when the S3 provider is selected.
|
|
// For non-AWS S3-compatible endpoints, the operator sets standard AWS env vars:
|
|
//
|
|
// AWS_ENDPOINT_URL_S3 -> override endpoint (MinIO, R2, etc.)
|
|
// AWS_REGION -> required by SDK; arbitrary value for MinIO
|
|
// AWS_ACCESS_KEY_ID -> S3 credential
|
|
// AWS_SECRET_ACCESS_KEY -> S3 credential
|
|
//
|
|
// BLOB_BUCKET overrides defaultBucket when set.
|
|
func NewFromEnv(ctx context.Context, awscfg aws.Config, defaultBucket string) (Store, error) {
|
|
provider := os.Getenv("BLOB_PROVIDER")
|
|
if provider == "" {
|
|
provider = "s3"
|
|
}
|
|
switch provider {
|
|
case "s3":
|
|
bucket := os.Getenv("BLOB_BUCKET")
|
|
if bucket == "" {
|
|
bucket = defaultBucket
|
|
}
|
|
if bucket == "" {
|
|
return nil, fmt.Errorf("storage: s3 provider requires BLOB_BUCKET or default bucket")
|
|
}
|
|
return NewClient(ctx, awscfg, bucket)
|
|
case "filesystem", "fs":
|
|
root := os.Getenv("BLOB_FS_ROOT")
|
|
if root == "" {
|
|
return nil, fmt.Errorf("storage: filesystem provider requires BLOB_FS_ROOT")
|
|
}
|
|
return NewFilesystem(root)
|
|
default:
|
|
return nil, fmt.Errorf("storage: unknown BLOB_PROVIDER %q (want: s3, filesystem)", provider)
|
|
}
|
|
}
|
|
|
|
// Compile-time interface checks.
|
|
var (
|
|
_ Store = (*Client)(nil)
|
|
_ Store = (*FilesystemStore)(nil)
|
|
)
|