Weave documentation
Strand Blobs

Blob Store

Put async-readable bytes, retrieve a reader and inspect offset-based listing.

BlobStore::new(metadata_strand, data_strand, config).await builds the index from persisted records. put takes an AsyncRead + Unpin source and optional JSON metadata. ListOptions uses offset/limit and optional metadata filtering; ListResult contains blobs, total and has_more, not a continuation cursor. A missing/deleted/unusable blob can produce None; other storage/integrity failures are errors.

This example is checked against source signatures; it was not compiled or run during this documentation pass.

use strand::{Strand, StrandConfig};
use strand_blobs::{BlobConfig, BlobStore, ListOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // BlobStore is built from two strands: one for metadata, one for chunked data.
    // It deduplicates by BLAKE3 chunk hash and tracks usage in dedup_stats().
    let dir = tempfile::tempdir()?;
    let meta = Strand::new(StrandConfig::new().with_storage(dir.path().join("meta"))).await?;
    let data = Strand::new(StrandConfig::new().with_storage(dir.path().join("data"))).await?;
    let store = BlobStore::new(meta, data, BlobConfig::default()).await?;

    // put() ingests bytes and returns a BLAKE3-derived BlobId.
    let id = store.put(b"a binary blob, content-addressed by BLAKE3".as_ref(), None).await?;
    let _reader = store.get(&id).await?.expect("blob present");

    // list() uses offset/limit and reports whether more records exist.
    let listing = store.list(ListOptions::default()).await?;
    let dedup = store.dedup_stats().await?;

    println!(
        "blobs_listed={} dedup_unique_chunks={} dedup_logical={}",
        listing.blobs.len(),
        dedup.unique_chunks,
        dedup.total_chunks,
    );
    Ok(())
}

Source declarations