#[cfg(feature = "providers")]
pub mod embedded;
#[cfg(feature = "providers")]
pub mod file;
use std::convert::TryInto;
use thiserror::Error;
use tokio_stream::Stream;
use crate::verification::Verified;
use crate::SignatureError;
use crate::{Id, Signed};
pub type Result<T> = core::result::Result<T, ProviderError>;
#[async_trait::async_trait]
pub trait Provider {
async fn create_invoice<I>(&self, inv: I) -> Result<(crate::Invoice, Vec<super::Label>)>
where
I: Signed + Verified + Send + Sync;
async fn get_invoice<I>(&self, id: I) -> Result<super::Invoice>
where
I: TryInto<Id> + Send,
I::Error: Into<ProviderError>,
{
match self.get_yanked_invoice(id).await {
Ok(inv) if !inv.yanked.unwrap_or(false) => Ok(inv),
Err(e) => Err(e),
_ => Err(ProviderError::Yanked),
}
}
async fn get_yanked_invoice<I>(&self, id: I) -> Result<super::Invoice>
where
I: TryInto<Id> + Send,
I::Error: Into<ProviderError>;
async fn yank_invoice<I>(&self, id: I) -> Result<()>
where
I: TryInto<Id> + Send,
I::Error: Into<ProviderError>;
async fn validate_parcel<I>(&self, bindle_id: I, parcel_id: &str) -> Result<crate::Label>
where
I: TryInto<Id> + Send,
I::Error: Into<ProviderError>,
{
let inv = self.get_yanked_invoice(bindle_id).await?;
match inv
.parcel
.unwrap_or_default()
.into_iter()
.find(|p| p.label.sha256 == parcel_id)
{
Some(p) => Ok(p.label),
None => Err(ProviderError::NotFound),
}
}
async fn create_parcel<I, R, B>(&self, bindle_id: I, parcel_id: &str, data: R) -> Result<()>
where
I: TryInto<Id> + Send,
I::Error: Into<ProviderError>,
R: Stream<Item = std::io::Result<B>> + Unpin + Send + Sync + 'static,
B: bytes::Buf + Send;
async fn get_parcel<I>(
&self,
bindle_id: I,
parcel_id: &str,
) -> Result<Box<dyn Stream<Item = Result<bytes::Bytes>> + Unpin + Send + Sync>>
where
I: TryInto<Id> + Send,
I::Error: Into<ProviderError>;
async fn parcel_exists<I>(&self, bindle_id: I, parcel_id: &str) -> Result<bool>
where
I: TryInto<Id> + Send,
I::Error: Into<ProviderError>;
}
#[derive(Error, Debug)]
pub enum ProviderError {
#[error("bindle is yanked")]
Yanked,
#[error("bindle cannot be created as yanked")]
CreateYanked,
#[error("resource not found: if an item does not appear in our records, it does not exist!")]
NotFound,
#[error("resource could not be loaded")]
Io(#[from] std::io::Error),
#[error("resource already exists")]
Exists,
#[error("invalid ID given")]
InvalidId(#[from] crate::id::ParseError),
#[error("digest does not match")]
DigestMismatch,
#[error("parcel size does not match invoice")]
SizeMismatch,
#[error(
"a write operation is currently in progress for this resource and it cannot be accessed"
)]
WriteInProgress,
#[cfg(feature = "client")]
#[error("proxy error")]
ProxyError(#[from] crate::client::ClientError),
#[error("resource is malformed")]
Malformed(#[from] toml::de::Error),
#[error("resource cannot be stored")]
Unserializable(#[from] toml::ser::Error),
#[error("failed signature check invoice")]
FailedSigning(#[from] SignatureError),
#[error("{0}")]
Other(String),
}
impl From<std::convert::Infallible> for ProviderError {
fn from(_: std::convert::Infallible) -> ProviderError {
ProviderError::Other("Shouldn't happen".to_string())
}
}
#[cfg(feature = "providers")]
impl From<serde_cbor::Error> for ProviderError {
fn from(e: serde_cbor::Error) -> Self {
if e.is_io() {
ProviderError::Io(std::io::Error::new(std::io::ErrorKind::Other, e))
} else {
ProviderError::Other(format!("Unable to parse CBOR payload: {}", e))
}
}
}