noosphere_core/data/
body_chunk.rs1use anyhow::{anyhow, Result};
2use cid::Cid;
3use fastcdc::v2020::FastCDC;
4use libipld_cbor::DagCborCodec;
5use serde::{Deserialize, Serialize};
6
7use noosphere_storage::BlockStore;
8
9pub const BODY_CHUNK_MAX_SIZE: u32 = 1024 * 1024; #[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
17pub struct BodyChunkIpld {
18 pub bytes: Vec<u8>,
20 pub next: Option<Cid>,
22}
23
24impl BodyChunkIpld {
25 pub async fn store_bytes<S: BlockStore>(bytes: &[u8], store: &mut S) -> Result<Cid> {
29 let chunks = FastCDC::new(
30 bytes,
31 fastcdc::v2020::MINIMUM_MIN,
32 BODY_CHUNK_MAX_SIZE / 2,
33 BODY_CHUNK_MAX_SIZE,
34 );
35 let mut byte_chunks = Vec::new();
36
37 for chunk in chunks {
38 let length = chunk.length;
39 let offset = chunk.offset;
40 let end = offset + length;
41 let bytes = &bytes[offset..end];
42
43 byte_chunks.push(bytes);
44 }
45
46 let mut next_chunk_cid = None;
47
48 for byte_chunk in byte_chunks.into_iter().rev() {
49 next_chunk_cid = Some(
50 store
51 .save::<DagCborCodec, _>(&BodyChunkIpld {
52 bytes: Vec::from(byte_chunk),
53 next: next_chunk_cid,
54 })
55 .await?,
56 );
57 }
58
59 next_chunk_cid.ok_or_else(|| anyhow!("No CID; did you try to store zero bytes?"))
60 }
61
62 pub async fn load_all_bytes<S: BlockStore>(&self, store: &S) -> Result<Vec<u8>> {
65 let mut all_bytes = self.bytes.clone();
66 let mut next_cid = self.next;
67
68 while let Some(cid) = next_cid {
69 let BodyChunkIpld { mut bytes, next } = store.load::<DagCborCodec, _>(&cid).await?;
70
71 all_bytes.append(&mut bytes);
72 next_cid = next;
73 }
74
75 Ok(all_bytes)
76 }
77}