package storage import ( "io" "time" ) // Storage defines the interface for file storage backends type Storage interface { // Store saves a file and returns the storage path/key Store(filename string, content io.Reader, contentType string) (string, error) // Retrieve gets a file by its storage path/key Retrieve(path string) (io.ReadCloser, error) // Delete removes a file by its storage path/key Delete(path string) error // GetURL returns a URL for accessing the file (may be signed/temporary) GetURL(path string, expiry time.Duration) (string, error) // Exists checks if a file exists at the given path Exists(path string) (bool, error) // GetMetadata returns file metadata (size, last modified, etc.) GetMetadata(path string) (*FileMetadata, error) } // FileMetadata contains information about a stored file type FileMetadata struct { Size int64 LastModified time.Time ContentType string ETag string } // Config holds configuration for storage backends type Config struct { // Storage backend type: "local", "s3" Backend string `mapstructure:"backend"` // Local filesystem configuration Local LocalConfig `mapstructure:"local"` // S3-compatible storage configuration (S3, B2, R2, etc.) S3 S3Config `mapstructure:"s3"` } // LocalConfig configures local filesystem storage type LocalConfig struct { // Root directory for file storage RootDir string `mapstructure:"root_dir"` // Base URL for serving files (optional) BaseURL string `mapstructure:"base_url"` } // S3Config configures S3-compatible storage (AWS S3, Backblaze B2, Cloudflare R2, etc.) type S3Config struct { // AWS Region (use "auto" for Cloudflare R2) Region string `mapstructure:"region"` // S3 Bucket name Bucket string `mapstructure:"bucket"` // Optional prefix for all objects Prefix string `mapstructure:"prefix"` // Access Key ID AccessKeyID string `mapstructure:"access_key_id"` // Secret Access Key SecretAccessKey string `mapstructure:"secret_access_key"` // Custom endpoint URL for S3-compatible services: // - Backblaze B2: https://s3.us-west-004.backblazeb2.com // - Cloudflare R2: https://.r2.cloudflarestorage.com // - MinIO: http://localhost:9000 // Leave empty for AWS S3 Endpoint string `mapstructure:"endpoint"` // Use path-style addressing (required for some S3-compatible services) PathStyle bool `mapstructure:"path_style"` } // NewStorage creates a new storage backend based on configuration func NewStorage(config Config) (Storage, error) { switch config.Backend { case "local", "": return NewLocalStorage(config.Local) case "s3": return NewS3Storage(config.S3) default: return nil, &UnsupportedBackendError{Backend: config.Backend} } } // UnsupportedBackendError is returned when an unknown storage backend is requested type UnsupportedBackendError struct { Backend string } func (e *UnsupportedBackendError) Error() string { return "unsupported storage backend: " + e.Backend }