Files and blobs
Task: store a large binary (a file, an image) for your app and read it back.
Blobs live outside the app’s state: the bytes go to the cluster’s sealed blob
store, and the state keeps a BlobRef, the blob’s SHA-256. A reference in state
is what keeps a blob: drop the reference and the blob goes. The store and its
replication are in the blobs reference.
Keep a blob a client uploaded
Section titled “Keep a blob a client uploaded”A client uploads to POST /apps/{app}/blobs and gets back the blob’s id (64
hex digits). It then calls a method with that id; a BlobRef parameter takes it
as a string:
#[app::state(version = 1)]pub struct Files { /// The files kept, by name: a reference in state is what retains one. kept: UnorderedMap<String, BlobRef>,}
pub fn attach(&mut self, name: String, file: BlobRef) -> app::Result<()> { let Some(info) = file.info() else { app::bail!(Error::NotUploaded); }; env::log(&format!("{name}: {} bytes of {}", info.size, info.mime)); self.kept.insert(&name, &file)?; Ok(())}BlobRef::info() is None for a blob the app does not hold.
Write a file from a run
Section titled “Write a file from a run”calimero_sdk::files writes and reads blobs from inside the app
(apps/v2-fixtures/files, the sample guest):
use std::io::{Read, Write};use calimero_sdk::files;
pub fn save_file(&mut self, data: Vec<u8>) -> app::Result<BlobRef> { let mut writer = files::create()?; writer.write_all(&data)?; Ok(writer.finish()?)}
#[app::view]pub fn file_len(&self, id: BlobRef) -> app::Result<Option<u64>> { Ok(id.info().map(|info| info.size))}files::create()returns aWriter(std::io::Write);finish()gives theBlobRef. A writer dropped unfinished leaves no file.files::open(&blob)returns aReader(std::io::Read), but only inside an#[app::compute]run: in a call, view, timer orinitit is refused, andBlobRef::infogives the size and hash instead.- A file a failed call wrote is not kept: only a committed call’s files are.
Let a client download one
Section titled “Let a client download one”#[app::view]pub fn share(&self, file: BlobRef) -> app::Result<String> { Ok(file.grant(3600))}grant(ttl_seconds) (1 to 86,400) returns a grant; a client downloads with
GET /apps/{app}/blobs/{id}?grant=<grant>, signed in or not.