r1_api_layer/server/
mod.rs

1use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt};
2use hyper::{Request, Response, StatusCode, Body, HeaderMap};
3use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
4use log::warn;
5#[allow(unused_imports)]
6use std::convert::{TryFrom, TryInto};
7use std::error::Error;
8use std::future::Future;
9use std::marker::PhantomData;
10use std::task::{Context, Poll};
11use swagger::{ApiError, BodyExt, Has, RequestParser, XSpanIdString};
12pub use swagger::auth::Authorization;
13use swagger::auth::Scopes;
14use url::form_urlencoded;
15
16#[allow(unused_imports)]
17use crate::{models, header, AuthenticationApi};
18
19pub use crate::context;
20
21type ServiceFuture = BoxFuture<'static, Result<Response<Body>, crate::ServiceError>>;
22
23use crate::{Api,
24     BobbyDeleteResponse,
25     GamePostResponse,
26     MapsGetResponse,
27     RegisterPostResponse,
28     StatisticsGetResponse,
29     MapLevelGetResponse,
30     StatisticsUuidGetResponse,
31     UserUuidGetResponse
32};
33
34mod server_auth;
35
36mod paths {
37    use lazy_static::lazy_static;
38
39    lazy_static! {
40        pub static ref GLOBAL_REGEX_SET: regex::RegexSet = regex::RegexSet::new(vec![
41            r"^/bobby$",
42            r"^/game$",
43            r"^/map/(?P<level>[^/?#]*)$",
44            r"^/maps$",
45            r"^/register$",
46            r"^/statistics$",
47            r"^/statistics/(?P<UUID>[^/?#]*)$",
48            r"^/user/(?P<UUID>[^/?#]*)$"
49        ])
50        .expect("Unable to create global regex set");
51    }
52    pub(crate) static ID_BOBBY: usize = 0;
53    pub(crate) static ID_GAME: usize = 1;
54    pub(crate) static ID_MAP_LEVEL: usize = 2;
55    lazy_static! {
56        pub static ref REGEX_MAP_LEVEL: regex::Regex =
57            #[allow(clippy::invalid_regex)]
58            regex::Regex::new(r"^/map/(?P<level>[^/?#]*)$")
59                .expect("Unable to create regex for MAP_LEVEL");
60    }
61    pub(crate) static ID_MAPS: usize = 3;
62    pub(crate) static ID_REGISTER: usize = 4;
63    pub(crate) static ID_STATISTICS: usize = 5;
64    pub(crate) static ID_STATISTICS_UUID: usize = 6;
65    lazy_static! {
66        pub static ref REGEX_STATISTICS_UUID: regex::Regex =
67            #[allow(clippy::invalid_regex)]
68            regex::Regex::new(r"^/statistics/(?P<UUID>[^/?#]*)$")
69                .expect("Unable to create regex for STATISTICS_UUID");
70    }
71    pub(crate) static ID_USER_UUID: usize = 7;
72    lazy_static! {
73        pub static ref REGEX_USER_UUID: regex::Regex =
74            #[allow(clippy::invalid_regex)]
75            regex::Regex::new(r"^/user/(?P<UUID>[^/?#]*)$")
76                .expect("Unable to create regex for USER_UUID");
77    }
78}
79
80
81pub struct MakeService<T, C> where
82    T: Api<C> + Clone + Send + 'static,
83    C: Has<XSpanIdString>  + Send + Sync + 'static
84{
85    api_impl: T,
86    marker: PhantomData<C>,
87}
88
89impl<T, C> MakeService<T, C> where
90    T: Api<C> + Clone + Send + 'static,
91    C: Has<XSpanIdString>  + Send + Sync + 'static
92{
93    pub fn new(api_impl: T) -> Self {
94        MakeService {
95            api_impl,
96            marker: PhantomData
97        }
98    }
99}
100
101impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
102    T: Api<C> + Clone + Send + 'static,
103    C: Has<XSpanIdString>  + Send + Sync + 'static
104{
105    type Response = Service<T, C>;
106    type Error = crate::ServiceError;
107    type Future = future::Ready<Result<Self::Response, Self::Error>>;
108
109    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
110        Poll::Ready(Ok(()))
111    }
112
113    fn call(&mut self, target: Target) -> Self::Future {
114        let service = Service::new(self.api_impl.clone());
115
116        future::ok(service)
117    }
118}
119
120fn method_not_allowed() -> Result<Response<Body>, crate::ServiceError> {
121    Ok(
122        Response::builder().status(StatusCode::METHOD_NOT_ALLOWED)
123            .body(Body::empty())
124            .expect("Unable to create Method Not Allowed response")
125    )
126}
127
128pub struct Service<T, C> where
129    T: Api<C> + Clone + Send + 'static,
130    C: Has<XSpanIdString>  + Send + Sync + 'static
131{
132    api_impl: T,
133    marker: PhantomData<C>,
134}
135
136impl<T, C> Service<T, C> where
137    T: Api<C> + Clone + Send + 'static,
138    C: Has<XSpanIdString>  + Send + Sync + 'static
139{
140    pub fn new(api_impl: T) -> Self {
141        Service {
142            api_impl,
143            marker: PhantomData
144        }
145    }
146}
147
148impl<T, C> Clone for Service<T, C> where
149    T: Api<C> + Clone + Send + 'static,
150    C: Has<XSpanIdString>  + Send + Sync + 'static
151{
152    fn clone(&self) -> Self {
153        Service {
154            api_impl: self.api_impl.clone(),
155            marker: self.marker,
156        }
157    }
158}
159
160impl<T, C> hyper::service::Service<(Request<Body>, C)> for Service<T, C> where
161    T: Api<C> + Clone + Send + Sync + 'static,
162    C: Has<XSpanIdString>  + Send + Sync + 'static
163{
164    type Response = Response<Body>;
165    type Error = crate::ServiceError;
166    type Future = ServiceFuture;
167
168    fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
169        self.api_impl.poll_ready(cx)
170    }
171
172    fn call(&mut self, req: (Request<Body>, C)) -> Self::Future {
173        async fn run<T, C>(
174            mut api_impl: T,
175            req: (Request<Body>, C),
176        ) -> Result<Response<Body>, crate::ServiceError> where
177            T: Api<C> + Clone + Send + 'static,
178            C: Has<XSpanIdString>  + Send + Sync + 'static
179        {
180            let (request, context) = req;
181            let (parts, body) = request.into_parts();
182            let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
183            let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
184
185            match method {
186
187            // BobbyDelete - DELETE /bobby
188            hyper::Method::DELETE if path.matched(paths::ID_BOBBY) => {
189                                let result = api_impl.bobby_delete(
190                                        &context
191                                    ).await;
192                                let mut response = Response::new(Body::empty());
193                                response.headers_mut().insert(
194                                            HeaderName::from_static("x-span-id"),
195                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().as_str())
196                                                .expect("Unable to create X-Span-ID header value"));
197
198                                        match result {
199                                            Ok(rsp) => match rsp {
200                                                BobbyDeleteResponse::DroppedAllData
201                                                => {
202                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
203
204                                                },
205                                                BobbyDeleteResponse::WrongPassphraseProvided
206                                                => {
207                                                    *response.status_mut() = StatusCode::from_u16(409).expect("Unable to turn 409 into a StatusCode");
208
209                                                },
210                                            },
211                                            Err(_) => {
212                                                // Application code returned an error. This should not happen, as the implementation should
213                                                // return a valid response.
214                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
215                                                *response.body_mut() = Body::from("An internal error occurred");
216                                            },
217                                        }
218
219                                        Ok(response)
220            },
221
222            // GamePost - POST /game
223            hyper::Method::POST if path.matched(paths::ID_GAME) => {
224                // Handle body parameters (note that non-required body parameters will ignore garbage
225                // values, rather than causing a 400 response). Produce warning header and logs for
226                // any unused fields.
227                let result = body.into_raw().await;
228                match result {
229                     Ok(body) => {
230                                let mut unused_elements : Vec<String> = vec![];
231                                let param_game_end_dto: Option<models::GameEndDto> = if !body.is_empty() {
232                                    let deserializer = &mut serde_json::Deserializer::from_slice(&*body);
233                                    match serde_ignored::deserialize(deserializer, |path| {
234                                            warn!("Ignoring unknown field in body: {}", path);
235                                            unused_elements.push(path.to_string());
236                                    }) {
237                                        Ok(param_game_end_dto) => param_game_end_dto,
238                                        Err(e) => return Ok(Response::builder()
239                                                        .status(StatusCode::BAD_REQUEST)
240                                                        .body(Body::from(format!("Couldn't parse body parameter GameEndDto - doesn't match schema: {}", e)))
241                                                        .expect("Unable to create Bad Request response for invalid body parameter GameEndDto due to schema")),
242                                    }
243                                } else {
244                                    None
245                                };
246                                let param_game_end_dto = match param_game_end_dto {
247                                    Some(param_game_end_dto) => param_game_end_dto,
248                                    None => return Ok(Response::builder()
249                                                        .status(StatusCode::BAD_REQUEST)
250                                                        .body(Body::from("Missing required body parameter GameEndDto"))
251                                                        .expect("Unable to create Bad Request response for missing body parameter GameEndDto")),
252                                };
253
254
255                                let result = api_impl.game_post(
256                                            param_game_end_dto,
257                                        &context
258                                    ).await;
259                                let mut response = Response::new(Body::empty());
260                                response.headers_mut().insert(
261                                            HeaderName::from_static("x-span-id"),
262                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().as_str())
263                                                .expect("Unable to create X-Span-ID header value"));
264
265                                        if !unused_elements.is_empty() {
266                                            response.headers_mut().insert(
267                                                HeaderName::from_static("warning"),
268                                                HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str())
269                                                    .expect("Unable to create Warning header value"));
270                                        }
271                                        match result {
272                                            Ok(rsp) => match rsp {
273                                                GamePostResponse::GameResultDetails
274                                                    (body)
275                                                => {
276                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
277                                                    response.headers_mut().insert(
278                                                        CONTENT_TYPE,
279                                                        HeaderValue::from_str("application/json")
280                                                            .expect("Unable to create Content-Type header for application/json"));
281                                                    // JSON Body
282                                                    let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
283                                                    *response.body_mut() = Body::from(body);
284
285                                                },
286                                            },
287                                            Err(_) => {
288                                                // Application code returned an error. This should not happen, as the implementation should
289                                                // return a valid response.
290                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
291                                                *response.body_mut() = Body::from("An internal error occurred");
292                                            },
293                                        }
294
295                                        Ok(response)
296                            },
297                            Err(e) => Ok(Response::builder()
298                                                .status(StatusCode::BAD_REQUEST)
299                                                .body(Body::from(format!("Unable to read body: {}", e)))
300                                                .expect("Unable to create Bad Request response due to unable to read body")),
301                        }
302            },
303
304            // MapsGet - GET /maps
305            hyper::Method::GET if path.matched(paths::ID_MAPS) => {
306                                let result = api_impl.maps_get(
307                                        &context
308                                    ).await;
309                                let mut response = Response::new(Body::empty());
310                                response.headers_mut().insert(
311                                            HeaderName::from_static("x-span-id"),
312                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().as_str())
313                                                .expect("Unable to create X-Span-ID header value"));
314
315                                        match result {
316                                            Ok(rsp) => match rsp {
317                                                MapsGetResponse::ListOfTheIdsOfAllExistingMaps
318                                                    (body)
319                                                => {
320                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
321                                                    response.headers_mut().insert(
322                                                        CONTENT_TYPE,
323                                                        HeaderValue::from_str("application/json")
324                                                            .expect("Unable to create Content-Type header for application/json"));
325                                                    // JSON Body
326                                                    let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
327                                                    *response.body_mut() = Body::from(body);
328
329                                                },
330                                                MapsGetResponse::NoMapsInDatabase
331                                                => {
332                                                    *response.status_mut() = StatusCode::from_u16(500).expect("Unable to turn 500 into a StatusCode");
333
334                                                },
335                                            },
336                                            Err(_) => {
337                                                // Application code returned an error. This should not happen, as the implementation should
338                                                // return a valid response.
339                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
340                                                *response.body_mut() = Body::from("An internal error occurred");
341                                            },
342                                        }
343
344                                        Ok(response)
345            },
346
347            // RegisterPost - POST /register
348            hyper::Method::POST if path.matched(paths::ID_REGISTER) => {
349                // Handle body parameters (note that non-required body parameters will ignore garbage
350                // values, rather than causing a 400 response). Produce warning header and logs for
351                // any unused fields.
352                let result = body.into_raw().await;
353                match result {
354                     Ok(body) => {
355                                let mut unused_elements : Vec<String> = vec![];
356                                let param_create_user_dto: Option<models::CreateUserDto> = if !body.is_empty() {
357                                    let deserializer = &mut serde_json::Deserializer::from_slice(&*body);
358                                    match serde_ignored::deserialize(deserializer, |path| {
359                                            warn!("Ignoring unknown field in body: {}", path);
360                                            unused_elements.push(path.to_string());
361                                    }) {
362                                        Ok(param_create_user_dto) => param_create_user_dto,
363                                        Err(e) => return Ok(Response::builder()
364                                                        .status(StatusCode::BAD_REQUEST)
365                                                        .body(Body::from(format!("Couldn't parse body parameter CreateUserDto - doesn't match schema: {}", e)))
366                                                        .expect("Unable to create Bad Request response for invalid body parameter CreateUserDto due to schema")),
367                                    }
368                                } else {
369                                    None
370                                };
371                                let param_create_user_dto = match param_create_user_dto {
372                                    Some(param_create_user_dto) => param_create_user_dto,
373                                    None => return Ok(Response::builder()
374                                                        .status(StatusCode::BAD_REQUEST)
375                                                        .body(Body::from("Missing required body parameter CreateUserDto"))
376                                                        .expect("Unable to create Bad Request response for missing body parameter CreateUserDto")),
377                                };
378
379
380                                let result = api_impl.register_post(
381                                            param_create_user_dto,
382                                        &context
383                                    ).await;
384                                let mut response = Response::new(Body::empty());
385                                response.headers_mut().insert(
386                                            HeaderName::from_static("x-span-id"),
387                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().as_str())
388                                                .expect("Unable to create X-Span-ID header value"));
389
390                                        if !unused_elements.is_empty() {
391                                            response.headers_mut().insert(
392                                                HeaderName::from_static("warning"),
393                                                HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str())
394                                                    .expect("Unable to create Warning header value"));
395                                        }
396                                        match result {
397                                            Ok(rsp) => match rsp {
398                                                RegisterPostResponse::Created
399                                                => {
400                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
401
402                                                },
403                                                RegisterPostResponse::UserWithThatIDDoesAlreadyExist
404                                                => {
405                                                    *response.status_mut() = StatusCode::from_u16(409).expect("Unable to turn 409 into a StatusCode");
406
407                                                },
408                                            },
409                                            Err(_) => {
410                                                // Application code returned an error. This should not happen, as the implementation should
411                                                // return a valid response.
412                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
413                                                *response.body_mut() = Body::from("An internal error occurred");
414                                            },
415                                        }
416
417                                        Ok(response)
418                            },
419                            Err(e) => Ok(Response::builder()
420                                                .status(StatusCode::BAD_REQUEST)
421                                                .body(Body::from(format!("Unable to read body: {}", e)))
422                                                .expect("Unable to create Bad Request response due to unable to read body")),
423                        }
424            },
425
426            // StatisticsGet - GET /statistics
427            hyper::Method::GET if path.matched(paths::ID_STATISTICS) => {
428                                let result = api_impl.statistics_get(
429                                        &context
430                                    ).await;
431                                let mut response = Response::new(Body::empty());
432                                response.headers_mut().insert(
433                                            HeaderName::from_static("x-span-id"),
434                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().as_str())
435                                                .expect("Unable to create X-Span-ID header value"));
436
437                                        match result {
438                                            Ok(rsp) => match rsp {
439                                                StatisticsGetResponse::GameResultDetails
440                                                    (body)
441                                                => {
442                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
443                                                    response.headers_mut().insert(
444                                                        CONTENT_TYPE,
445                                                        HeaderValue::from_str("application/json")
446                                                            .expect("Unable to create Content-Type header for application/json"));
447                                                    // JSON Body
448                                                    let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
449                                                    *response.body_mut() = Body::from(body);
450
451                                                },
452                                            },
453                                            Err(_) => {
454                                                // Application code returned an error. This should not happen, as the implementation should
455                                                // return a valid response.
456                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
457                                                *response.body_mut() = Body::from("An internal error occurred");
458                                            },
459                                        }
460
461                                        Ok(response)
462            },
463
464            // MapLevelGet - GET /map/{level}
465            hyper::Method::GET if path.matched(paths::ID_MAP_LEVEL) => {
466                // Path parameters
467                let path: &str = uri.path();
468                let path_params =
469                    paths::REGEX_MAP_LEVEL
470                    .captures(path)
471                    .unwrap_or_else(||
472                        panic!("Path {} matched RE MAP_LEVEL in set but failed match against \"{}\"", path, paths::REGEX_MAP_LEVEL.as_str())
473                    );
474
475                let param_level = match percent_encoding::percent_decode(path_params["level"].as_bytes()).decode_utf8() {
476                    Ok(param_level) => match param_level.parse::<String>() {
477                        Ok(param_level) => param_level,
478                        Err(e) => return Ok(Response::builder()
479                                        .status(StatusCode::BAD_REQUEST)
480                                        .body(Body::from(format!("Couldn't parse path parameter level: {}", e)))
481                                        .expect("Unable to create Bad Request response for invalid path parameter")),
482                    },
483                    Err(_) => return Ok(Response::builder()
484                                        .status(StatusCode::BAD_REQUEST)
485                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["level"])))
486                                        .expect("Unable to create Bad Request response for invalid percent decode"))
487                };
488
489                                let result = api_impl.map_level_get(
490                                            param_level,
491                                        &context
492                                    ).await;
493                                let mut response = Response::new(Body::empty());
494                                response.headers_mut().insert(
495                                            HeaderName::from_static("x-span-id"),
496                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().as_str())
497                                                .expect("Unable to create X-Span-ID header value"));
498
499                                        match result {
500                                            Ok(rsp) => match rsp {
501                                                MapLevelGetResponse::BeatMap
502                                                    (body)
503                                                => {
504                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
505                                                    response.headers_mut().insert(
506                                                        CONTENT_TYPE,
507                                                        HeaderValue::from_str("application/json")
508                                                            .expect("Unable to create Content-Type header for application/json"));
509                                                    // JSON Body
510                                                    let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
511                                                    *response.body_mut() = Body::from(body);
512
513                                                },
514                                                MapLevelGetResponse::ThisMapDoesNotExist
515                                                => {
516                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
517
518                                                },
519                                            },
520                                            Err(_) => {
521                                                // Application code returned an error. This should not happen, as the implementation should
522                                                // return a valid response.
523                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
524                                                *response.body_mut() = Body::from("An internal error occurred");
525                                            },
526                                        }
527
528                                        Ok(response)
529            },
530
531            // StatisticsUuidGet - GET /statistics/{UUID}
532            hyper::Method::GET if path.matched(paths::ID_STATISTICS_UUID) => {
533                // Path parameters
534                let path: &str = uri.path();
535                let path_params =
536                    paths::REGEX_STATISTICS_UUID
537                    .captures(path)
538                    .unwrap_or_else(||
539                        panic!("Path {} matched RE STATISTICS_UUID in set but failed match against \"{}\"", path, paths::REGEX_STATISTICS_UUID.as_str())
540                    );
541
542                let param_uuid = match percent_encoding::percent_decode(path_params["UUID"].as_bytes()).decode_utf8() {
543                    Ok(param_uuid) => match param_uuid.parse::<String>() {
544                        Ok(param_uuid) => param_uuid,
545                        Err(e) => return Ok(Response::builder()
546                                        .status(StatusCode::BAD_REQUEST)
547                                        .body(Body::from(format!("Couldn't parse path parameter UUID: {}", e)))
548                                        .expect("Unable to create Bad Request response for invalid path parameter")),
549                    },
550                    Err(_) => return Ok(Response::builder()
551                                        .status(StatusCode::BAD_REQUEST)
552                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["UUID"])))
553                                        .expect("Unable to create Bad Request response for invalid percent decode"))
554                };
555
556                                let result = api_impl.statistics_uuid_get(
557                                            param_uuid,
558                                        &context
559                                    ).await;
560                                let mut response = Response::new(Body::empty());
561                                response.headers_mut().insert(
562                                            HeaderName::from_static("x-span-id"),
563                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().as_str())
564                                                .expect("Unable to create X-Span-ID header value"));
565
566                                        match result {
567                                            Ok(rsp) => match rsp {
568                                                StatisticsUuidGetResponse::GameResultDetails
569                                                    (body)
570                                                => {
571                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
572                                                    response.headers_mut().insert(
573                                                        CONTENT_TYPE,
574                                                        HeaderValue::from_str("application/json")
575                                                            .expect("Unable to create Content-Type header for application/json"));
576                                                    // JSON Body
577                                                    let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
578                                                    *response.body_mut() = Body::from(body);
579
580                                                },
581                                                StatisticsUuidGetResponse::ThisStatisticDoesNotExist
582                                                => {
583                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
584
585                                                },
586                                            },
587                                            Err(_) => {
588                                                // Application code returned an error. This should not happen, as the implementation should
589                                                // return a valid response.
590                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
591                                                *response.body_mut() = Body::from("An internal error occurred");
592                                            },
593                                        }
594
595                                        Ok(response)
596            },
597
598            // UserUuidGet - GET /user/{UUID}
599            hyper::Method::GET if path.matched(paths::ID_USER_UUID) => {
600                // Path parameters
601                let path: &str = uri.path();
602                let path_params =
603                    paths::REGEX_USER_UUID
604                    .captures(path)
605                    .unwrap_or_else(||
606                        panic!("Path {} matched RE USER_UUID in set but failed match against \"{}\"", path, paths::REGEX_USER_UUID.as_str())
607                    );
608
609                let param_uuid = match percent_encoding::percent_decode(path_params["UUID"].as_bytes()).decode_utf8() {
610                    Ok(param_uuid) => match param_uuid.parse::<String>() {
611                        Ok(param_uuid) => param_uuid,
612                        Err(e) => return Ok(Response::builder()
613                                        .status(StatusCode::BAD_REQUEST)
614                                        .body(Body::from(format!("Couldn't parse path parameter UUID: {}", e)))
615                                        .expect("Unable to create Bad Request response for invalid path parameter")),
616                    },
617                    Err(_) => return Ok(Response::builder()
618                                        .status(StatusCode::BAD_REQUEST)
619                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["UUID"])))
620                                        .expect("Unable to create Bad Request response for invalid percent decode"))
621                };
622
623                                let result = api_impl.user_uuid_get(
624                                            param_uuid,
625                                        &context
626                                    ).await;
627                                let mut response = Response::new(Body::empty());
628                                response.headers_mut().insert(
629                                            HeaderName::from_static("x-span-id"),
630                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().as_str())
631                                                .expect("Unable to create X-Span-ID header value"));
632
633                                        match result {
634                                            Ok(rsp) => match rsp {
635                                                UserUuidGetResponse::SuccessfullyFetchedUserData
636                                                    (body)
637                                                => {
638                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
639                                                    response.headers_mut().insert(
640                                                        CONTENT_TYPE,
641                                                        HeaderValue::from_str("application/json")
642                                                            .expect("Unable to create Content-Type header for application/json"));
643                                                    // JSON Body
644                                                    let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
645                                                    *response.body_mut() = Body::from(body);
646
647                                                },
648                                                UserUuidGetResponse::UserWithThatIDDoesExist
649                                                => {
650                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
651
652                                                },
653                                            },
654                                            Err(_) => {
655                                                // Application code returned an error. This should not happen, as the implementation should
656                                                // return a valid response.
657                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
658                                                *response.body_mut() = Body::from("An internal error occurred");
659                                            },
660                                        }
661
662                                        Ok(response)
663            },
664
665            _ if path.matched(paths::ID_BOBBY) => method_not_allowed(),
666            _ if path.matched(paths::ID_GAME) => method_not_allowed(),
667            _ if path.matched(paths::ID_MAP_LEVEL) => method_not_allowed(),
668            _ if path.matched(paths::ID_MAPS) => method_not_allowed(),
669            _ if path.matched(paths::ID_REGISTER) => method_not_allowed(),
670            _ if path.matched(paths::ID_STATISTICS) => method_not_allowed(),
671            _ if path.matched(paths::ID_STATISTICS_UUID) => method_not_allowed(),
672            _ if path.matched(paths::ID_USER_UUID) => method_not_allowed(),
673                _ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
674                        .body(Body::empty())
675                        .expect("Unable to create Not Found response"))
676            }
677        }
678        Box::pin(run(
679            self.api_impl.clone(),
680            req,
681        ))
682    }
683}
684
685/// Request parser for `Api`.
686pub struct ApiRequestParser;
687impl<T> RequestParser<T> for ApiRequestParser {
688    fn parse_operation_id(request: &Request<T>) -> Option<&'static str> {
689        let path = paths::GLOBAL_REGEX_SET.matches(request.uri().path());
690        match *request.method() {
691            // BobbyDelete - DELETE /bobby
692            hyper::Method::DELETE if path.matched(paths::ID_BOBBY) => Some("BobbyDelete"),
693            // GamePost - POST /game
694            hyper::Method::POST if path.matched(paths::ID_GAME) => Some("GamePost"),
695            // MapsGet - GET /maps
696            hyper::Method::GET if path.matched(paths::ID_MAPS) => Some("MapsGet"),
697            // RegisterPost - POST /register
698            hyper::Method::POST if path.matched(paths::ID_REGISTER) => Some("RegisterPost"),
699            // StatisticsGet - GET /statistics
700            hyper::Method::GET if path.matched(paths::ID_STATISTICS) => Some("StatisticsGet"),
701            // MapLevelGet - GET /map/{level}
702            hyper::Method::GET if path.matched(paths::ID_MAP_LEVEL) => Some("MapLevelGet"),
703            // StatisticsUuidGet - GET /statistics/{UUID}
704            hyper::Method::GET if path.matched(paths::ID_STATISTICS_UUID) => Some("StatisticsUuidGet"),
705            // UserUuidGet - GET /user/{UUID}
706            hyper::Method::GET if path.matched(paths::ID_USER_UUID) => Some("UserUuidGet"),
707            _ => None,
708        }
709    }
710}