use crate::client::{Error, Result};
use bincode::serialize;
use bytes::Bytes;
use rayon::prelude::*;
use self_encryption::{DataMap, EncryptedChunk};
use serde::{Deserialize, Serialize};
use sn_interface::types::{BytesAddress, Chunk, Encryption};
use std::path::Path;
#[derive(Serialize, Deserialize)]
pub(crate) enum DataMapLevel {
First(DataMap),
Additional(DataMap),
}
#[allow(unused)]
pub(crate) fn encrypt_from_path(
path: &Path,
encryption: Option<&impl Encryption>,
) -> Result<(BytesAddress, Vec<Chunk>)> {
let (data_map, encrypted_chunks) = encrypt_file(path)?;
pack(data_map, encrypted_chunks, encryption)
}
pub(crate) fn encrypt_large(
data: Bytes,
encryption: Option<&impl Encryption>,
) -> Result<(BytesAddress, Vec<Chunk>)> {
let (data_map, encrypted_chunks) = encrypt_data(data)?;
pack(data_map, encrypted_chunks, encryption)
}
pub(crate) fn pack(
data_map: DataMap,
encrypted_chunks: Vec<EncryptedChunk>,
encryption: Option<&impl Encryption>,
) -> Result<(BytesAddress, Vec<Chunk>)> {
let mut chunks = vec![];
let mut chunk_content = pack_data_map(DataMapLevel::First(data_map))?;
let mut no_encryption = encryption; let _value = no_encryption.take();
let (address, additional_chunks) = loop {
let chunk = to_chunk(chunk_content, encryption)?;
if chunk.validate_size() {
let name = *chunk.name();
chunks.reverse();
chunks.push(chunk);
let address = if encryption.is_some() {
BytesAddress::Private(name)
} else {
BytesAddress::Public(name)
};
break (address, chunks);
} else {
let serialized_chunk = Bytes::from(serialize(&chunk)?);
let (data_map, next_encrypted_chunks) =
self_encryption::encrypt(serialized_chunk).map_err(Error::SelfEncryption)?;
let expected_total = chunks.len() + next_encrypted_chunks.len();
chunks = next_encrypted_chunks
.par_iter()
.map(|c| to_chunk(c.content.clone(), no_encryption)) .flatten()
.chain(chunks)
.collect();
if expected_total > chunks.len() {
return Err(Error::NotAllDataWasChunked {
expected: expected_total,
chunked: chunks.len(),
});
}
chunk_content = pack_data_map(DataMapLevel::Additional(data_map))?;
}
};
let expected_total = encrypted_chunks.len() + additional_chunks.len();
let all_chunks: Vec<_> = encrypted_chunks
.par_iter()
.map(|c| to_chunk(c.content.clone(), no_encryption)) .flatten() .chain(additional_chunks)
.collect();
if expected_total > all_chunks.len() {
return Err(Error::NotAllDataWasChunked {
expected: expected_total,
chunked: all_chunks.len(),
});
}
Ok((address, all_chunks))
}
pub(crate) fn to_chunk(
chunk_content: Bytes,
encryption: Option<&impl Encryption>,
) -> Result<Chunk> {
let chunk: Chunk = if let Some(encryption) = encryption {
let encrypted_content = encryption.encrypt(chunk_content)?;
Chunk::new(encrypted_content)
} else {
Chunk::new(chunk_content)
};
Ok(chunk)
}
fn pack_data_map(data_map: DataMapLevel) -> Result<Bytes> {
Ok(Bytes::from(serialize(&data_map)?))
}
fn encrypt_file(file: &Path) -> Result<(DataMap, Vec<EncryptedChunk>)> {
let bytes = Bytes::from(std::fs::read(file).map_err(Error::IoError)?);
self_encryption::encrypt(bytes).map_err(Error::SelfEncryption)
}
fn encrypt_data(bytes: Bytes) -> Result<(DataMap, Vec<EncryptedChunk>)> {
self_encryption::encrypt(bytes).map_err(Error::SelfEncryption)
}