use futures_util::future::BoxFuture;
use std::{future::Future, task::Poll};
use tower_layer::{Layer, Stack};
use tower_service::Service;
use crate::{
backend::Backend,
error::BoxDynError,
task::{ExecutionContext, Task},
worker::builder::WorkerBuilder,
};
pub trait AcknowledgementExt<Args, Source, Middleware, Ack, Res>: Sized
where
Source: Backend,
Ack: Acknowledge<Res>,
{
fn ack_with(
self,
ack: Ack,
) -> WorkerBuilder<Args, Source, Stack<AcknowledgeLayer<Ack>, Middleware>>;
}
pub trait Acknowledge<Res> {
type Error;
type Future: Future<Output = Result<(), Self::Error>>;
fn ack(&mut self, res: &Result<Res, BoxDynError>, ctx: &ExecutionContext) -> Self::Future;
}
impl<Res, F, Fut, E> Acknowledge<Res> for F
where
for<'c> F: FnMut(&'c Result<Res, BoxDynError>, &'c ExecutionContext) -> Fut,
Fut: Future<Output = Result<(), E>>,
{
type Error = E;
type Future = Fut;
fn ack(&mut self, res: &Result<Res, BoxDynError>, ctx: &ExecutionContext) -> Self::Future {
(self)(res, ctx)
}
}
#[derive(Debug, Clone)]
pub struct AcknowledgeLayer<A> {
acknowledger: A,
}
impl<A> AcknowledgeLayer<A> {
pub fn new(acknowledger: A) -> Self {
Self { acknowledger }
}
}
impl<S, A> Layer<S> for AcknowledgeLayer<A>
where
A: Clone,
{
type Service = AcknowledgeService<S, A>;
fn layer(&self, inner: S) -> Self::Service {
AcknowledgeService {
inner,
acknowledger: self.acknowledger.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct AcknowledgeService<S, A> {
inner: S,
acknowledger: A,
}
impl<S, A, Args, Res> Service<Task<Args>> for AcknowledgeService<S, A>
where
S: Service<Task<Args>, Response = Res>,
A: Acknowledge<Res> + Clone + Send + 'static,
S::Error: Into<BoxDynError>,
A::Error: std::error::Error + Send + Sync + 'static,
S::Future: Send + 'static,
A::Future: Send + 'static,
Res: Send,
{
type Response = Res;
type Error = BoxDynError;
type Future = BoxFuture<'static, Result<Res, BoxDynError>>;
fn poll_ready(&mut self, cx: &mut std::task::Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx).map_err(|e| e.into())
}
fn call(&mut self, task: Task<Args>) -> Self::Future {
let ctx = task.ctx().clone();
let future = self.inner.call(task);
let mut acknowledger = self.acknowledger.clone();
Box::pin(async move {
let res = future.await.map_err(|e| e.into());
acknowledger.ack(&res, &ctx).await?;
res
})
}
}
impl<Args, B, M, Ack, Res> AcknowledgementExt<Args, B, M, Ack, Res> for WorkerBuilder<Args, B, M>
where
M: Layer<AcknowledgeLayer<Ack>>,
Ack: Acknowledge<Res>,
B: Backend,
{
fn ack_with(self, ack: Ack) -> WorkerBuilder<Args, B, Stack<AcknowledgeLayer<Ack>, M>> {
let this = self.layer(AcknowledgeLayer::new(ack));
WorkerBuilder {
context: this.context,
request: this.request,
layer: this.layer,
source: this.source,
shutdown: this.shutdown,
event_handler: this.event_handler,
}
}
}