scuffle_http/service/
mod.rs

1//! HTTP service and service factory traits.
2use std::future::Future;
3use std::net::SocketAddr;
4
5use crate::IncomingRequest;
6
7mod clone_factory;
8mod function;
9#[cfg(feature = "tower")]
10mod tower_factory;
11
12pub use clone_factory::*;
13pub use function::*;
14#[cfg(feature = "tower")]
15pub use tower_factory::*;
16
17/// A trait representing an HTTP service.
18///
19/// This trait must be used in combination with [`HttpServiceFactory`].
20/// It is very similar to tower's service trait and implemented
21/// for all types that implement [`tower::Service<IncomingRequest>`](https://docs.rs/tower/latest/tower/trait.Service.html).
22pub trait HttpService {
23    /// The error type that can be returned by [`call`](HttpService::call).
24    type Error;
25    /// The response body type that is returned by [`call`](HttpService::call).
26    type ResBody: http_body::Body;
27
28    /// Handle an incoming request.
29    ///
30    /// This method is called for each incoming request.
31    /// The service must return a response for the given request.
32    fn call(
33        &mut self,
34        req: IncomingRequest,
35    ) -> impl Future<Output = Result<http::Response<Self::ResBody>, Self::Error>> + Send;
36}
37
38// Implement for tower services
39#[cfg(feature = "tower")]
40impl<T, B> HttpService for T
41where
42    T: tower::Service<IncomingRequest, Response = http::Response<B>> + Send,
43    T::Future: Send,
44    B: http_body::Body,
45{
46    type Error = T::Error;
47    type ResBody = B;
48
49    async fn call(&mut self, req: IncomingRequest) -> Result<http::Response<Self::ResBody>, Self::Error> {
50        // wait for the tower service to be ready
51        futures::future::poll_fn(|cx| self.poll_ready(cx)).await?;
52
53        self.call(req).await
54    }
55}
56
57/// A trait representing an HTTP service factory.
58///
59/// This trait must be implemented by types that can create new instances of [`HttpService`].
60/// It is conceptually similar to tower's [`MakeService`](https://docs.rs/tower/latest/tower/trait.MakeService.html) trait.
61///
62/// It is intended to create a new service for each incoming connection.
63/// If you don't need to implement any custom factory logic, you can use [`ServiceCloneFactory`] to make a factory that clones the given service for each new connection.
64pub trait HttpServiceFactory {
65    /// The error type that can be returned by [`new_service`](HttpServiceFactory::new_service).
66    type Error;
67    /// The service type that is created by this factory.
68    type Service: HttpService;
69
70    /// Create a new service for a new connection.
71    ///
72    /// `remote_addr` is the address of the connecting remote peer.
73    fn new_service(&mut self, remote_addr: SocketAddr) -> impl Future<Output = Result<Self::Service, Self::Error>> + Send;
74}