use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use crate::proto;
use crate::proto::{AsPaymentProblem, ErrorReason, PaymentProblem, PaymentVerificationError};
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FacilitatorError {
#[error(transparent)]
PaymentVerification(#[from] PaymentVerificationError),
#[error("Onchain error: {0}")]
OnchainFailure(String),
#[error("{reason}: {message}")]
Aborted {
reason: String,
message: String,
},
#[error(transparent)]
Other(Box<dyn std::error::Error + Send + Sync>),
}
impl AsPaymentProblem for FacilitatorError {
fn as_payment_problem(&self) -> PaymentProblem {
match self {
Self::PaymentVerification(e) => e.as_payment_problem(),
Self::OnchainFailure(e) => PaymentProblem::new(ErrorReason::UnexpectedError, e.clone()),
Self::Aborted { reason, message } => {
PaymentProblem::new(ErrorReason::UnexpectedError, format!("{reason}: {message}"))
}
Self::Other(e) => PaymentProblem::new(ErrorReason::UnexpectedError, e.to_string()),
}
}
}
pub trait Facilitator: Send + Sync {
fn verify(
&self,
request: proto::VerifyRequest,
) -> BoxFuture<'_, Result<proto::VerifyResponse, FacilitatorError>>;
fn settle(
&self,
request: proto::SettleRequest,
) -> BoxFuture<'_, Result<proto::SettleResponse, FacilitatorError>>;
fn supported(&self) -> BoxFuture<'_, Result<proto::SupportedResponse, FacilitatorError>>;
}
impl<T: Facilitator> Facilitator for Arc<T> {
fn verify(
&self,
request: proto::VerifyRequest,
) -> BoxFuture<'_, Result<proto::VerifyResponse, FacilitatorError>> {
self.as_ref().verify(request)
}
fn settle(
&self,
request: proto::SettleRequest,
) -> BoxFuture<'_, Result<proto::SettleResponse, FacilitatorError>> {
self.as_ref().settle(request)
}
fn supported(&self) -> BoxFuture<'_, Result<proto::SupportedResponse, FacilitatorError>> {
self.as_ref().supported()
}
}