NAME
Net::Blossom::Server::Backend::S3 - S3-compatible storage for Blossom servers
SYNOPSIS
use DBI;
use Net::Blossom::Server;
use Net::Blossom::Server::Backend::S3;
use Net::Blossom::Server::Backend::SQLite::MetadataStore;
my $sqlite_dbh = DBI->connect('dbi:SQLite:dbname=blossom.sqlite', '', '', {
AutoCommit => 1,
RaiseError => 1,
PrintError => 0,
});
my $metadata = Net::Blossom::Server::Backend::SQLite::MetadataStore->new(
dbh => $sqlite_dbh,
);
my $storage = Net::Blossom::Server::Backend::S3->new(
metadata_store => $metadata,
base_url => 'https://cdn.example.com',
bucket => 'blossom',
endpoint => 'https://s3.example.com',
region => 'us-east-1',
access_key_id => $ENV{AWS_ACCESS_KEY_ID},
secret_access_key => $ENV{AWS_SECRET_ACCESS_KEY},
);
$storage->deploy_schema;
my $server = Net::Blossom::Server->new(storage => $storage);
DESCRIPTION
This module implements Net::Blossom::Server::Storage with S3-compatible object storage. It works with Amazon S3 and independent implementations such as Ceph and Garage.
Descriptor and owner metadata are supplied separately through any Net::Blossom::Server::MetadataStore implementation. The S3 backend has no runtime dependency on a particular database backend.
The default blob store stages uploads in a temporary file. Files below multipart_threshold use one PUT unless they exceed S3's single-PUT limit. Other files use multipart upload. Downloads use bounded range requests and may return short reads, so blob bodies are not held in memory in full.
CONSTRUCTOR
new
my $storage = Net::Blossom::Server::Backend::S3->new(%args);
Requires metadata_store and base_url. The default S3 client also requires bucket. Credentials may be passed as access_key_id, secret_access_key, and session_token, or read from AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN.
region defaults to us-east-1. endpoint selects a compatible service; when omitted, Amazon S3 is used. Custom endpoints use path-style bucket URLs by default. Set path_style explicitly when the service requires another style.
timeout defaults to 30 seconds and retry is enabled by default. An existing Net::Amazon::S3 object may be passed as s3 for advanced client configuration. It cannot be combined with other connection arguments.
temp_dir selects the upload staging directory. prefix defaults to blossom. multipart_threshold, multipart_part_size, and range_size default to 100 MiB, 16 MiB, and 8 MiB. Multipart parts are enlarged when needed to remain within S3's 10,000-part limit. The configured part size must be between 5 MiB and 5 GiB; the final part may be smaller. Objects above 5 GB always use multipart upload. The client follows Amazon S3's multipart limits: 10,000 5-GiB parts, or about 48.8 TiB. Compatible services may impose lower limits.
generation may supply an object-key callback for testing. Each result must be unique for a given hash. The default uses 128 random bits.
client may supply an object client that implements upload_file, head, get_range, and delete. It cannot be combined with S3 connection options.
cleanup_error_handler may be a code reference. It receives a post-commit cleanup error and the storage key, when available. The default warns.
blob_store may be supplied for custom composition or tests. It cannot be combined with any option used to construct the default blob store.
CONSISTENCY
The default blob store uses a new generation-specific object key for each newly stored object. Object bytes are durable before metadata commits, so the metadata transaction remains open during a new object upload. Database-backed metadata stores also keep their connection occupied. Deletion commits the metadata change before deleting that exact object key, so delayed cleanup cannot erase a later upload of the same hash.
S3 and the metadata store cannot commit atomically. A metadata failure or failed object deletion can therefore leave an unreachable object. The object remains invisible because metadata is authoritative. Operators should monitor cleanup errors and may remove unreachable objects separately.
The bucket must already exist and have the required access policy. This module does not create buckets or configure encryption, lifecycle, or replication. Only an HTTP 404 response is treated as a missing object. Other service errors propagate. On Amazon S3, grant s3:ListBucket so a missing object returns 404 rather than an indistinguishable 403 permission error.
LIVE TESTING
t/20-LiveS3.t runs the same storage contract against any S3-compatible endpoint. Set NET_BLOSSOM_S3_ENDPOINT, NET_BLOSSOM_S3_BUCKET, NET_BLOSSOM_S3_REGION, NET_BLOSSOM_S3_ACCESS_KEY_ID, and NET_BLOSSOM_S3_SECRET_ACCESS_KEY. Set NET_BLOSSOM_POSTGRES_DSN, NET_BLOSSOM_POSTGRES_USER, and NET_BLOSSOM_POSTGRES_PASSWORD to also run the contract with Postgres metadata.
t/21-LiveMultiNode.t repeats cross-node operations through two independent backend instances. Set NET_BLOSSOM_S3_PEER_ENDPOINT to route the second instance through another S3 gateway; otherwise it uses the primary endpoint.
When live S3 testing is required, CI runs both tests against three-node Garage and Ceph clusters.
METHODS
BUILDARGS
Normalizes and validates constructor arguments for Class::Tiny.
metadata_store
Returns the configured metadata store.
blob_store
Returns the configured byte store.
base_url
Returns the normalized public blob URL prefix.
cleanup_error_handler
Returns the post-commit cleanup error callback.
deploy_schema
Deploys both store schemas. The default S3 byte store has no schema.
begin_upload
Starts a blob upload.
get_blob
Returns a Net::Blossom::Server::BlobResult, or undef when metadata or object bytes are absent. The default byte store returns a ranged-read stream for nonempty objects.
head_blob
Returns the blob descriptor from metadata, or undef when absent.
delete_blob
With pubkey, removes that owner and deletes the object after its final owner is removed. Without pubkey, deletes the whole blob.
list_blobs
Returns an array reference of Net::Blossom::BlobDescriptor objects for one pubkey. cursor and limit follow Net::Blossom::Server::Storage.