1use crate::error::{Error, IntoFailure};
2use crate::io::{Filter, Io, types};
3use crate::service::{IntoServiceFactory, RequestState, pipeline::PipelineFactory};
4use crate::{Ctx, Service, ServiceFactory};
5
6use super::error::{DispatchError, H2Error, ResponseError};
7use super::{Request, Response, config::DispatcherConfig, h1, h2};
8
9#[derive(derive_more::Debug)]
16#[debug("HttpService")]
17pub struct HttpService<F, Req: RequestState<Io<F>>, Err> {
18 sf: super::HttpPipeline<Req::State, Err>,
19 h1_ctl: Option<super::Ctl1Pipeline<Req::State, F, Err>>,
21 h2_ctl: super::Ctl2Pipeline<Req::State>,
22 config: DispatcherConfig,
23}
24
25impl<F, Req, Err> HttpService<F, Req, Err>
26where
27 F: Filter + 'static,
28 Req: RequestState<Io<F>>,
29 Req::State: Clone,
30 Err: ResponseError + 'static,
31{
32 #[must_use]
33 pub fn new<H>(sf: impl IntoServiceFactory<H, Req::State, Request>) -> Self
35 where
36 H: ServiceFactory<Req::State, Request, Error = Err> + 'static,
37 H::Res: Into<Response>,
38 H::InitError: IntoFailure,
39 {
40 HttpService {
41 sf: PipelineFactory::new(
42 sf.into_factory()
43 .map(Into::into)
44 .map_init_err(|e| DispatchError::Control(e.fail())),
45 ),
46 h1_ctl: None,
47 h2_ctl: PipelineFactory::new(h2::DefaultControlService),
48 config: DispatcherConfig::default(),
49 }
50 }
51
52 #[must_use]
53 pub fn h1<H>(sf: impl IntoServiceFactory<H, Req::State, Request>) -> h1::H1Service<F, Req, Err>
55 where
56 H: ServiceFactory<Req::State, Request, Error = Err> + 'static,
57 H::Res: Into<Response>,
58 H::InitError: IntoFailure,
59 {
60 h1::H1Service::new(sf)
61 }
62
63 #[must_use]
64 pub fn h2<H>(sf: impl IntoServiceFactory<H, Req::State, Request>) -> h2::H2Service<F, Req, Err>
66 where
67 H: ServiceFactory<Req::State, Request, Error = Err> + 'static,
68 H::Res: Into<Response>,
69 H::InitError: IntoFailure,
70 {
71 h2::H2Service::new(sf)
72 }
73}
74
75impl<F, Req, Err> HttpService<F, Req, Err>
76where
77 F: Filter,
78 Req: RequestState<Io<F>>,
79 Err: ResponseError + 'static,
80{
81 #[must_use]
82 pub fn h1_control<Ctl>(
88 self,
89 ctl: impl IntoServiceFactory<Ctl, Req::State, h1::Control<F, Err>>,
90 ) -> Self
91 where
92 Ctl: ServiceFactory<Req::State, h1::Control<F, Err>, Res = h1::ControlAck<F>> + 'static,
93 Ctl::Error: IntoFailure,
94 Ctl::InitError: IntoFailure,
95 {
96 HttpService {
97 sf: self.sf,
98 h1_ctl: Some(PipelineFactory::new(
99 ctl.into_factory()
100 .map_err(|e| DispatchError::Service(e.fail()))
101 .map_init_err(|e| DispatchError::Control(e.fail())),
102 )),
103 h2_ctl: self.h2_ctl,
104 config: self.config,
105 }
106 }
107
108 #[must_use]
109 pub fn h2_control<Ctl>(
114 self,
115 ctl: impl IntoServiceFactory<Ctl, Req::State, h2::Control<Error<H2Error>>>,
116 ) -> Self
117 where
118 Ctl:
119 ServiceFactory<Req::State, h2::Control<Error<H2Error>>, Res = h2::ControlAck> + 'static,
120 Ctl::Error: IntoFailure,
121 Ctl::InitError: IntoFailure,
122 {
123 HttpService {
124 sf: self.sf,
125 h1_ctl: self.h1_ctl,
126 h2_ctl: PipelineFactory::new(
127 ctl.into_factory()
128 .map_err(|e| DispatchError::Service(e.fail()))
129 .map_init_err(|e| DispatchError::Control(e.fail())),
130 ),
131 config: self.config,
132 }
133 }
134}
135
136impl<St, F, Req, Err> Service<St, Req> for HttpService<F, Req, Err>
137where
138 F: Filter + 'static,
139 Req: RequestState<Io<F>>,
140 Req::State: Clone,
141 Err: ResponseError + 'static,
142{
143 type Res = ();
144 type Error = DispatchError;
145
146 async fn call(&self, req: Req, _: Ctx<'_, Self, St>) -> Result<Self::Res, Self::Error> {
147 let (st, io) = req.unpack();
148
149 let svc = self.sf.create(st.clone()).await?;
150
151 let id = self.config.next_id();
152 let ioref = io.get_ref();
153 let (_guard, inflight) = self.config.insert_io(&ioref);
154
155 if io.query::<types::HttpProtocol>().get() == Some(types::HttpProtocol::Http2) {
156 log::trace!(
157 "{}: New http2 connection {id}, peer address {:?}, in-flight: {inflight}",
158 io.tag(),
159 io.query::<types::PeerAddr>().get(),
160 );
161 let ctl = self.h2_ctl.create(st).await?;
162
163 h2::handle(id, io.into(), svc, ctl).await
164 } else {
165 log::trace!(
166 "{}: New http1 connection {id}, peer address {:?}, in-flight: {inflight}",
167 io.tag(),
168 io.query::<types::PeerAddr>().get(),
169 );
170 let ctl = match &self.h1_ctl {
171 Some(ctl) => Some(ctl.create(st).await?),
172 None => None,
173 };
174
175 h1::handle_io(id, io, svc, ctl, self.config.clone()).await
176 }
177 }
178
179 async fn ready(&self, _: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
180 Ok(())
181 }
182
183 async fn shutdown(&self, _: crate::Ctx<'_, Self, St>) {
184 let inflight = self.config.shutdown();
186 if inflight != 0 {
187 log::trace!("Shutting down service, in-flight connections: {inflight}");
188
189 self.config.wait_shutdown().await;
190 log::trace!("Shutting down is complected");
191 }
192 }
193}