use std::fmt::{Debug, Display};
use async_trait::async_trait;
use uuid::Uuid;
use crate::linked_data::Link;
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
pub enum BucketLogError<T> {
#[error("unhandled bucket log provider error: {0}")]
Provider(#[from] T),
#[error("head not found at height {0}")]
HeadNotFound(u64),
#[error("conflict with current log entry")]
Conflict,
#[error("invalid append: {0}, {1}, {2}")]
InvalidAppend(Link, Link, u64),
}
#[async_trait]
pub trait BucketLogProvider: Send + Sync + std::fmt::Debug + Clone + 'static {
type Error: Display + Debug;
async fn exists(&self, id: Uuid) -> Result<bool, BucketLogError<Self::Error>>;
async fn heads(&self, id: Uuid, height: u64) -> Result<Vec<Link>, BucketLogError<Self::Error>>;
async fn append(
&self,
id: Uuid,
name: String,
current: Link,
previous: Option<Link>,
height: u64,
published: bool,
) -> Result<(), BucketLogError<Self::Error>>;
async fn height(&self, id: Uuid) -> Result<u64, BucketLogError<Self::Error>>;
async fn has(&self, id: Uuid, link: Link) -> Result<Vec<u64>, BucketLogError<Self::Error>>;
async fn head(
&self,
id: Uuid,
height: Option<u64>,
) -> Result<(Link, u64), BucketLogError<Self::Error>> {
let height = height.unwrap_or(self.height(id).await?);
let heads = self.heads(id, height).await?;
Ok((
heads
.into_iter()
.max()
.ok_or(BucketLogError::HeadNotFound(height))?,
height,
))
}
async fn list_buckets(&self) -> Result<Vec<Uuid>, BucketLogError<Self::Error>>;
async fn latest_published(
&self,
id: Uuid,
) -> Result<Option<(Link, u64)>, BucketLogError<Self::Error>>;
async fn should_sync_content(&self, _id: Uuid) -> Result<bool, BucketLogError<Self::Error>> {
Ok(true)
}
async fn on_new_bucket_discovered(
&self,
_id: Uuid,
_shared_by: Option<String>,
) -> Result<(), BucketLogError<Self::Error>> {
Ok(())
}
async fn list_syncable_buckets(&self) -> Result<Vec<Uuid>, BucketLogError<Self::Error>> {
self.list_buckets().await
}
}