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}