use std::{
future::Future,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use axum::http::Request;
use tower::{Layer, Service};
use crate::{mail::scope_config, MailConfig};
#[derive(Clone)]
pub struct MailLayer {
config: Arc<MailConfig>,
#[cfg(feature = "queue")]
queue: Option<crate::queue_job::QueueRef>,
}
impl MailLayer {
pub fn new(config: MailConfig) -> Self {
Self {
config: Arc::new(config),
#[cfg(feature = "queue")]
queue: None,
}
}
#[cfg(feature = "queue")]
pub fn with_queue(mut self, queue: crate::queue_job::QueueRef) -> Self {
self.queue = Some(queue);
self
}
}
impl<S> Layer<S> for MailLayer {
type Service = MailService<S>;
fn layer(&self, inner: S) -> Self::Service {
MailService {
inner,
config: self.config.clone(),
#[cfg(feature = "queue")]
queue: self.queue.clone(),
}
}
}
#[derive(Clone)]
pub struct MailService<S> {
inner: S,
config: Arc<MailConfig>,
#[cfg(feature = "queue")]
queue: Option<crate::queue_job::QueueRef>,
}
impl<S, ReqBody> Service<Request<ReqBody>> for MailService<S>
where
S: Service<Request<ReqBody>> + Send + Clone + 'static,
S::Future: Send + 'static,
ReqBody: Send + 'static,
{
type Response = S::Response;
type Error = S::Error;
type Future = Pin<Box<dyn Future<Output = Result<S::Response, S::Error>> + Send + 'static>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
let config = self.config.clone();
req.extensions_mut().insert(config.clone());
#[cfg(feature = "queue")]
let queue = self.queue.clone();
#[cfg(feature = "queue")]
if let Some(ref q) = queue {
req.extensions_mut().insert(q.clone());
}
let future = self.inner.call(req);
#[cfg(feature = "queue")]
{
if let Some(q) = queue {
return Box::pin(crate::mail::scope_config(config, crate::mail::scope_queue(q, future)));
}
}
Box::pin(scope_config(config, future))
}
}