Skip to main content

Module media

Module media 

Source
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;

Modules§

collection
MediaCollection — hierarchical “where the file lives” folders. One Media row belongs to at most one collection; collections nest via parent_id.
router
Axum REST router for the MediaManager surface — the internal management API.
tag
MediaTag — flat, free-form labels on Media rows.

Structs§

Media
First-class media row. Always referenced from user models via Option<ForeignKey<Media>> rather than embedded directly.
MediaManager
Glue between the Media model and a StorageRegistry. Cheap to clone — internal state is Arc-shared.
SaveOpts
Arguments to MediaManager::save_bytes.
UploadIntent
Arguments to MediaManager::begin_upload (direct browser flow).
UploadTicket
Server response to MediaManager::begin_upload — the row id the browser will reference, the URL it should PUT to, and an expiry hint.

Enums§

MediaError
MediaStatus
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::MediaAuthorizer does not need async-trait in the integrator’s own Cargo.toml, and cannot drift from the version the trait was declared with.