mbus_api/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;
18use crate::header;
19
20pub use crate::context;
21
22type ServiceFuture = BoxFuture<'static, Result<Response<Body>, crate::ServiceError>>;
23
24use crate::{Api,
25     GetResponse,
26     GetMultiResponse,
27     HatResponse,
28     HatOffResponse,
29     HatOnResponse,
30     MbusApiResponse,
31     ScanResponse
32};
33
34mod paths {
35    use lazy_static::lazy_static;
36
37    lazy_static! {
38        pub static ref GLOBAL_REGEX_SET: regex::RegexSet = regex::RegexSet::new(vec![
39            r"^/mbus/api$",
40            r"^/mbus/get/(?P<device>[^/?#]*)/(?P<baudrate>[^/?#]*)/(?P<address>[^/?#]*)$",
41            r"^/mbus/getMulti/(?P<device>[^/?#]*)/(?P<baudrate>[^/?#]*)/(?P<address>[^/?#]*)/(?P<maxframes>[^/?#]*)$",
42            r"^/mbus/hat$",
43            r"^/mbus/hat/off$",
44            r"^/mbus/hat/on$",
45            r"^/mbus/scan/(?P<device>[^/?#]*)/(?P<baudrate>[^/?#]*)$"
46        ])
47        .expect("Unable to create global regex set");
48    }
49    pub(crate) static ID_MBUS_API: usize = 0;
50    pub(crate) static ID_MBUS_GET_DEVICE_BAUDRATE_ADDRESS: usize = 1;
51    lazy_static! {
52        pub static ref REGEX_MBUS_GET_DEVICE_BAUDRATE_ADDRESS: regex::Regex =
53            regex::Regex::new(r"^/mbus/get/(?P<device>[^/?#]*)/(?P<baudrate>[^/?#]*)/(?P<address>[^/?#]*)$")
54                .expect("Unable to create regex for MBUS_GET_DEVICE_BAUDRATE_ADDRESS");
55    }
56    pub(crate) static ID_MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES: usize = 2;
57    lazy_static! {
58        pub static ref REGEX_MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES: regex::Regex =
59            regex::Regex::new(r"^/mbus/getMulti/(?P<device>[^/?#]*)/(?P<baudrate>[^/?#]*)/(?P<address>[^/?#]*)/(?P<maxframes>[^/?#]*)$")
60                .expect("Unable to create regex for MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES");
61    }
62    pub(crate) static ID_MBUS_HAT: usize = 3;
63    pub(crate) static ID_MBUS_HAT_OFF: usize = 4;
64    pub(crate) static ID_MBUS_HAT_ON: usize = 5;
65    pub(crate) static ID_MBUS_SCAN_DEVICE_BAUDRATE: usize = 6;
66    lazy_static! {
67        pub static ref REGEX_MBUS_SCAN_DEVICE_BAUDRATE: regex::Regex =
68            regex::Regex::new(r"^/mbus/scan/(?P<device>[^/?#]*)/(?P<baudrate>[^/?#]*)$")
69                .expect("Unable to create regex for MBUS_SCAN_DEVICE_BAUDRATE");
70    }
71}
72
73pub struct MakeService<T, C> where
74    T: Api<C> + Clone + Send + 'static,
75    C: Has<XSpanIdString>  + Send + Sync + 'static
76{
77    api_impl: T,
78    marker: PhantomData<C>,
79}
80
81impl<T, C> MakeService<T, C> where
82    T: Api<C> + Clone + Send + 'static,
83    C: Has<XSpanIdString>  + Send + Sync + 'static
84{
85    pub fn new(api_impl: T) -> Self {
86        MakeService {
87            api_impl,
88            marker: PhantomData
89        }
90    }
91}
92
93impl<T, C, Target> hyper::service::Service<Target> for MakeService<T, C> where
94    T: Api<C> + Clone + Send + 'static,
95    C: Has<XSpanIdString>  + Send + Sync + 'static
96{
97    type Response = Service<T, C>;
98    type Error = crate::ServiceError;
99    type Future = future::Ready<Result<Self::Response, Self::Error>>;
100
101    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
102        Poll::Ready(Ok(()))
103    }
104
105    fn call(&mut self, target: Target) -> Self::Future {
106        futures::future::ok(Service::new(
107            self.api_impl.clone(),
108        ))
109    }
110}
111
112fn method_not_allowed() -> Result<Response<Body>, crate::ServiceError> {
113    Ok(
114        Response::builder().status(StatusCode::METHOD_NOT_ALLOWED)
115            .body(Body::empty())
116            .expect("Unable to create Method Not Allowed response")
117    )
118}
119
120pub struct Service<T, C> where
121    T: Api<C> + Clone + Send + 'static,
122    C: Has<XSpanIdString>  + Send + Sync + 'static
123{
124    api_impl: T,
125    marker: PhantomData<C>,
126}
127
128impl<T, C> Service<T, C> where
129    T: Api<C> + Clone + Send + 'static,
130    C: Has<XSpanIdString>  + Send + Sync + 'static
131{
132    pub fn new(api_impl: T) -> Self {
133        Service {
134            api_impl: api_impl,
135            marker: PhantomData
136        }
137    }
138}
139
140impl<T, C> Clone for Service<T, C> where
141    T: Api<C> + Clone + Send + 'static,
142    C: Has<XSpanIdString>  + Send + Sync + 'static
143{
144    fn clone(&self) -> Self {
145        Service {
146            api_impl: self.api_impl.clone(),
147            marker: self.marker.clone(),
148        }
149    }
150}
151
152impl<T, C> hyper::service::Service<(Request<Body>, C)> for Service<T, C> where
153    T: Api<C> + Clone + Send + Sync + 'static,
154    C: Has<XSpanIdString>  + Send + Sync + 'static
155{
156    type Response = Response<Body>;
157    type Error = crate::ServiceError;
158    type Future = ServiceFuture;
159
160    fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
161        self.api_impl.poll_ready(cx)
162    }
163
164    fn call(&mut self, req: (Request<Body>, C)) -> Self::Future { async fn run<T, C>(mut api_impl: T, req: (Request<Body>, C)) -> Result<Response<Body>, crate::ServiceError> where
165        T: Api<C> + Clone + Send + 'static,
166        C: Has<XSpanIdString>  + Send + Sync + 'static
167    {
168        let (request, context) = req;
169        let (parts, body) = request.into_parts();
170        let (method, uri, headers) = (parts.method, parts.uri, parts.headers);
171        let path = paths::GLOBAL_REGEX_SET.matches(uri.path());
172
173        match &method {
174
175            // Get - POST /mbus/get/{device}/{baudrate}/{address}
176            &hyper::Method::POST if path.matched(paths::ID_MBUS_GET_DEVICE_BAUDRATE_ADDRESS) => {
177                // Path parameters
178                let path: &str = &uri.path().to_string();
179                let path_params =
180                    paths::REGEX_MBUS_GET_DEVICE_BAUDRATE_ADDRESS
181                    .captures(&path)
182                    .unwrap_or_else(||
183                        panic!("Path {} matched RE MBUS_GET_DEVICE_BAUDRATE_ADDRESS in set but failed match against \"{}\"", path, paths::REGEX_MBUS_GET_DEVICE_BAUDRATE_ADDRESS.as_str())
184                    );
185
186                let param_device = match percent_encoding::percent_decode(path_params["device"].as_bytes()).decode_utf8() {
187                    Ok(param_device) => match param_device.parse::<String>() {
188                        Ok(param_device) => param_device,
189                        Err(e) => return Ok(Response::builder()
190                                        .status(StatusCode::BAD_REQUEST)
191                                        .body(Body::from(format!("Couldn't parse path parameter device: {}", e)))
192                                        .expect("Unable to create Bad Request response for invalid path parameter")),
193                    },
194                    Err(_) => return Ok(Response::builder()
195                                        .status(StatusCode::BAD_REQUEST)
196                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["device"])))
197                                        .expect("Unable to create Bad Request response for invalid percent decode"))
198                };
199
200                let param_baudrate = match percent_encoding::percent_decode(path_params["baudrate"].as_bytes()).decode_utf8() {
201                    Ok(param_baudrate) => match param_baudrate.parse::<models::Baudrate>() {
202                        Ok(param_baudrate) => param_baudrate,
203                        Err(e) => return Ok(Response::builder()
204                                        .status(StatusCode::BAD_REQUEST)
205                                        .body(Body::from(format!("Couldn't parse path parameter baudrate: {}", e)))
206                                        .expect("Unable to create Bad Request response for invalid path parameter")),
207                    },
208                    Err(_) => return Ok(Response::builder()
209                                        .status(StatusCode::BAD_REQUEST)
210                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["baudrate"])))
211                                        .expect("Unable to create Bad Request response for invalid percent decode"))
212                };
213
214                let param_address = match percent_encoding::percent_decode(path_params["address"].as_bytes()).decode_utf8() {
215                    Ok(param_address) => match param_address.parse::<String>() {
216                        Ok(param_address) => param_address,
217                        Err(e) => return Ok(Response::builder()
218                                        .status(StatusCode::BAD_REQUEST)
219                                        .body(Body::from(format!("Couldn't parse path parameter address: {}", e)))
220                                        .expect("Unable to create Bad Request response for invalid path parameter")),
221                    },
222                    Err(_) => return Ok(Response::builder()
223                                        .status(StatusCode::BAD_REQUEST)
224                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["address"])))
225                                        .expect("Unable to create Bad Request response for invalid percent decode"))
226                };
227
228                                let result = api_impl.get(
229                                            param_device,
230                                            param_baudrate,
231                                            param_address,
232                                        &context
233                                    ).await;
234                                let mut response = Response::new(Body::empty());
235                                response.headers_mut().insert(
236                                            HeaderName::from_static("x-span-id"),
237                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
238                                                .expect("Unable to create X-Span-ID header value"));
239
240                                        match result {
241                                            Ok(rsp) => match rsp {
242                                                GetResponse::OK
243                                                    (body)
244                                                => {
245                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
246                                                    response.headers_mut().insert(
247                                                        CONTENT_TYPE,
248                                                        HeaderValue::from_str("application/xml")
249                                                            .expect("Unable to create Content-Type header for GET_OK"));
250                                                    let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize");
251                                                    *response.body_mut() = Body::from(body);
252                                                },
253                                                GetResponse::BadRequest
254                                                    (body)
255                                                => {
256                                                    *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode");
257                                                    response.headers_mut().insert(
258                                                        CONTENT_TYPE,
259                                                        HeaderValue::from_str("text/plain")
260                                                            .expect("Unable to create Content-Type header for GET_BAD_REQUEST"));
261                                                    let body = body;
262                                                    *response.body_mut() = Body::from(body);
263                                                },
264                                                GetResponse::NotFound
265                                                    (body)
266                                                => {
267                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
268                                                    response.headers_mut().insert(
269                                                        CONTENT_TYPE,
270                                                        HeaderValue::from_str("text/plain")
271                                                            .expect("Unable to create Content-Type header for GET_NOT_FOUND"));
272                                                    let body = body;
273                                                    *response.body_mut() = Body::from(body);
274                                                },
275                                            },
276                                            Err(_) => {
277                                                // Application code returned an error. This should not happen, as the implementation should
278                                                // return a valid response.
279                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
280                                                *response.body_mut() = Body::from("An internal error occurred");
281                                            },
282                                        }
283
284                                        Ok(response)
285            },
286
287            // GetMulti - POST /mbus/getMulti/{device}/{baudrate}/{address}/{maxframes}
288            &hyper::Method::POST if path.matched(paths::ID_MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES) => {
289                // Path parameters
290                let path: &str = &uri.path().to_string();
291                let path_params =
292                    paths::REGEX_MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES
293                    .captures(&path)
294                    .unwrap_or_else(||
295                        panic!("Path {} matched RE MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES in set but failed match against \"{}\"", path, paths::REGEX_MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES.as_str())
296                    );
297
298                let param_device = match percent_encoding::percent_decode(path_params["device"].as_bytes()).decode_utf8() {
299                    Ok(param_device) => match param_device.parse::<String>() {
300                        Ok(param_device) => param_device,
301                        Err(e) => return Ok(Response::builder()
302                                        .status(StatusCode::BAD_REQUEST)
303                                        .body(Body::from(format!("Couldn't parse path parameter device: {}", e)))
304                                        .expect("Unable to create Bad Request response for invalid path parameter")),
305                    },
306                    Err(_) => return Ok(Response::builder()
307                                        .status(StatusCode::BAD_REQUEST)
308                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["device"])))
309                                        .expect("Unable to create Bad Request response for invalid percent decode"))
310                };
311
312                let param_baudrate = match percent_encoding::percent_decode(path_params["baudrate"].as_bytes()).decode_utf8() {
313                    Ok(param_baudrate) => match param_baudrate.parse::<models::Baudrate>() {
314                        Ok(param_baudrate) => param_baudrate,
315                        Err(e) => return Ok(Response::builder()
316                                        .status(StatusCode::BAD_REQUEST)
317                                        .body(Body::from(format!("Couldn't parse path parameter baudrate: {}", e)))
318                                        .expect("Unable to create Bad Request response for invalid path parameter")),
319                    },
320                    Err(_) => return Ok(Response::builder()
321                                        .status(StatusCode::BAD_REQUEST)
322                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["baudrate"])))
323                                        .expect("Unable to create Bad Request response for invalid percent decode"))
324                };
325
326                let param_address = match percent_encoding::percent_decode(path_params["address"].as_bytes()).decode_utf8() {
327                    Ok(param_address) => match param_address.parse::<String>() {
328                        Ok(param_address) => param_address,
329                        Err(e) => return Ok(Response::builder()
330                                        .status(StatusCode::BAD_REQUEST)
331                                        .body(Body::from(format!("Couldn't parse path parameter address: {}", e)))
332                                        .expect("Unable to create Bad Request response for invalid path parameter")),
333                    },
334                    Err(_) => return Ok(Response::builder()
335                                        .status(StatusCode::BAD_REQUEST)
336                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["address"])))
337                                        .expect("Unable to create Bad Request response for invalid percent decode"))
338                };
339
340                let param_maxframes = match percent_encoding::percent_decode(path_params["maxframes"].as_bytes()).decode_utf8() {
341                    Ok(param_maxframes) => match param_maxframes.parse::<i32>() {
342                        Ok(param_maxframes) => param_maxframes,
343                        Err(e) => return Ok(Response::builder()
344                                        .status(StatusCode::BAD_REQUEST)
345                                        .body(Body::from(format!("Couldn't parse path parameter maxframes: {}", e)))
346                                        .expect("Unable to create Bad Request response for invalid path parameter")),
347                    },
348                    Err(_) => return Ok(Response::builder()
349                                        .status(StatusCode::BAD_REQUEST)
350                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["maxframes"])))
351                                        .expect("Unable to create Bad Request response for invalid percent decode"))
352                };
353
354                                let result = api_impl.get_multi(
355                                            param_device,
356                                            param_baudrate,
357                                            param_address,
358                                            param_maxframes,
359                                        &context
360                                    ).await;
361                                let mut response = Response::new(Body::empty());
362                                response.headers_mut().insert(
363                                            HeaderName::from_static("x-span-id"),
364                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
365                                                .expect("Unable to create X-Span-ID header value"));
366
367                                        match result {
368                                            Ok(rsp) => match rsp {
369                                                GetMultiResponse::OK
370                                                    (body)
371                                                => {
372                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
373                                                    response.headers_mut().insert(
374                                                        CONTENT_TYPE,
375                                                        HeaderValue::from_str("application/xml")
376                                                            .expect("Unable to create Content-Type header for GET_MULTI_OK"));
377                                                    let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize");
378                                                    *response.body_mut() = Body::from(body);
379                                                },
380                                                GetMultiResponse::BadRequest
381                                                    (body)
382                                                => {
383                                                    *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode");
384                                                    response.headers_mut().insert(
385                                                        CONTENT_TYPE,
386                                                        HeaderValue::from_str("text/plain")
387                                                            .expect("Unable to create Content-Type header for GET_MULTI_BAD_REQUEST"));
388                                                    let body = body;
389                                                    *response.body_mut() = Body::from(body);
390                                                },
391                                                GetMultiResponse::NotFound
392                                                    (body)
393                                                => {
394                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
395                                                    response.headers_mut().insert(
396                                                        CONTENT_TYPE,
397                                                        HeaderValue::from_str("text/plain")
398                                                            .expect("Unable to create Content-Type header for GET_MULTI_NOT_FOUND"));
399                                                    let body = body;
400                                                    *response.body_mut() = Body::from(body);
401                                                },
402                                            },
403                                            Err(_) => {
404                                                // Application code returned an error. This should not happen, as the implementation should
405                                                // return a valid response.
406                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
407                                                *response.body_mut() = Body::from("An internal error occurred");
408                                            },
409                                        }
410
411                                        Ok(response)
412            },
413
414            // Hat - GET /mbus/hat
415            &hyper::Method::GET if path.matched(paths::ID_MBUS_HAT) => {
416                                let result = api_impl.hat(
417                                        &context
418                                    ).await;
419                                let mut response = Response::new(Body::empty());
420                                response.headers_mut().insert(
421                                            HeaderName::from_static("x-span-id"),
422                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
423                                                .expect("Unable to create X-Span-ID header value"));
424
425                                        match result {
426                                            Ok(rsp) => match rsp {
427                                                HatResponse::OK
428                                                    (body)
429                                                => {
430                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
431                                                    response.headers_mut().insert(
432                                                        CONTENT_TYPE,
433                                                        HeaderValue::from_str("application/json")
434                                                            .expect("Unable to create Content-Type header for HAT_OK"));
435                                                    let body = serde_json::to_string(&body).expect("impossible to fail to serialize");
436                                                    *response.body_mut() = Body::from(body);
437                                                },
438                                                HatResponse::NotFound
439                                                    (body)
440                                                => {
441                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
442                                                    response.headers_mut().insert(
443                                                        CONTENT_TYPE,
444                                                        HeaderValue::from_str("text/plain")
445                                                            .expect("Unable to create Content-Type header for HAT_NOT_FOUND"));
446                                                    let body = body;
447                                                    *response.body_mut() = Body::from(body);
448                                                },
449                                            },
450                                            Err(_) => {
451                                                // Application code returned an error. This should not happen, as the implementation should
452                                                // return a valid response.
453                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
454                                                *response.body_mut() = Body::from("An internal error occurred");
455                                            },
456                                        }
457
458                                        Ok(response)
459            },
460
461            // HatOff - POST /mbus/hat/off
462            &hyper::Method::POST if path.matched(paths::ID_MBUS_HAT_OFF) => {
463                                let result = api_impl.hat_off(
464                                        &context
465                                    ).await;
466                                let mut response = Response::new(Body::empty());
467                                response.headers_mut().insert(
468                                            HeaderName::from_static("x-span-id"),
469                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
470                                                .expect("Unable to create X-Span-ID header value"));
471
472                                        match result {
473                                            Ok(rsp) => match rsp {
474                                                HatOffResponse::OK
475                                                => {
476                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
477                                                },
478                                                HatOffResponse::NotFound
479                                                    (body)
480                                                => {
481                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
482                                                    response.headers_mut().insert(
483                                                        CONTENT_TYPE,
484                                                        HeaderValue::from_str("text/plain")
485                                                            .expect("Unable to create Content-Type header for HAT_OFF_NOT_FOUND"));
486                                                    let body = body;
487                                                    *response.body_mut() = Body::from(body);
488                                                },
489                                            },
490                                            Err(_) => {
491                                                // Application code returned an error. This should not happen, as the implementation should
492                                                // return a valid response.
493                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
494                                                *response.body_mut() = Body::from("An internal error occurred");
495                                            },
496                                        }
497
498                                        Ok(response)
499            },
500
501            // HatOn - POST /mbus/hat/on
502            &hyper::Method::POST if path.matched(paths::ID_MBUS_HAT_ON) => {
503                                let result = api_impl.hat_on(
504                                        &context
505                                    ).await;
506                                let mut response = Response::new(Body::empty());
507                                response.headers_mut().insert(
508                                            HeaderName::from_static("x-span-id"),
509                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
510                                                .expect("Unable to create X-Span-ID header value"));
511
512                                        match result {
513                                            Ok(rsp) => match rsp {
514                                                HatOnResponse::OK
515                                                => {
516                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
517                                                },
518                                                HatOnResponse::NotFound
519                                                    (body)
520                                                => {
521                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
522                                                    response.headers_mut().insert(
523                                                        CONTENT_TYPE,
524                                                        HeaderValue::from_str("text/plain")
525                                                            .expect("Unable to create Content-Type header for HAT_ON_NOT_FOUND"));
526                                                    let body = body;
527                                                    *response.body_mut() = Body::from(body);
528                                                },
529                                            },
530                                            Err(_) => {
531                                                // Application code returned an error. This should not happen, as the implementation should
532                                                // return a valid response.
533                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
534                                                *response.body_mut() = Body::from("An internal error occurred");
535                                            },
536                                        }
537
538                                        Ok(response)
539            },
540
541            // MbusApi - GET /mbus/api
542            &hyper::Method::GET if path.matched(paths::ID_MBUS_API) => {
543                                let result = api_impl.mbus_api(
544                                        &context
545                                    ).await;
546                                let mut response = Response::new(Body::empty());
547                                response.headers_mut().insert(
548                                            HeaderName::from_static("x-span-id"),
549                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
550                                                .expect("Unable to create X-Span-ID header value"));
551
552                                        match result {
553                                            Ok(rsp) => match rsp {
554                                                MbusApiResponse::OK
555                                                    (body)
556                                                => {
557                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
558                                                    response.headers_mut().insert(
559                                                        CONTENT_TYPE,
560                                                        HeaderValue::from_str("text/x-yaml")
561                                                            .expect("Unable to create Content-Type header for MBUS_API_OK"));
562                                                    let body = body;
563                                                    *response.body_mut() = Body::from(body);
564                                                },
565                                                MbusApiResponse::NotFound
566                                                    (body)
567                                                => {
568                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
569                                                    response.headers_mut().insert(
570                                                        CONTENT_TYPE,
571                                                        HeaderValue::from_str("text/plain")
572                                                            .expect("Unable to create Content-Type header for MBUS_API_NOT_FOUND"));
573                                                    let body = body;
574                                                    *response.body_mut() = Body::from(body);
575                                                },
576                                            },
577                                            Err(_) => {
578                                                // Application code returned an error. This should not happen, as the implementation should
579                                                // return a valid response.
580                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
581                                                *response.body_mut() = Body::from("An internal error occurred");
582                                            },
583                                        }
584
585                                        Ok(response)
586            },
587
588            // Scan - POST /mbus/scan/{device}/{baudrate}
589            &hyper::Method::POST if path.matched(paths::ID_MBUS_SCAN_DEVICE_BAUDRATE) => {
590                // Path parameters
591                let path: &str = &uri.path().to_string();
592                let path_params =
593                    paths::REGEX_MBUS_SCAN_DEVICE_BAUDRATE
594                    .captures(&path)
595                    .unwrap_or_else(||
596                        panic!("Path {} matched RE MBUS_SCAN_DEVICE_BAUDRATE in set but failed match against \"{}\"", path, paths::REGEX_MBUS_SCAN_DEVICE_BAUDRATE.as_str())
597                    );
598
599                let param_device = match percent_encoding::percent_decode(path_params["device"].as_bytes()).decode_utf8() {
600                    Ok(param_device) => match param_device.parse::<String>() {
601                        Ok(param_device) => param_device,
602                        Err(e) => return Ok(Response::builder()
603                                        .status(StatusCode::BAD_REQUEST)
604                                        .body(Body::from(format!("Couldn't parse path parameter device: {}", e)))
605                                        .expect("Unable to create Bad Request response for invalid path parameter")),
606                    },
607                    Err(_) => return Ok(Response::builder()
608                                        .status(StatusCode::BAD_REQUEST)
609                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["device"])))
610                                        .expect("Unable to create Bad Request response for invalid percent decode"))
611                };
612
613                let param_baudrate = match percent_encoding::percent_decode(path_params["baudrate"].as_bytes()).decode_utf8() {
614                    Ok(param_baudrate) => match param_baudrate.parse::<models::Baudrate>() {
615                        Ok(param_baudrate) => param_baudrate,
616                        Err(e) => return Ok(Response::builder()
617                                        .status(StatusCode::BAD_REQUEST)
618                                        .body(Body::from(format!("Couldn't parse path parameter baudrate: {}", e)))
619                                        .expect("Unable to create Bad Request response for invalid path parameter")),
620                    },
621                    Err(_) => return Ok(Response::builder()
622                                        .status(StatusCode::BAD_REQUEST)
623                                        .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["baudrate"])))
624                                        .expect("Unable to create Bad Request response for invalid percent decode"))
625                };
626
627                                let result = api_impl.scan(
628                                            param_device,
629                                            param_baudrate,
630                                        &context
631                                    ).await;
632                                let mut response = Response::new(Body::empty());
633                                response.headers_mut().insert(
634                                            HeaderName::from_static("x-span-id"),
635                                            HeaderValue::from_str((&context as &dyn Has<XSpanIdString>).get().0.clone().to_string().as_str())
636                                                .expect("Unable to create X-Span-ID header value"));
637
638                                        match result {
639                                            Ok(rsp) => match rsp {
640                                                ScanResponse::OK
641                                                    (body)
642                                                => {
643                                                    *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode");
644                                                    response.headers_mut().insert(
645                                                        CONTENT_TYPE,
646                                                        HeaderValue::from_str("text/plain")
647                                                            .expect("Unable to create Content-Type header for SCAN_OK"));
648                                                    let body = body;
649                                                    *response.body_mut() = Body::from(body);
650                                                },
651                                                ScanResponse::BadRequest
652                                                    (body)
653                                                => {
654                                                    *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode");
655                                                    response.headers_mut().insert(
656                                                        CONTENT_TYPE,
657                                                        HeaderValue::from_str("text/plain")
658                                                            .expect("Unable to create Content-Type header for SCAN_BAD_REQUEST"));
659                                                    let body = body;
660                                                    *response.body_mut() = Body::from(body);
661                                                },
662                                                ScanResponse::NotFound
663                                                    (body)
664                                                => {
665                                                    *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode");
666                                                    response.headers_mut().insert(
667                                                        CONTENT_TYPE,
668                                                        HeaderValue::from_str("text/plain")
669                                                            .expect("Unable to create Content-Type header for SCAN_NOT_FOUND"));
670                                                    let body = body;
671                                                    *response.body_mut() = Body::from(body);
672                                                },
673                                            },
674                                            Err(_) => {
675                                                // Application code returned an error. This should not happen, as the implementation should
676                                                // return a valid response.
677                                                *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
678                                                *response.body_mut() = Body::from("An internal error occurred");
679                                            },
680                                        }
681
682                                        Ok(response)
683            },
684
685            _ if path.matched(paths::ID_MBUS_API) => method_not_allowed(),
686            _ if path.matched(paths::ID_MBUS_GET_DEVICE_BAUDRATE_ADDRESS) => method_not_allowed(),
687            _ if path.matched(paths::ID_MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES) => method_not_allowed(),
688            _ if path.matched(paths::ID_MBUS_HAT) => method_not_allowed(),
689            _ if path.matched(paths::ID_MBUS_HAT_OFF) => method_not_allowed(),
690            _ if path.matched(paths::ID_MBUS_HAT_ON) => method_not_allowed(),
691            _ if path.matched(paths::ID_MBUS_SCAN_DEVICE_BAUDRATE) => method_not_allowed(),
692            _ => Ok(Response::builder().status(StatusCode::NOT_FOUND)
693                    .body(Body::empty())
694                    .expect("Unable to create Not Found response"))
695        }
696    } Box::pin(run(self.api_impl.clone(), req)) }
697}
698
699/// Request parser for `Api`.
700pub struct ApiRequestParser;
701impl<T> RequestParser<T> for ApiRequestParser {
702    fn parse_operation_id(request: &Request<T>) -> Result<&'static str, ()> {
703        let path = paths::GLOBAL_REGEX_SET.matches(request.uri().path());
704        match request.method() {
705            // Get - POST /mbus/get/{device}/{baudrate}/{address}
706            &hyper::Method::POST if path.matched(paths::ID_MBUS_GET_DEVICE_BAUDRATE_ADDRESS) => Ok("Get"),
707            // GetMulti - POST /mbus/getMulti/{device}/{baudrate}/{address}/{maxframes}
708            &hyper::Method::POST if path.matched(paths::ID_MBUS_GETMULTI_DEVICE_BAUDRATE_ADDRESS_MAXFRAMES) => Ok("GetMulti"),
709            // Hat - GET /mbus/hat
710            &hyper::Method::GET if path.matched(paths::ID_MBUS_HAT) => Ok("Hat"),
711            // HatOff - POST /mbus/hat/off
712            &hyper::Method::POST if path.matched(paths::ID_MBUS_HAT_OFF) => Ok("HatOff"),
713            // HatOn - POST /mbus/hat/on
714            &hyper::Method::POST if path.matched(paths::ID_MBUS_HAT_ON) => Ok("HatOn"),
715            // MbusApi - GET /mbus/api
716            &hyper::Method::GET if path.matched(paths::ID_MBUS_API) => Ok("MbusApi"),
717            // Scan - POST /mbus/scan/{device}/{baudrate}
718            &hyper::Method::POST if path.matched(paths::ID_MBUS_SCAN_DEVICE_BAUDRATE) => Ok("Scan"),
719            _ => Err(()),
720        }
721    }
722}