1#[cfg(test)]
49mod tests;
50
51use std::future::Future;
52use std::pin::Pin;
53use std::sync::Arc;
54
55use crate::app::App;
56use crate::application::Application;
57use crate::core::New;
58use crate::request::Request;
59use crate::response::Response;
60use crate::router::matcher::{self, Segment};
61use crate::router::PathParams;
62use crate::server::ConnectionInfo;
63#[cfg(feature = "openapi")]
64use crate::mime_type::MimeType;
65#[cfg(feature = "openapi")]
66use crate::range::Range;
67#[cfg(feature = "openapi")]
68use crate::response::STATUS_CODE_REASON_PHRASE;
69
70type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
71
72type AsyncHandlerFn<S> = Arc<
73 dyn Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> BoxFuture<Response> + Send + Sync,
74>;
75
76#[derive(Clone)]
79struct AsyncRoute<S> {
80 method: String,
81 segments: Vec<Segment>,
82 handler: AsyncHandlerFn<S>,
83}
84
85#[derive(Clone)]
93pub struct AsyncAppWithState<S> {
94 state: Arc<S>,
95 routes: Vec<AsyncRoute<S>>,
96 config: Option<Arc<crate::server_config::ServerConfig>>,
101}
102
103impl<S: Send + Sync + 'static> AsyncAppWithState<S> {
104 pub fn new(state: S) -> Self {
106 AsyncAppWithState { state: Arc::new(state), routes: Vec::new(), config: None }
107 }
108
109 pub fn with_config(mut self, config: crate::server_config::ServerConfig) -> Self {
115 self.config = Some(Arc::new(config));
116 self
117 }
118
119 pub fn state(&self) -> &S {
121 &self.state
122 }
123
124 pub fn route_entries(&self) -> Vec<crate::router::RouteInfo> {
126 self.routes
127 .iter()
128 .map(|r| crate::router::RouteInfo {
129 method: r.method.clone(),
130 pattern: matcher::segments_to_pattern(&r.segments),
131 })
132 .collect()
133 }
134
135 fn fallback_app(&self) -> App {
139 match &self.config {
140 Some(c) => App::with_config((**c).clone()),
141 None => App::new(),
142 }
143 }
144
145 fn add<F, Fut>(mut self, method: &str, pattern: &str, handler: F) -> Self
146 where
147 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
148 Fut: Future<Output = Response> + Send + 'static,
149 {
150 self.routes.push(AsyncRoute {
151 method: method.to_string(),
152 segments: matcher::parse_pattern(pattern),
153 handler: Arc::new(move |req, params, conn, state| Box::pin(handler(req, params, conn, state))),
154 });
155 if let Some((last, earlier)) = self.routes.split_last() {
156 let earlier = earlier.iter().map(|r| (r.method.as_str(), r.segments.as_slice()));
157 if let Some(conflict) = crate::router::conflict_with(earlier, &last.method, &last.segments) {
158 conflict.warn_once();
159 }
160 }
161 self
162 }
163
164 pub fn route_conflicts(&self) -> Vec<crate::router::RouteConflict> {
169 crate::router::conflicts(self.routes.iter().map(|r| (r.method.as_str(), r.segments.as_slice())))
170 }
171
172 pub fn route<H: crate::handler::AsyncHandler<S>>(self, handler: H) -> Self {
185 let handler = Arc::new(handler);
186 self.add(H::METHOD, H::PATTERN, move |request, params, connection, state| {
187 handler.handle_async(request, params, connection, state)
188 })
189 }
190
191 pub fn get<F, Fut>(self, pattern: &str, handler: F) -> Self
193 where
194 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
195 Fut: Future<Output = Response> + Send + 'static,
196 {
197 self.add("GET", pattern, handler)
198 }
199
200 pub fn post<F, Fut>(self, pattern: &str, handler: F) -> Self
202 where
203 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
204 Fut: Future<Output = Response> + Send + 'static,
205 {
206 self.add("POST", pattern, handler)
207 }
208
209 pub fn put<F, Fut>(self, pattern: &str, handler: F) -> Self
211 where
212 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
213 Fut: Future<Output = Response> + Send + 'static,
214 {
215 self.add("PUT", pattern, handler)
216 }
217
218 pub fn patch<F, Fut>(self, pattern: &str, handler: F) -> Self
220 where
221 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
222 Fut: Future<Output = Response> + Send + 'static,
223 {
224 self.add("PATCH", pattern, handler)
225 }
226
227 pub fn delete<F, Fut>(self, pattern: &str, handler: F) -> Self
229 where
230 F: Fn(Request, PathParams, ConnectionInfo, Arc<S>) -> Fut + Send + Sync + 'static,
231 Fut: Future<Output = Response> + Send + 'static,
232 {
233 self.add("DELETE", pattern, handler)
234 }
235
236 #[cfg(feature = "openapi")]
247 pub fn openapi(self, config: crate::openapi::OpenApiConfig) -> Self {
248 let spec_json = Arc::new(crate::openapi::build_spec(&config, &self.route_entries()));
249 let html = Arc::new(crate::openapi::swagger_ui_html("/openapi.json"));
250
251 let spec_for_route = Arc::clone(&spec_json);
252 self.get("/openapi.json", move |_req, _params, _conn, _state| {
253 let spec_for_route = Arc::clone(&spec_for_route);
254 async move {
255 let mut r = Response::new();
256 r.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
257 r.reason_phrase = STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
258 r.content_range_list = vec![Range::get_content_range(
259 spec_for_route.as_bytes().to_vec(),
260 MimeType::APPLICATION_JSON.to_string(),
261 )];
262 r
263 }
264 })
265 .get("/docs", move |_req, _params, _conn, _state| {
266 let html = Arc::clone(&html);
267 async move {
268 let mut r = Response::new();
269 r.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
270 r.reason_phrase = STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
271 r.content_range_list = vec![Range::get_content_range(
272 html.as_bytes().to_vec(),
273 MimeType::TEXT_HTML.to_string(),
274 )];
275 r
276 }
277 })
278 }
279
280 async fn execute_async(
281 &self,
282 request: &Request,
283 connection: &ConnectionInfo,
284 ) -> Result<Response, String> {
285 let path = request.request_uri.split('?').next().unwrap_or(&request.request_uri);
286 let path_segs: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
287
288 for route in &self.routes {
289 if route.method != request.method {
290 continue;
291 }
292 if let Some(params_map) = matcher::try_match(&route.segments, &path_segs) {
293 let params = PathParams::from_map(params_map);
294 let fut = (route.handler)(
295 request.clone(),
296 params,
297 connection.clone(),
298 Arc::clone(&self.state),
299 );
300 return Ok(fut.await);
301 }
302 }
303
304 self.fallback_app().execute(request, connection)
305 }
306}
307
308impl<S: Send + Sync + 'static> Application for AsyncAppWithState<S> {
309 fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String> {
310 let request = request.clone();
311 let connection = connection.clone();
312 crate::async_bridge::block_on_isolated(|| self.execute_async(&request, &connection))
313 }
314
315 fn registered_routes(&self) -> Vec<crate::router::RouteInfo> {
316 self.route_entries()
317 }
318}