use super::Result;
use bytes::{BufMut, Bytes, BytesMut};
use rayon::prelude::*;
use self_encryption::{DataMap, StreamSelfEncryptor, MAX_CHUNK_SIZE};
use serde::{Deserialize, Serialize};
use sn_protocol::storage::Chunk;
use std::{
fs::File,
io::Write,
path::{Path, PathBuf},
};
use xor_name::XorName;
#[derive(Serialize, Deserialize)]
pub(crate) enum DataMapLevel {
First(DataMap),
Additional(DataMap),
}
#[expect(unused)]
pub(crate) fn encrypt_from_path(path: &Path, output_dir: &Path) -> Result<(Chunk, Vec<XorName>)> {
let (data_map, mut encrypted_chunks) = self_encryption::encrypt_from_file(path, output_dir)?;
let (data_map_chunk, additional_chunks) = pack_data_map(data_map)?;
for chunk in additional_chunks.iter() {
encrypted_chunks.push(*chunk.name());
let file_path = output_dir.join(hex::encode(chunk.name()));
let mut output_file = File::create(file_path)?;
output_file.write_all(&chunk.value)?;
}
Ok((data_map_chunk, encrypted_chunks))
}
pub(crate) fn encrypt_large(
file_path: &Path,
output_dir: &Path,
) -> Result<(Chunk, Vec<(XorName, PathBuf)>)> {
let mut encryptor = StreamSelfEncryptor::encrypt_from_file(
file_path.to_path_buf(),
Some(output_dir.to_path_buf()),
)?;
let data_map;
loop {
match encryptor.next_encryption()? {
(None, Some(m)) => {
data_map = m;
break;
}
_ => continue,
}
}
let mut encrypted_chunks: Vec<_> = data_map
.infos()
.iter()
.map(|chunk_info| {
let chunk_file_path = output_dir.join(hex::encode(chunk_info.dst_hash));
(chunk_info.dst_hash, chunk_file_path)
})
.collect();
let (data_map_chunk, additional_chunks) = pack_data_map(data_map)?;
for chunk in additional_chunks.iter() {
let file_path = output_dir.join(hex::encode(chunk.name()));
encrypted_chunks.push((*chunk.name(), file_path.to_path_buf()));
let mut output_file = File::create(file_path)?;
output_file.write_all(&chunk.value)?;
}
Ok((data_map_chunk, encrypted_chunks))
}
pub(crate) fn to_chunk(chunk_content: Bytes) -> Chunk {
Chunk::new(chunk_content)
}
fn pack_data_map(data_map: DataMap) -> Result<(Chunk, Vec<Chunk>)> {
let mut chunks = vec![];
let mut chunk_content = wrap_data_map(&DataMapLevel::First(data_map))?;
debug!("Max chunk size: {} bytes", *MAX_CHUNK_SIZE);
let (data_map_chunk, additional_chunks) = loop {
let chunk = to_chunk(chunk_content);
if chunk.serialised_size() <= *MAX_CHUNK_SIZE {
chunks.reverse();
break (chunk, chunks);
} else {
let mut bytes = BytesMut::with_capacity(*MAX_CHUNK_SIZE).writer();
let mut serialiser = rmp_serde::Serializer::new(&mut bytes);
chunk.serialize(&mut serialiser)?;
let serialized_chunk = bytes.into_inner().freeze();
let (data_map, next_encrypted_chunks) = self_encryption::encrypt(serialized_chunk)?;
chunks = next_encrypted_chunks
.par_iter()
.map(|c| to_chunk(c.content.clone())) .chain(chunks)
.collect();
chunk_content = wrap_data_map(&DataMapLevel::Additional(data_map))?;
}
};
Ok((data_map_chunk, additional_chunks))
}
fn wrap_data_map(data_map: &DataMapLevel) -> Result<Bytes> {
let mut bytes = BytesMut::with_capacity(300).writer();
let mut serialiser = rmp_serde::Serializer::new(&mut bytes);
data_map.serialize(&mut serialiser)?;
Ok(bytes.into_inner().freeze())
}