riverbase_file
Media management over OpenDAL: filesystem, S3 or HTTP storage plus metadata.
cargo add riverbase_file --git https://github.com/riverbase-io/riverbase --features aws-s3- postgresdefault
- fsdefault
- aws-s3
- http
riverbase_file stores files on any OpenDAL backend and keeps their
metadata in Postgres. It handles hashing, optional compression, and links between files and the
domain resources that own them.
Configure storage
[riverbase.media]
protocol = "s3" # fs | s3 | http
fskey = "default" # name of the default filesystem
root_path = "media/" # object-key prefix inside the storage root
[riverbase.media.params] # backend-specific settings
bucket = "acme-media"
region = "ap-southeast-1"
endpoint = "https://s3.ap-southeast-1.amazonaws.com"
# access keys from env: RIVERBASE_MEDIA_ACCESS_KEY_ID / RIVERBASE_MEDIA_SECRET_ACCESS_KEY
For local development, use protocol = "fs" with fs_root = "./var/media". Environment overrides
(RIVERBASE_MEDIA_PROTOCOL, …_FS_ROOT, …_FSKEY, …_ROOT_PATH, …_BUCKET, …_REGION,
…_ENDPOINT, …) win over the file.
Use it
use std::sync::Arc;
use riverbase_file::{
establish_media_dbpool, MediaManager, OpenDalMediaManager, PostgresMediaMetadataStore, PutMediaRequest,
};
let pool = establish_media_dbpool(&db_url).await?;
let media = OpenDalMediaManager::new(Arc::new(PostgresMediaMetadataStore::new(pool)))
.with_default_fskey("default");
let entry = media
.put(PutMediaRequest {
filename: "invoice.pdf".into(),
content: bytes,
filemime: Some("application/pdf".into()),
fskey: None, // the default filesystem
compress: None,
resource: Some("invoice".into()),
resource_id: Some(invoice_id),
})
.await?;
let data = media.get(&entry.domain.id).await?;
MediaManager
| Method | Purpose |
|---|---|
register_filesystem(FilesystemConfig) | Add a named backend at runtime |
put(PutMediaRequest) | Store bytes and metadata; returns a MediaEntry |
get(id) / stream(id, chunk_size) | Read the whole file, or in chunks |
get_metadata(id) / exists(id) | Metadata lookups |
copy(id, dest_fskey) | Copy to another filesystem |
delete(id) | Remove bytes and metadata |
list_files(MediaQuery) | List by owning resource / resource_id, with paging |
A MediaEntry records filename, filehash, filemime, length, fskey, fspath, the
compression method, the owning resource, and optional CDN fields (cdn_url, cdn_exp). Files are
laid out in hash-based folders, so no directory grows unbounded.
Uploads over HTTP
Expose uploads through a custom route (see Custom endpoints). The
multipart size limit is request_upload_max_bytes (default 20 MiB). Going over it fails with
MED-086.