use futures::{Future, IntoFuture};
use interledger_packet::{Address, Fulfill, Prepare, Reject};
use std::{
cmp::Eq,
fmt::{self, Debug, Display},
hash::Hash,
marker::PhantomData,
str::FromStr,
sync::Arc,
};
use serde::Serialize;
mod auth;
pub use auth::{Auth as AuthToken, Username};
#[cfg(feature = "trace")]
mod trace;
#[cfg(feature = "trace")]
pub use trace::*;
pub trait Account: Clone + Send + Sized + Debug {
type AccountId: Eq + Hash + Debug + Display + Default + FromStr + Send + Sync + Copy + Serialize;
fn id(&self) -> Self::AccountId;
fn username(&self) -> &Username;
fn ilp_address(&self) -> &Address;
fn asset_scale(&self) -> u8;
fn asset_code(&self) -> &str;
}
#[derive(Clone)]
pub struct IncomingRequest<A: Account> {
pub from: A,
pub prepare: Prepare,
}
impl<A> Debug for IncomingRequest<A>
where
A: Account,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("IncomingRequest")
.field("prepare", &self.prepare)
.field("from", &self.from)
.finish()
}
}
#[derive(Clone)]
pub struct OutgoingRequest<A: Account> {
pub from: A,
pub to: A,
pub original_amount: u64,
pub prepare: Prepare,
}
impl<A> Debug for OutgoingRequest<A>
where
A: Account,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("OutgoingRequest")
.field("prepare", &self.prepare)
.field("original_amount", &self.original_amount)
.field("to", &self.to)
.field("from", &self.from)
.finish()
}
}
impl<A> IncomingRequest<A>
where
A: Account,
{
pub fn into_outgoing(self, to: A) -> OutgoingRequest<A> {
OutgoingRequest {
from: self.from,
original_amount: self.prepare.amount(),
prepare: self.prepare,
to,
}
}
}
pub trait IncomingService<A: Account> {
type Future: Future<Item = Fulfill, Error = Reject> + Send + 'static;
fn handle_request(&mut self, request: IncomingRequest<A>) -> Self::Future;
fn wrap<F, R>(self, f: F) -> WrappedService<F, Self, A>
where
F: Fn(IncomingRequest<A>, Self) -> R,
R: Future<Item = Fulfill, Error = Reject> + Send + 'static,
Self: Clone + Sized,
{
WrappedService::wrap_incoming(self, f)
}
}
pub trait OutgoingService<A: Account> {
type Future: Future<Item = Fulfill, Error = Reject> + Send + 'static;
fn send_request(&mut self, request: OutgoingRequest<A>) -> Self::Future;
fn wrap<F, R>(self, f: F) -> WrappedService<F, Self, A>
where
F: Fn(OutgoingRequest<A>, Self) -> R,
R: Future<Item = Fulfill, Error = Reject> + Send + 'static,
Self: Clone + Sized,
{
WrappedService::wrap_outgoing(self, f)
}
}
pub type BoxedIlpFuture = Box<dyn Future<Item = Fulfill, Error = Reject> + Send + 'static>;
pub trait AccountStore {
type Account: Account;
fn get_accounts(
&self,
account_ids: Vec<<<Self as AccountStore>::Account as Account>::AccountId>,
) -> Box<dyn Future<Item = Vec<Self::Account>, Error = ()> + Send>;
fn get_account_id_from_username(
&self,
username: &Username,
) -> Box<
dyn Future<Item = <<Self as AccountStore>::Account as Account>::AccountId, Error = ()>
+ Send,
>;
}
pub fn incoming_service_fn<A, B, F>(handler: F) -> ServiceFn<F, A>
where
A: Account,
B: IntoFuture<Item = Fulfill, Error = Reject>,
F: FnMut(IncomingRequest<A>) -> B,
{
ServiceFn {
handler,
account_type: PhantomData,
}
}
pub fn outgoing_service_fn<A, B, F>(handler: F) -> ServiceFn<F, A>
where
A: Account,
B: IntoFuture<Item = Fulfill, Error = Reject>,
F: FnMut(OutgoingRequest<A>) -> B,
{
ServiceFn {
handler,
account_type: PhantomData,
}
}
#[derive(Clone)]
pub struct ServiceFn<F, A> {
handler: F,
account_type: PhantomData<A>,
}
impl<F, A, B> IncomingService<A> for ServiceFn<F, A>
where
A: Account,
B: IntoFuture<Item = Fulfill, Error = Reject>,
<B as futures::future::IntoFuture>::Future: std::marker::Send + 'static,
F: FnMut(IncomingRequest<A>) -> B,
{
type Future = BoxedIlpFuture;
fn handle_request(&mut self, request: IncomingRequest<A>) -> Self::Future {
Box::new((self.handler)(request).into_future())
}
}
impl<F, A, B> OutgoingService<A> for ServiceFn<F, A>
where
A: Account,
B: IntoFuture<Item = Fulfill, Error = Reject>,
<B as futures::future::IntoFuture>::Future: std::marker::Send + 'static,
F: FnMut(OutgoingRequest<A>) -> B,
{
type Future = BoxedIlpFuture;
fn send_request(&mut self, request: OutgoingRequest<A>) -> Self::Future {
Box::new((self.handler)(request).into_future())
}
}
#[derive(Clone)]
pub struct WrappedService<F, I, A> {
f: F,
inner: Arc<I>,
account_type: PhantomData<A>,
}
impl<F, IO, A, R> WrappedService<F, IO, A>
where
F: Fn(IncomingRequest<A>, IO) -> R,
IO: IncomingService<A> + Clone,
A: Account,
R: Future<Item = Fulfill, Error = Reject> + Send + 'static,
{
pub fn wrap_incoming(inner: IO, f: F) -> Self {
WrappedService {
f,
inner: Arc::new(inner),
account_type: PhantomData,
}
}
}
impl<F, IO, A, R> IncomingService<A> for WrappedService<F, IO, A>
where
F: Fn(IncomingRequest<A>, IO) -> R,
IO: IncomingService<A> + Clone,
A: Account,
R: Future<Item = Fulfill, Error = Reject> + Send + 'static,
{
type Future = R;
fn handle_request(&mut self, request: IncomingRequest<A>) -> R {
(self.f)(request, (*self.inner).clone())
}
}
impl<F, IO, A, R> WrappedService<F, IO, A>
where
F: Fn(OutgoingRequest<A>, IO) -> R,
IO: OutgoingService<A> + Clone,
A: Account,
R: Future<Item = Fulfill, Error = Reject> + Send + 'static,
{
pub fn wrap_outgoing(inner: IO, f: F) -> Self {
WrappedService {
f,
inner: Arc::new(inner),
account_type: PhantomData,
}
}
}
impl<F, IO, A, R> OutgoingService<A> for WrappedService<F, IO, A>
where
F: Fn(OutgoingRequest<A>, IO) -> R,
IO: OutgoingService<A> + Clone,
A: Account,
R: Future<Item = Fulfill, Error = Reject> + Send + 'static,
{
type Future = R;
fn send_request(&mut self, request: OutgoingRequest<A>) -> R {
(self.f)(request, (*self.inner).clone())
}
}
pub trait AddressStore: Clone {
fn set_ilp_address(
&self,
ilp_address: Address,
) -> Box<dyn Future<Item = (), Error = ()> + Send>;
fn clear_ilp_address(&self) -> Box<dyn Future<Item = (), Error = ()> + Send>;
fn get_ilp_address(&self) -> Address;
}