Skip to main content

store_bytes

Function store_bytes 

Source
pub fn store_bytes(
    ctx: &Ctx,
    prefix: &str,
    filename: &str,
    content_type: &str,
    bytes: Vec<u8>,
) -> impl Future<Output = Result<Attachment>> + Send + use<>
Expand description

Stores bytes built by the app (a generated report, an export) like store.

The object gets a new random key under prefix; filename is cleaned up (no directories or control characters, at most 200 characters) and content_type normalized (lowercase, no parameters; empty becomes application/octet-stream). The returned Attachment records all four, ready to save with columns.

Free plan: one R2 class A operation (1M free per month); copying 10 MB to R2 takes about 0.15 ms of CPU.

§Errors

Error::Internal (500) when the STORAGE binding is missing (the message shows the STORAGE entry to add to cloudflare.config.ts) or the R2 write fails.

§Examples

use axum::extract::State;
use ocre::{Ctx, Result, storage};
use serde::Deserialize;

#[derive(Deserialize)]
struct Post {
    id: i64,
    title: String,
}

// POST /exports: writes every post to a CSV kept in R2.
async fn export(State(ctx): State<Ctx>) -> Result<String> {
    let posts: Vec<Post> = ctx.db()?.all("SELECT id, title FROM posts ORDER BY id", vec![]).await?;
    let mut csv = String::from("id,title\n");
    for post in posts {
        csv.push_str(&format!("{},\"{}\"\n", post.id, post.title.replace('"', "\"\"")));
    }
    let file = storage::store_bytes(&ctx, "exports", "posts.csv", "text/csv", csv.into_bytes()).await?;
    Ok(file.key)
}