2019-09-11 11:00:22 -07:00
|
|
|
use pin_project::pin_project;
|
|
|
|
use std::{
|
|
|
|
future::Future,
|
|
|
|
pin::Pin,
|
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
2019-04-27 09:32:26 -07:00
|
|
|
use tower_service::Service;
|
|
|
|
|
|
|
|
/// A policy which decides which requests can be cloned and sent to the B
|
|
|
|
/// service.
|
|
|
|
pub trait Policy<Request> {
|
|
|
|
fn clone_request(&self, req: &Request) -> Option<Request>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Select is a middleware which attempts to clone the request and sends the
|
|
|
|
/// original request to the A service and, if the request was able to be cloned,
|
|
|
|
/// the cloned request to the B service. Both resulting futures will be polled
|
|
|
|
/// and whichever future completes first will be used as the result.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Select<P, A, B> {
|
|
|
|
policy: P,
|
|
|
|
a: A,
|
|
|
|
b: B,
|
|
|
|
}
|
|
|
|
|
2019-09-11 11:00:22 -07:00
|
|
|
#[pin_project]
|
2019-04-27 09:32:26 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ResponseFuture<AF, BF> {
|
2019-09-11 11:00:22 -07:00
|
|
|
#[pin]
|
2019-04-27 09:32:26 -07:00
|
|
|
a_fut: AF,
|
2019-09-11 11:00:22 -07:00
|
|
|
#[pin]
|
2019-04-27 09:32:26 -07:00
|
|
|
b_fut: Option<BF>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<P, A, B> Select<P, A, B> {
|
|
|
|
pub fn new<Request>(policy: P, a: A, b: B) -> Self
|
|
|
|
where
|
|
|
|
P: Policy<Request>,
|
|
|
|
A: Service<Request>,
|
|
|
|
A::Error: Into<super::Error>,
|
|
|
|
B: Service<Request, Response = A::Response>,
|
|
|
|
B::Error: Into<super::Error>,
|
|
|
|
{
|
|
|
|
Select { policy, a, b }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<P, A, B, Request> Service<Request> for Select<P, A, B>
|
|
|
|
where
|
|
|
|
P: Policy<Request>,
|
|
|
|
A: Service<Request>,
|
2019-12-19 14:30:23 -08:00
|
|
|
A::Error: Into<super::Error>,
|
2019-04-27 09:32:26 -07:00
|
|
|
B: Service<Request, Response = A::Response>,
|
2019-12-19 14:30:23 -08:00
|
|
|
B::Error: Into<super::Error>,
|
2019-04-27 09:32:26 -07:00
|
|
|
{
|
|
|
|
type Response = A::Response;
|
|
|
|
type Error = super::Error;
|
|
|
|
type Future = ResponseFuture<A::Future, B::Future>;
|
|
|
|
|
2019-09-11 11:00:22 -07:00
|
|
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
match (self.a.poll_ready(cx), self.b.poll_ready(cx)) {
|
|
|
|
(Poll::Ready(Ok(())), Poll::Ready(Ok(()))) => Poll::Ready(Ok(())),
|
|
|
|
(Poll::Ready(Err(e)), _) => Poll::Ready(Err(e.into())),
|
|
|
|
(_, Poll::Ready(Err(e))) => Poll::Ready(Err(e.into())),
|
|
|
|
_ => Poll::Pending,
|
2019-04-27 09:32:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call(&mut self, request: Request) -> Self::Future {
|
|
|
|
let b_fut = if let Some(cloned_req) = self.policy.clone_request(&request) {
|
|
|
|
Some(self.b.call(cloned_req))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
ResponseFuture {
|
|
|
|
a_fut: self.a.call(request),
|
|
|
|
b_fut,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-11 11:00:22 -07:00
|
|
|
impl<AF, BF, T, AE, BE> Future for ResponseFuture<AF, BF>
|
2019-04-27 09:32:26 -07:00
|
|
|
where
|
2019-09-11 11:00:22 -07:00
|
|
|
AF: Future<Output = Result<T, AE>>,
|
2019-12-19 14:30:23 -08:00
|
|
|
AE: Into<super::Error>,
|
2019-09-11 11:00:22 -07:00
|
|
|
BF: Future<Output = Result<T, BE>>,
|
2019-12-19 14:30:23 -08:00
|
|
|
BE: Into<super::Error>,
|
2019-04-27 09:32:26 -07:00
|
|
|
{
|
2019-09-11 11:00:22 -07:00
|
|
|
type Output = Result<T, super::Error>;
|
|
|
|
|
2019-09-30 11:58:27 -07:00
|
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
2019-09-11 11:00:22 -07:00
|
|
|
let this = self.project();
|
2019-04-27 09:32:26 -07:00
|
|
|
|
2019-09-11 11:00:22 -07:00
|
|
|
if let Poll::Ready(r) = this.a_fut.poll(cx) {
|
2019-12-19 14:30:23 -08:00
|
|
|
return Poll::Ready(Ok(r.map_err(Into::into)?));
|
2019-04-27 09:32:26 -07:00
|
|
|
}
|
2019-09-11 11:00:22 -07:00
|
|
|
if let Some(b_fut) = this.b_fut.as_pin_mut() {
|
|
|
|
if let Poll::Ready(r) = b_fut.poll(cx) {
|
2019-12-19 14:30:23 -08:00
|
|
|
return Poll::Ready(Ok(r.map_err(Into::into)?));
|
2019-04-27 09:32:26 -07:00
|
|
|
}
|
|
|
|
}
|
2019-09-11 11:00:22 -07:00
|
|
|
return Poll::Pending;
|
2019-04-27 09:32:26 -07:00
|
|
|
}
|
|
|
|
}
|