scuffle_http/service/
tower_factory.rs

1use std::net::SocketAddr;
2
3use super::{HttpService, HttpServiceFactory};
4use crate::IncomingRequest;
5
6/// A [`HttpServiceFactory`] that wraps a [`tower::MakeService`](https://docs.rs/tower/latest/tower/trait.MakeService.html).
7/// The given [`tower::MakeService`](https://docs.rs/tower/latest/tower/trait.MakeService.html) will be called to create a new service for each new connection.
8///
9/// Create by calling [`tower_make_service_factory`] or [`custom_tower_make_service_factory`].
10#[derive(Clone, Debug)]
11pub struct TowerMakeServiceFactory<M, T> {
12    make_service: M,
13    target: T,
14}
15
16/// Create a [`TowerMakeServiceFactory`] from a given [`tower::MakeService`](https://docs.rs/tower/latest/tower/trait.MakeService.html) and `target` value.
17///
18/// `target` is the value that will be passed to the [`tower::MakeService::make_service`] method.
19/// `target` will be cloned for each new connection.
20/// If the `target` should be the remote address of the incoming connection, use [`tower_make_service_with_addr_factory`] instead.
21/// If `target` is not needed, use [`tower_make_service_factory`] instead.
22pub fn custom_tower_make_service_factory<M, T>(make_service: M, target: T) -> TowerMakeServiceFactory<M, T> {
23    TowerMakeServiceFactory { make_service, target }
24}
25
26/// Create a [`TowerMakeServiceFactory`] from a given [`tower::MakeService`](https://docs.rs/tower/latest/tower/trait.MakeService.html).
27///
28/// Can be used with [`axum::Router::into_make_service`](https://docs.rs/axum/latest/axum/struct.Router.html#method.into_make_service).
29pub fn tower_make_service_factory<M>(make_service: M) -> TowerMakeServiceFactory<M, ()> {
30    TowerMakeServiceFactory {
31        make_service,
32        target: (),
33    }
34}
35
36impl<M, T> HttpServiceFactory for TowerMakeServiceFactory<M, T>
37where
38    M: tower::MakeService<T, IncomingRequest> + Send,
39    M::Future: Send,
40    M::Service: HttpService,
41    T: Clone + Send,
42{
43    type Error = M::MakeError;
44    type Service = M::Service;
45
46    async fn new_service(&mut self, _remote_addr: SocketAddr) -> Result<Self::Service, Self::Error> {
47        // wait for the service to be ready
48        futures::future::poll_fn(|cx| self.make_service.poll_ready(cx)).await?;
49
50        self.make_service.make_service(self.target.clone()).await
51    }
52}
53
54/// A [`HttpServiceFactory`] that wraps a [`tower::MakeService`](https://docs.rs/tower/latest/tower/trait.MakeService.html) that takes a [`SocketAddr`] as input.
55///
56/// Can be used with [`axum::Router::into_make_service_with_connect_info`](https://docs.rs/axum/latest/axum/struct.Router.html#method.into_make_service_with_connect_info).
57#[derive(Clone, Debug)]
58pub struct TowerMakeServiceWithAddrFactory<M>(M);
59
60/// Create a [`TowerMakeServiceWithAddrFactory`] from a given [`tower::MakeService`](https://docs.rs/tower/latest/tower/trait.MakeService.html).
61///
62/// See [`TowerMakeServiceFactory`] for details.
63pub fn tower_make_service_with_addr_factory<M>(make_service: M) -> TowerMakeServiceWithAddrFactory<M> {
64    TowerMakeServiceWithAddrFactory(make_service)
65}
66
67impl<M> HttpServiceFactory for TowerMakeServiceWithAddrFactory<M>
68where
69    M: tower::MakeService<SocketAddr, IncomingRequest> + Send,
70    M::Future: Send,
71    M::Service: HttpService,
72{
73    type Error = M::MakeError;
74    type Service = M::Service;
75
76    async fn new_service(&mut self, remote_addr: SocketAddr) -> Result<Self::Service, Self::Error> {
77        // wait for the service to be ready
78        futures::future::poll_fn(|cx| self.0.poll_ready(cx)).await?;
79
80        self.0.make_service(remote_addr).await
81    }
82}