use iroh_blobs::Hash;
use ufotofu::sync::{consumer::IntoVec, producer::FromSlice};
pub use willow_data_model::{InvalidPathError, UnauthorisedWriteError};
use willow_encoding::sync::{Decodable, Encodable};
use super::{
keys,
meadowcap::{self},
};
pub type NamespaceId = keys::NamespaceId;
pub type SubspaceId = keys::UserId;
pub type WriteCapability = meadowcap::McCapability;
pub type SerdeWriteCapability = meadowcap::serde_encoding::SerdeMcCapability;
pub type Timestamp = willow_data_model::Timestamp;
pub type AuthorisationToken = meadowcap::McAuthorisationToken;
pub const MAX_COMPONENT_LENGTH: usize = 4096;
pub const MAX_COMPONENT_COUNT: usize = 1024;
pub const MAX_PATH_LENGTH: usize = 4096;
pub const DIGEST_LENGTH: usize = 32;
pub type Component<'a> = willow_data_model::Component<'a, MAX_COMPONENT_LENGTH>;
#[derive(
Debug,
Clone,
Copy,
Hash,
Eq,
PartialEq,
Ord,
PartialOrd,
derive_more::From,
derive_more::Into,
derive_more::Display,
)]
pub struct PayloadDigest(pub Hash);
impl Default for PayloadDigest {
fn default() -> Self {
Self(Hash::from_bytes([0u8; 32]))
}
}
impl willow_data_model::PayloadDigest for PayloadDigest {}
pub type Path = willow_data_model::Path<MAX_COMPONENT_LENGTH, MAX_COMPONENT_COUNT, MAX_PATH_LENGTH>;
pub trait PathExt {
fn from_bytes(slices: &[&[u8]]) -> Result<Path, InvalidPathError2>;
fn fmt_utf8(&self) -> String;
}
impl PathExt for Path {
fn from_bytes(slices: &[&[u8]]) -> Result<Self, InvalidPathError2> {
let component_count = slices.len();
let total_len = slices.iter().map(|x| x.len()).sum::<usize>();
let iter = slices.iter().filter_map(|c| Component::new(c));
let mut iter = iter.collect::<Vec<_>>().into_iter();
let path = willow_data_model::Path::new_from_iter(total_len, &mut iter)?;
if path.get_component_count() != component_count {
Err(InvalidPathError2::ComponentTooLong(
path.get_component_count(),
))
} else {
Ok(path)
}
}
fn fmt_utf8(&self) -> String {
let mut s = String::new();
let mut iter = self.components().peekable();
while let Some(c) = iter.next() {
if let Ok(c) = std::str::from_utf8(c.as_ref()) {
s.push_str(c);
} else {
s.push_str(&format!("<{}>", hex::encode(c.as_ref())));
}
if iter.peek().is_some() {
s.push('/');
}
}
s
}
}
#[derive(Debug, thiserror::Error)]
pub enum InvalidPathError2 {
#[error("One of the path's component is too large.")]
ComponentTooLong(usize),
#[error("The path's total length in bytes is too large.")]
PathTooLong,
#[error("The path has too many components.")]
TooManyComponents,
}
impl From<InvalidPathError> for InvalidPathError2 {
fn from(value: InvalidPathError) -> Self {
match value {
InvalidPathError::PathTooLong => Self::PathTooLong,
InvalidPathError::TooManyComponents => Self::TooManyComponents,
}
}
}
pub type Entry = willow_data_model::Entry<
MAX_COMPONENT_LENGTH,
MAX_COMPONENT_COUNT,
MAX_PATH_LENGTH,
NamespaceId,
SubspaceId,
PayloadDigest,
>;
pub trait EntryExt {
fn encode_to_vec(&self) -> Vec<u8>;
fn decode_from_slice(bytes: &[u8]) -> anyhow::Result<Entry>;
fn as_sortable_tuple(&self) -> (&NamespaceId, &SubspaceId, &Path);
}
impl EntryExt for Entry {
fn encode_to_vec(&self) -> Vec<u8> {
let mut consumer = IntoVec::<u8>::new();
self.encode(&mut consumer).expect("encoding not to fail");
consumer.into_vec()
}
fn decode_from_slice(bytes: &[u8]) -> anyhow::Result<Self> {
let mut producer = FromSlice::<u8>::new(bytes);
let entry = willow_data_model::Entry::decode(&mut producer)?;
Ok(entry)
}
fn as_sortable_tuple(&self) -> (&NamespaceId, &SubspaceId, &Path) {
(self.namespace_id(), self.subspace_id(), self.path())
}
}
pub type AuthorisedEntry = willow_data_model::AuthorisedEntry<
MAX_COMPONENT_LENGTH,
MAX_COMPONENT_COUNT,
MAX_PATH_LENGTH,
NamespaceId,
SubspaceId,
PayloadDigest,
AuthorisationToken,
>;
use syncify::{syncify, syncify_replace};
#[syncify(encoding_sync)]
mod encoding {
#[syncify_replace(use ufotofu::sync::{BulkConsumer, BulkProducer};)]
use ufotofu::local_nb::{BulkConsumer, BulkProducer};
#[syncify_replace(use willow_encoding::sync::{Decodable, Encodable};)]
use willow_encoding::{Decodable, Encodable};
use super::*;
impl Encodable for PayloadDigest {
async fn encode<Consumer>(&self, consumer: &mut Consumer) -> Result<(), Consumer::Error>
where
Consumer: BulkConsumer<Item = u8>,
{
consumer
.bulk_consume_full_slice(self.0.as_bytes())
.await
.map_err(|err| err.reason)
}
}
impl Decodable for PayloadDigest {
async fn decode<Producer>(
producer: &mut Producer,
) -> Result<Self, willow_encoding::DecodeError<Producer::Error>>
where
Producer: BulkProducer<Item = u8>,
Self: Sized,
{
let mut bytes = [0u8; DIGEST_LENGTH];
producer.bulk_overwrite_full_slice(&mut bytes).await?;
Ok(Self(Hash::from_bytes(bytes)))
}
}
}
pub mod serde_encoding {
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use super::*;
use crate::util::codec2::{from_bytes, to_vec};
pub mod path {
use super::*;
pub fn serialize<S: Serializer>(path: &Path, serializer: S) -> Result<S::Ok, S::Error> {
to_vec(path).serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Path, D::Error>
where
D: Deserializer<'de>,
{
let bytes: Vec<u8> = Deserialize::deserialize(deserializer)?;
let decoded = from_bytes(&bytes).map_err(de::Error::custom)?;
Ok(decoded)
}
}
pub mod entry {
use super::*;
pub fn serialize<S: Serializer>(entry: &Entry, serializer: S) -> Result<S::Ok, S::Error> {
to_vec(entry).serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Entry, D::Error>
where
D: Deserializer<'de>,
{
let bytes: Vec<u8> = Deserialize::deserialize(deserializer)?;
let decoded = from_bytes(&bytes).map_err(de::Error::custom)?;
Ok(decoded)
}
}
#[derive(
Debug,
Clone,
derive_more::From,
derive_more::Into,
derive_more::Deref,
Serialize,
Deserialize,
)]
pub struct SerdeEntry(#[serde(with = "entry")] pub Entry);
pub mod authorised_entry {
use keys::UserSignature;
use super::*;
use crate::proto::meadowcap::serde_encoding::SerdeMcCapability;
pub fn serialize<S: Serializer>(
entry: &AuthorisedEntry,
serializer: S,
) -> Result<S::Ok, S::Error> {
let (entry, token) = entry.clone().into_parts();
(
SerdeEntry(entry),
SerdeMcCapability(token.capability),
token.signature,
)
.serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<AuthorisedEntry, D::Error>
where
D: Deserializer<'de>,
{
let (entry, capability, signature): (SerdeEntry, SerdeMcCapability, UserSignature) =
Deserialize::deserialize(deserializer)?;
let token = AuthorisationToken::new(capability.0, signature);
AuthorisedEntry::new(entry.0, token).map_err(de::Error::custom)
}
}
#[derive(
Debug,
Clone,
derive_more::From,
derive_more::Into,
derive_more::Deref,
Serialize,
Deserialize,
)]
pub struct SerdeAuthorisedEntry(#[serde(with = "authorised_entry")] pub AuthorisedEntry);
}