use std::{
collections::BTreeMap,
path::{Path, PathBuf},
};
use bytes::Bytes;
use color_eyre::eyre::{eyre, Result};
use autonomi::chunk::DataMapChunk;
use autonomi::client::files::RenameError;
use autonomi::data::DataAddress;
use autonomi::files::{Metadata, PrivateArchive, PublicArchive};
use crate::storage::DwebType;
pub const ARCHIVE_PATH_SEPARATOR: char = '/';
#[derive(Clone)]
pub struct DualArchive {
pub dweb_type: DwebType,
pub public_archive: PublicArchive,
pub private_archive: PrivateArchive,
}
impl DualArchive {
pub fn new() -> Self {
Self {
dweb_type: DwebType::Unknown,
public_archive: PublicArchive::new(),
private_archive: PrivateArchive::new(),
}
}
pub fn lookup_file(&self, path: &PathBuf) -> Option<(String, String, &Metadata)> {
match self.dweb_type {
DwebType::PrivateArchive => {
if let Some((datamap_chunk, metadata)) = self.private_archive.map().get(path) {
Some((datamap_chunk.to_hex(), "".to_string(), metadata))
} else {
None
}
}
DwebType::PublicArchive => {
if let Some((data_address, metadata)) = self.public_archive.map().get(path) {
Some(("".to_string(), data_address.to_hex(), metadata))
} else {
None
}
}
_ => {
println!(
"DEBUG DualArchive accessed with type {:?} - this is probably a bug",
self.dweb_type
);
None
}
}
}
pub fn rename_file(&mut self, old_path: &Path, new_path: &Path) -> Result<(), RenameError> {
match self.public_archive.rename_file(old_path, new_path) {
Ok(()) => (),
Err(e) => return Err(e),
}
self.private_archive.rename_file(old_path, new_path)
}
pub fn add_file_as_public(&mut self, path: PathBuf, data_addr: DataAddress, meta: Metadata) {
self.public_archive.add_file(path, data_addr, meta);
}
pub fn add_file_as_private(&mut self, path: PathBuf, data_map: DataMapChunk, meta: Metadata) {
self.private_archive.add_file(path, data_map, meta);
}
pub fn files(&self) -> Vec<(PathBuf, Metadata)> {
match self.dweb_type {
DwebType::PrivateArchive => self.private_archive.files(),
DwebType::PublicArchive => self.public_archive.files(),
_ => Vec::<(PathBuf, Metadata)>::new(),
}
}
pub fn addresses(&self) -> Vec<DataAddress> {
self.public_archive.addresses()
}
pub fn data_maps(&self) -> Vec<DataMapChunk> {
self.private_archive.data_maps()
}
pub fn iter_as_public(&self) -> impl Iterator<Item = (&PathBuf, &DataAddress, &Metadata)> {
self.public_archive.iter()
}
pub fn map_as_public(&self) -> &BTreeMap<PathBuf, (DataAddress, Metadata)> {
&self.public_archive.map()
}
pub fn map_as_private(&self) -> &BTreeMap<PathBuf, (DataMapChunk, Metadata)> {
self.private_archive.map()
}
pub fn from_bytes(data: Bytes) -> Result<DualArchive> {
println!("DEBUG DualArchive attempting to deserialise as PrivateArchive...");
match DualArchive::from_bytes_as_private(data.clone()) {
Ok(private_dual_archive) => Ok(private_dual_archive),
Err(_e) => {
println!("DEBUG DualArchive attempting to deserialise as PublicArchive...");
match DualArchive::from_bytes_as_public(data) {
Ok(public_dual_archive) => Ok(public_dual_archive),
Err(e) => Err(e),
}
}
}
}
pub fn from_bytes_as_private(data: Bytes) -> Result<DualArchive> {
match PrivateArchive::from_bytes(data) {
Ok(archive) => {
if let Some((_path_buf, (datamap_chunk, _metadata))) = archive.map().iter().next() {
if datamap_chunk.to_hex().len() <= crate::helpers::DATA_ADDRESS_LEN {
return Err(eyre!(
"Found DataAddress instead of DatamapChunk: {}",
datamap_chunk.to_hex()
));
}
}
{
Ok(DualArchive {
dweb_type: DwebType::PrivateArchive,
public_archive: PublicArchive::new(),
private_archive: archive,
})
}
}
Err(e) => return Err(e.into()),
}
}
pub fn from_bytes_as_public(data: Bytes) -> Result<DualArchive> {
match Self::from_bytes_as_private(data.clone()) {
Ok(_archive) => return Err(eyre!("Found PrivateArchive not PublicArchive")),
Err(_) => {}
}
match PublicArchive::from_bytes(data) {
Ok(archive) => Ok(DualArchive {
dweb_type: DwebType::PublicArchive,
public_archive: archive,
private_archive: PrivateArchive::new(),
}),
Err(e) => return Err(e.into()),
}
}
pub fn to_bytes_as_public(&self) -> Result<Bytes, rmp_serde::encode::Error> {
match self.dweb_type {
DwebType::PublicArchive => PublicArchive::to_bytes(&self.public_archive),
_ => {
return Err(rmp_serde::encode::Error::InvalidDataModel(
"DualArchive::to_bytes_as_public() can only serialise DwebType::PublicArchive",
))
}
}
}
pub fn to_bytes_as_private(&self) -> Result<Bytes, rmp_serde::encode::Error> {
match self.dweb_type {
DwebType::PrivateArchive => PrivateArchive::to_bytes(&self.private_archive),
_ => return Err(rmp_serde::encode::Error::InvalidDataModel(
"DualArchive::to_bytes_as_private() can only serialise DwebType::PrivateArchive",
)),
}
}
pub fn merge_as_public(&mut self, other: &PublicArchive) {
self.public_archive.merge(other)
}
pub fn merge_as_private(&mut self, other: &PrivateArchive) {
self.private_archive.merge(other)
}
}