Expand description
First-class Media model — database-backed file references with
direct-browser upload, CDN-aware URLs, soft delete and orphan purge.
See media::Media + media::MediaManager.
First-class Media model — a real #[derive(Model)] row that
references a file in the crate::storage::Storage layer.
Other models reference media via Option<ForeignKey<Media>>
(a normal integer FK column). All metadata — disk, key, MIME,
size, original filename, derived-from chain, custom JSONB —
lives on the Media row, so deletes are atomic and the admin can
browse uploads with no extra wiring.
§Quick start
use rustango::media::{MediaManager, SaveOpts};
use rustango::storage::StorageRegistry;
use std::sync::Arc;
use std::time::Duration;
// Tables come from the framework's system migrations.
let registry = StorageRegistry::new()
.set("avatars", Arc::new(s3_storage))
.with_default("avatars");
// `new_pool` works on all three backends. `MediaManager::new` is
// Postgres-only and takes a `PgPool`.
let manager = MediaManager::new_pool(pool.clone(), registry);
// Server-side save (small files):
let media = manager.save_bytes(SaveOpts {
disk: "avatars".into(),
key_prefix: "users/".into(),
bytes: png_bytes.clone(),
mime: "image/png".into(),
original_filename: "alice.png".into(),
uploaded_by_id: Some(42),
collection_id: None,
metadata: serde_json::json!({}),
}).await?;
// Read:
let url = manager.url(&media); // CDN-aware
let download = manager.presigned_get(&media, Duration::from_secs(3600)).await;
// Soft-delete the row. The storage object survives, so a presigned
// URL minted before this keeps working until its TTL expires —
// `purge` is what actually revokes access.
manager.delete(&media).await?;The REST router over this surface lives in router and needs the
admin feature. It requires an authorization policy: media_router
is deprecated and answers 403 to everything, and
router::media_router_with takes a router::MediaAuthorizer.
§Schema
The rustango_media table, and the collection / tag / tag-link
tables, are managed #[derive(Model)]s, so their schema ships as
ordinary system migrations. See Media for the columns.
Re-exports§
pub use collection::MediaCollection;pub use tag::MediaTag;pub use tag::MediaTagLink;
Modules§
- collection
MediaCollection— hierarchical “where the file lives” folders. OneMediarow belongs to at most one collection; collections nest viaparent_id.- router
- Axum REST router for the
MediaManagersurface — the internal management API. - tag
MediaTag— flat, free-form labels onMediarows.
Structs§
- Media
- First-class media row. Always referenced from user models via
Option<ForeignKey<Media>>rather than embedded directly. - Media
Manager - Glue between the
Mediamodel and aStorageRegistry. Cheap to clone — internal state isArc-shared. - Save
Opts - Arguments to
MediaManager::save_bytes. - Upload
Intent - Arguments to
MediaManager::begin_upload(direct browser flow). - Upload
Ticket - Server response to
MediaManager::begin_upload— the row id the browser will reference, the URL it should PUT to, and an expiry hint.
Enums§
- Media
Error - Media
Status - Lifecycle state of a Media row.
Constants§
- DEFAULT_
MAX_ UPLOAD_ BYTES - Default cap on a direct upload’s declared size: 100 MiB.
Attribute Macros§
- async_
trait - Re-exported so implementing
router::MediaAuthorizerdoes not needasync-traitin the integrator’s ownCargo.toml, and cannot drift from the version the trait was declared with.