2019-09-11 11:00:22 -07:00
|
|
|
use futures_util::ready;
|
|
|
|
use pin_project::{pin_project, project};
|
2019-04-27 09:32:26 -07:00
|
|
|
use std::time::Duration;
|
2019-09-11 11:00:22 -07:00
|
|
|
use std::{
|
|
|
|
future::Future,
|
|
|
|
pin::Pin,
|
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
|
|
|
use tower_service::Service;
|
2019-04-27 09:32:26 -07:00
|
|
|
|
|
|
|
/// A policy which specifies how long each request should be delayed for.
|
|
|
|
pub trait Policy<Request> {
|
|
|
|
fn delay(&self, req: &Request) -> Duration;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A middleware which delays sending the request to the underlying service
|
|
|
|
/// for an amount of time specified by the policy.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Delay<P, S> {
|
|
|
|
policy: P,
|
|
|
|
service: S,
|
|
|
|
}
|
|
|
|
|
2019-09-11 11:00:22 -07:00
|
|
|
#[pin_project]
|
2019-04-27 09:32:26 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ResponseFuture<Request, S, F> {
|
|
|
|
service: S,
|
2019-09-11 11:00:22 -07:00
|
|
|
#[pin]
|
2019-04-27 09:32:26 -07:00
|
|
|
state: State<Request, F>,
|
|
|
|
}
|
|
|
|
|
2019-09-11 11:00:22 -07:00
|
|
|
#[pin_project]
|
2019-04-27 09:32:26 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum State<Request, F> {
|
2019-12-05 11:21:47 -08:00
|
|
|
Delaying(#[pin] tokio::time::Delay, Option<Request>),
|
2019-09-11 11:00:22 -07:00
|
|
|
Called(#[pin] F),
|
2019-04-27 09:32:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<P, S> Delay<P, S> {
|
|
|
|
pub fn new<Request>(policy: P, service: S) -> Self
|
|
|
|
where
|
|
|
|
P: Policy<Request>,
|
|
|
|
S: Service<Request> + Clone,
|
|
|
|
S::Error: Into<super::Error>,
|
|
|
|
{
|
|
|
|
Delay { policy, service }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Request, P, S> Service<Request> for Delay<P, S>
|
|
|
|
where
|
|
|
|
P: Policy<Request>,
|
|
|
|
S: Service<Request> + Clone,
|
|
|
|
S::Error: Into<super::Error>,
|
|
|
|
{
|
|
|
|
type Response = S::Response;
|
|
|
|
type Error = super::Error;
|
|
|
|
type Future = ResponseFuture<Request, S, S::Future>;
|
|
|
|
|
2019-09-11 11:00:22 -07:00
|
|
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
self.service.poll_ready(cx).map_err(|e| e.into())
|
2019-04-27 09:32:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn call(&mut self, request: Request) -> Self::Future {
|
2019-12-05 11:21:47 -08:00
|
|
|
let deadline = tokio::time::Instant::now() + self.policy.delay(&request);
|
2019-04-27 09:32:26 -07:00
|
|
|
let mut cloned = self.service.clone();
|
|
|
|
// Pass the original service to the ResponseFuture and keep the cloned service on self.
|
|
|
|
let orig = {
|
|
|
|
std::mem::swap(&mut cloned, &mut self.service);
|
|
|
|
cloned
|
|
|
|
};
|
|
|
|
ResponseFuture {
|
|
|
|
service: orig,
|
2019-12-05 11:21:47 -08:00
|
|
|
state: State::Delaying(tokio::time::delay_until(deadline), Some(request)),
|
2019-04-27 09:32:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-11 11:00:22 -07:00
|
|
|
impl<Request, S, F, T, E> Future for ResponseFuture<Request, S, F>
|
2019-04-27 09:32:26 -07:00
|
|
|
where
|
2019-09-11 11:00:22 -07:00
|
|
|
F: Future<Output = Result<T, E>>,
|
|
|
|
E: Into<super::Error>,
|
|
|
|
S: Service<Request, Future = F, Response = T, Error = E>,
|
2019-04-27 09:32:26 -07:00
|
|
|
{
|
2019-09-11 11:00:22 -07:00
|
|
|
type Output = Result<T, super::Error>;
|
|
|
|
|
|
|
|
#[project]
|
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 mut this = self.project();
|
2019-04-27 09:32:26 -07:00
|
|
|
|
|
|
|
loop {
|
2019-09-11 11:00:22 -07:00
|
|
|
#[project]
|
2019-09-30 11:58:27 -07:00
|
|
|
match this.state.as_mut().project() {
|
2019-09-11 11:00:22 -07:00
|
|
|
State::Delaying(delay, req) => {
|
|
|
|
ready!(delay.poll(cx));
|
|
|
|
let req = req.take().expect("Missing request in delay");
|
|
|
|
let fut = this.service.call(req);
|
|
|
|
this.state.set(State::Called(fut));
|
|
|
|
}
|
|
|
|
State::Called(fut) => {
|
|
|
|
return fut.poll(cx).map_err(Into::into);
|
2019-04-27 09:32:26 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|