nodedb_types/backup_envelope/
write.rs1use super::types::{
6 DEFAULT_MAX_SECTION_BYTES, DEFAULT_MAX_TOTAL_BYTES, HEADER_LEN, MAGIC, SECTION_OVERHEAD,
7 TRAILER_LEN, VERSION,
8};
9use super::types::{EnvelopeError, EnvelopeMeta, Section};
10
11pub struct EnvelopeWriter {
13 pub(super) meta: EnvelopeMeta,
14 pub(super) sections: Vec<Section>,
15 pub(super) max_total: u64,
16 pub(super) max_section: u64,
17 pub(super) framed_size: u64,
18}
19
20impl EnvelopeWriter {
21 pub fn new(meta: EnvelopeMeta) -> Self {
22 Self::with_caps(meta, DEFAULT_MAX_TOTAL_BYTES, DEFAULT_MAX_SECTION_BYTES)
23 }
24
25 pub fn with_caps(meta: EnvelopeMeta, max_total: u64, max_section: u64) -> Self {
26 Self {
27 meta,
28 sections: Vec::new(),
29 max_total,
30 max_section,
31 framed_size: HEADER_LEN as u64 + TRAILER_LEN as u64,
32 }
33 }
34
35 pub fn push_section(
36 &mut self,
37 origin_node_id: u64,
38 body: Vec<u8>,
39 ) -> Result<(), EnvelopeError> {
40 if body.len() as u64 > self.max_section {
41 return Err(EnvelopeError::OverSizeSection {
42 cap: self.max_section,
43 });
44 }
45 let added = SECTION_OVERHEAD as u64 + body.len() as u64;
46 if self.framed_size + added > self.max_total {
47 return Err(EnvelopeError::OverSizeTotal {
48 cap: self.max_total,
49 });
50 }
51 if self.sections.len() >= u16::MAX as usize {
52 return Err(EnvelopeError::TooManySections(u16::MAX));
53 }
54 self.framed_size += added;
55 self.sections.push(Section {
56 origin_node_id,
57 body,
58 });
59 Ok(())
60 }
61
62 pub fn finalize(self) -> Vec<u8> {
64 let mut out = Vec::with_capacity(self.framed_size as usize);
65 write_header(&mut out, &self.meta, self.sections.len() as u16, VERSION);
66 for section in &self.sections {
67 write_section(&mut out, section);
68 }
69 let trailer_crc = crc32c::crc32c(&out);
71 out.extend_from_slice(&trailer_crc.to_le_bytes());
72 out
73 }
74}
75
76pub(super) fn write_header(
77 out: &mut Vec<u8>,
78 meta: &EnvelopeMeta,
79 section_count: u16,
80 version: u8,
81) {
82 let start = out.len();
83 out.extend_from_slice(MAGIC); out.push(version); out.extend_from_slice(&[0u8; 3]); out.extend_from_slice(&meta.tenant_id.to_le_bytes()); out.extend_from_slice(&meta.source_vshard_count.to_le_bytes()); out.extend_from_slice(&[0u8; 6]); out.extend_from_slice(&meta.hash_seed.to_le_bytes()); out.extend_from_slice(&meta.snapshot_watermark.to_le_bytes()); out.extend_from_slice(§ion_count.to_le_bytes()); out.extend_from_slice(&[0u8; 6]); let header_crc = crc32c::crc32c(&out[start..]);
94 out.extend_from_slice(&header_crc.to_le_bytes()); }
96
97pub(super) fn write_section(out: &mut Vec<u8>, section: &Section) {
98 out.extend_from_slice(§ion.origin_node_id.to_le_bytes());
99 out.extend_from_slice(&(section.body.len() as u32).to_le_bytes());
100 out.extend_from_slice(§ion.body);
101 let body_crc = crc32c::crc32c(§ion.body);
102 out.extend_from_slice(&body_crc.to_le_bytes());
103}