1#[cfg(test)]
64mod tests;
65
66use std::future::Future;
67use std::pin::Pin;
68use std::sync::Arc;
69
70use crate::app::App;
71use crate::application::Application;
72use crate::core::New;
73use crate::request::Request;
74use crate::response::Response;
75use crate::router::matcher::{self, Segment};
76use crate::router::PathParams;
77use crate::server::ConnectionInfo;
78#[cfg(feature = "openapi")]
79use crate::mime_type::MimeType;
80#[cfg(feature = "openapi")]
81use crate::range::Range;
82#[cfg(feature = "openapi")]
83use crate::response::STATUS_CODE_REASON_PHRASE;
84
85type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
86
87type AsyncHandlerFn<S> = Arc<
88 dyn Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> BoxFuture<Response> + Send + Sync,
89>;
90
91#[derive(Clone)]
94struct AsyncRoute<S> {
95 method: String,
96 segments: Vec<Segment>,
97 handler: AsyncHandlerFn<S>,
98}
99
100#[derive(Clone)]
108pub struct AsyncAppWithState<S> {
109 state: Arc<S>,
110 routes: Vec<AsyncRoute<S>>,
111 config: Option<Arc<crate::server_config::ServerConfig>>,
116}
117
118impl<S: Send + Sync + 'static> AsyncAppWithState<S> {
119 pub fn new(state: S) -> Self {
121 AsyncAppWithState { state: Arc::new(state), routes: Vec::new(), config: None }
122 }
123
124 pub fn with_config(mut self, config: crate::server_config::ServerConfig) -> Self {
130 self.config = Some(Arc::new(config));
131 self
132 }
133
134 pub fn state(&self) -> &S {
136 &self.state
137 }
138
139 pub fn route_entries(&self) -> Vec<crate::router::RouteInfo> {
141 self.routes
142 .iter()
143 .map(|r| crate::router::RouteInfo {
144 method: r.method.clone(),
145 pattern: matcher::segments_to_pattern(&r.segments),
146 })
147 .collect()
148 }
149
150 fn fallback_app(&self) -> App {
154 match &self.config {
155 Some(c) => App::with_config((**c).clone()),
156 None => App::new(),
157 }
158 }
159
160 fn add<F, Fut>(mut self, method: &str, pattern: &str, handler: F) -> Self
161 where
162 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
163 Fut: Future<Output = Response> + Send + 'static,
164 {
165 self.routes.push(AsyncRoute {
166 method: method.to_string(),
167 segments: matcher::parse_pattern(pattern),
168 handler: Arc::new(move |req, params, conn, state| Box::pin(handler(req, params, conn, state))),
169 });
170 if let Some((last, earlier)) = self.routes.split_last() {
171 let earlier = earlier.iter().map(|r| (r.method.as_str(), r.segments.as_slice()));
172 if let Some(conflict) = crate::router::conflict_with(earlier, &last.method, &last.segments) {
173 conflict.warn_once();
174 }
175 }
176 self
177 }
178
179 pub fn route_conflicts(&self) -> Vec<crate::router::RouteConflict> {
184 crate::router::conflicts(self.routes.iter().map(|r| (r.method.as_str(), r.segments.as_slice())))
185 }
186
187 pub fn route<H: crate::handler::AsyncHandler<S>>(self, handler: H) -> Self {
200 let handler = Arc::new(handler);
201 self.add(H::METHOD, H::PATTERN, move |request, params, connection, state| {
202 handler.handle_async(request, params, connection, state)
203 })
204 }
205
206 pub fn group(mut self, prefix: &str, build: impl FnOnce(crate::group::AsyncGroup<S>) -> crate::group::AsyncGroup<S>) -> Self {
209 for route in build(crate::group::AsyncGroup::new(prefix)).finish() {
210 self = self.add_group_route(route);
211 }
212 self
213 }
214
215 pub fn resource(mut self, path: &str, build: impl FnOnce(crate::group::AsyncResource<S>) -> crate::group::AsyncResource<S>) -> Self {
218 for route in crate::group::AsyncGroup::new("").resource(path, build).finish() {
219 self = self.add_group_route(route);
220 }
221 self
222 }
223
224 pub fn name(self, name: &str) -> Self {
227 if let Some(route) = self.routes.last() {
228 crate::router::name_route(name, &matcher::segments_to_pattern(&route.segments));
229 }
230 self
231 }
232
233 fn add_group_route(self, route: crate::group::GroupRoute<crate::group::AsyncHandlerFn<S>>) -> Self {
234 if let Some(name) = &route.name {
235 crate::router::name_route(name, &route.pattern);
236 }
237 let handler = route.handler;
238 self.add(route.method, &route.pattern, move |request, params, connection, state| handler(request, params, connection, state))
239 }
240
241 pub fn wrap<M: crate::middleware::Middleware + 'static>(self, layer: M) -> crate::middleware::WithMiddleware<AsyncAppWithState<S>> {
245 crate::middleware::WithMiddleware::new(self).wrap(layer)
246 }
247
248 pub fn get<F, Fut>(self, pattern: &str, handler: F) -> Self
250 where
251 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
252 Fut: Future<Output = Response> + Send + 'static,
253 {
254 self.add("GET", pattern, handler)
255 }
256
257 pub fn post<F, Fut>(self, pattern: &str, handler: F) -> Self
259 where
260 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
261 Fut: Future<Output = Response> + Send + 'static,
262 {
263 self.add("POST", pattern, handler)
264 }
265
266 pub fn put<F, Fut>(self, pattern: &str, handler: F) -> Self
268 where
269 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
270 Fut: Future<Output = Response> + Send + 'static,
271 {
272 self.add("PUT", pattern, handler)
273 }
274
275 pub fn patch<F, Fut>(self, pattern: &str, handler: F) -> Self
277 where
278 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
279 Fut: Future<Output = Response> + Send + 'static,
280 {
281 self.add("PATCH", pattern, handler)
282 }
283
284 pub fn delete<F, Fut>(self, pattern: &str, handler: F) -> Self
286 where
287 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
288 Fut: Future<Output = Response> + Send + 'static,
289 {
290 self.add("DELETE", pattern, handler)
291 }
292
293 #[cfg(feature = "openapi")]
304 pub fn openapi(self, config: crate::openapi::OpenApiConfig) -> Self {
305 let spec_json = Arc::new(crate::openapi::build_spec(&config, &self.route_entries()));
306 let html = Arc::new(crate::openapi::swagger_ui_html("/openapi.json"));
307
308 let spec_for_route = Arc::clone(&spec_json);
309 self.get("/openapi.json", move |_req, _params, _conn, _state| {
310 let spec_for_route = Arc::clone(&spec_for_route);
311 async move {
312 let mut r = Response::new();
313 r.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
314 r.reason_phrase = STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
315 r.content_range_list = vec![Range::get_content_range(
316 spec_for_route.as_bytes().to_vec(),
317 MimeType::APPLICATION_JSON.to_string(),
318 )];
319 r
320 }
321 })
322 .get("/docs", move |_req, _params, _conn, _state| {
323 let html = Arc::clone(&html);
324 async move {
325 let mut r = Response::new();
326 r.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
327 r.reason_phrase = STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
328 r.content_range_list = vec![Range::get_content_range(
329 html.as_bytes().to_vec(),
330 MimeType::TEXT_HTML.to_string(),
331 )];
332 r
333 }
334 })
335 }
336
337 fn dispatch(&self, request: &Request, connection: &ConnectionInfo) -> Option<BoxFuture<Response>> {
339 let path = request.request_uri.split('?').next().unwrap_or(&request.request_uri);
340 let path_segs: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
341
342 for route in &self.routes {
343 if route.method != request.method {
344 continue;
345 }
346 if let Some(params_map) = matcher::try_match(&route.segments, &path_segs) {
347 let params = PathParams::from_map(params_map);
348 return Some((route.handler)(request.clone(), params, connection.clone(), Arc::clone(&self.state)));
349 }
350 }
351 None
352 }
353
354 pub(crate) async fn respond(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String> {
357 match self.dispatch(request, connection) {
358 Some(handler) => Ok(crate::async_bridge::run_async(handler).await),
359 None => self.fallback_app().execute(request, connection),
360 }
361 }
362}
363
364impl<S: Send + Sync + 'static> Application for AsyncAppWithState<S> {
365 fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String> {
368 match self.dispatch(request, connection) {
369 Some(handler) => Ok(crate::async_bridge::block_on_shared(handler)),
370 None => self.fallback_app().execute(request, connection),
371 }
372 }
373
374 fn execute_async<'a>(&'a self, request: &'a Request, connection: &'a ConnectionInfo) -> Option<crate::application::AsyncResponse<'a>> {
377 let handler = self.dispatch(request, connection)?;
378 Some(Box::pin(async move { Ok(crate::async_bridge::run_async(handler).await) }))
379 }
380
381 fn registered_routes(&self) -> Vec<crate::router::RouteInfo> {
382 self.route_entries()
383 }
384}