1use async_trait::async_trait;
2use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt};
3use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
4use hyper::{Body, Request, Response, service::Service, Uri};
5use percent_encoding::{utf8_percent_encode, AsciiSet};
6use std::borrow::Cow;
7use std::convert::TryInto;
8use std::io::{ErrorKind, Read};
9use std::error::Error;
10use std::future::Future;
11use std::fmt;
12use std::marker::PhantomData;
13use std::path::Path;
14use std::sync::{Arc, Mutex};
15use std::str;
16use std::str::FromStr;
17use std::string::ToString;
18use std::task::{Context, Poll};
19use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString};
20use url::form_urlencoded;
21
22
23use crate::models;
24use crate::header;
25
26#[allow(dead_code)]
28const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
29 .add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
30
31#[allow(dead_code)]
36const ID_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'|');
37
38use crate::{Api,
39 BobbyDeleteResponse,
40 GamePostResponse,
41 MapsGetResponse,
42 RegisterPostResponse,
43 StatisticsGetResponse,
44 MapLevelGetResponse,
45 StatisticsUuidGetResponse,
46 UserUuidGetResponse
47 };
48
49fn into_base_path(input: impl TryInto<Uri, Error=hyper::http::uri::InvalidUri>, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> {
51 let uri = input.try_into()?;
53
54 let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
55
56 if let Some(correct_scheme) = correct_scheme {
58 if scheme != correct_scheme {
59 return Err(ClientInitError::InvalidScheme);
60 }
61 }
62
63 let host = uri.host().ok_or(ClientInitError::MissingHost)?;
64 let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default();
65 Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/')))
66}
67
68pub struct Client<S, C> where
70 S: Service<
71 (Request<Body>, C),
72 Response=Response<Body>> + Clone + Sync + Send + 'static,
73 S::Future: Send + 'static,
74 S::Error: Into<crate::ServiceError> + fmt::Display,
75 C: Clone + Send + Sync + 'static
76{
77 client_service: S,
79
80 base_path: String,
82
83 marker: PhantomData<fn(C)>,
85}
86
87impl<S, C> fmt::Debug for Client<S, C> where
88 S: Service<
89 (Request<Body>, C),
90 Response=Response<Body>> + Clone + Sync + Send + 'static,
91 S::Future: Send + 'static,
92 S::Error: Into<crate::ServiceError> + fmt::Display,
93 C: Clone + Send + Sync + 'static
94{
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 write!(f, "Client {{ base_path: {} }}", self.base_path)
97 }
98}
99
100impl<S, C> Clone for Client<S, C> where
101 S: Service<
102 (Request<Body>, C),
103 Response=Response<Body>> + Clone + Sync + Send + 'static,
104 S::Future: Send + 'static,
105 S::Error: Into<crate::ServiceError> + fmt::Display,
106 C: Clone + Send + Sync + 'static
107{
108 fn clone(&self) -> Self {
109 Self {
110 client_service: self.client_service.clone(),
111 base_path: self.base_path.clone(),
112 marker: PhantomData,
113 }
114 }
115}
116
117impl<Connector, C> Client<DropContextService<hyper::client::Client<Connector, Body>, C>, C> where
118 Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
119 C: Clone + Send + Sync + 'static,
120{
121 pub fn try_new_with_connector(
136 base_path: &str,
137 protocol: Option<&'static str>,
138 connector: Connector,
139 ) -> Result<Self, ClientInitError>
140 {
141 let client_service = hyper::client::Client::builder().build(connector);
142 let client_service = DropContextService::new(client_service);
143
144 Ok(Self {
145 client_service,
146 base_path: into_base_path(base_path, protocol)?,
147 marker: PhantomData,
148 })
149 }
150}
151
152#[derive(Debug, Clone)]
153pub enum HyperClient {
154 Http(hyper::client::Client<hyper::client::HttpConnector, Body>),
155 Https(hyper::client::Client<HttpsConnector, Body>),
156}
157
158impl Service<Request<Body>> for HyperClient {
159 type Response = Response<Body>;
160 type Error = hyper::Error;
161 type Future = hyper::client::ResponseFuture;
162
163 fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
164 match self {
165 HyperClient::Http(client) => client.poll_ready(cx),
166 HyperClient::Https(client) => client.poll_ready(cx),
167 }
168 }
169
170 fn call(&mut self, req: Request<Body>) -> Self::Future {
171 match self {
172 HyperClient::Http(client) => client.call(req),
173 HyperClient::Https(client) => client.call(req)
174 }
175 }
176}
177
178impl<C> Client<DropContextService<HyperClient, C>, C> where
179 C: Clone + Send + Sync + 'static,
180{
181 pub fn try_new(
186 base_path: &str,
187 ) -> Result<Self, ClientInitError> {
188 let uri = Uri::from_str(base_path)?;
189
190 let scheme = uri.scheme_str().ok_or(ClientInitError::InvalidScheme)?;
191 let scheme = scheme.to_ascii_lowercase();
192
193 let connector = Connector::builder();
194
195 let client_service = match scheme.as_str() {
196 "http" => {
197 HyperClient::Http(hyper::client::Client::builder().build(connector.build()))
198 },
199 "https" => {
200 let connector = connector.https()
201 .build()
202 .map_err(ClientInitError::SslError)?;
203 HyperClient::Https(hyper::client::Client::builder().build(connector))
204 },
205 _ => {
206 return Err(ClientInitError::InvalidScheme);
207 }
208 };
209
210 let client_service = DropContextService::new(client_service);
211
212 Ok(Self {
213 client_service,
214 base_path: into_base_path(base_path, None)?,
215 marker: PhantomData,
216 })
217 }
218}
219
220impl<C> Client<DropContextService<hyper::client::Client<hyper::client::HttpConnector, Body>, C>, C> where
221 C: Clone + Send + Sync + 'static
222{
223 pub fn try_new_http(
228 base_path: &str,
229 ) -> Result<Self, ClientInitError> {
230 let http_connector = Connector::builder().build();
231
232 Self::try_new_with_connector(base_path, Some("http"), http_connector)
233 }
234}
235
236#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
237type HttpsConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;
238
239#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
240type HttpsConnector = hyper_openssl::HttpsConnector<hyper::client::HttpConnector>;
241
242impl<C> Client<DropContextService<hyper::client::Client<HttpsConnector, Body>, C>, C> where
243 C: Clone + Send + Sync + 'static
244{
245 pub fn try_new_https(base_path: &str) -> Result<Self, ClientInitError>
250 {
251 let https_connector = Connector::builder()
252 .https()
253 .build()
254 .map_err(ClientInitError::SslError)?;
255 Self::try_new_with_connector(base_path, Some("https"), https_connector)
256 }
257
258 #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
264 pub fn try_new_https_pinned<CA>(
265 base_path: &str,
266 ca_certificate: CA,
267 ) -> Result<Self, ClientInitError>
268 where
269 CA: AsRef<Path>,
270 {
271 let https_connector = Connector::builder()
272 .https()
273 .pin_server_certificate(ca_certificate)
274 .build()
275 .map_err(ClientInitError::SslError)?;
276 Self::try_new_with_connector(base_path, Some("https"), https_connector)
277 }
278
279 #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
287 pub fn try_new_https_mutual<CA, K, D>(
288 base_path: &str,
289 ca_certificate: CA,
290 client_key: K,
291 client_certificate: D,
292 ) -> Result<Self, ClientInitError>
293 where
294 CA: AsRef<Path>,
295 K: AsRef<Path>,
296 D: AsRef<Path>,
297 {
298 let https_connector = Connector::builder()
299 .https()
300 .pin_server_certificate(ca_certificate)
301 .client_authentication(client_key, client_certificate)
302 .build()
303 .map_err(ClientInitError::SslError)?;
304 Self::try_new_with_connector(base_path, Some("https"), https_connector)
305 }
306}
307
308impl<S, C> Client<S, C> where
309 S: Service<
310 (Request<Body>, C),
311 Response=Response<Body>> + Clone + Sync + Send + 'static,
312 S::Future: Send + 'static,
313 S::Error: Into<crate::ServiceError> + fmt::Display,
314 C: Clone + Send + Sync + 'static
315{
316 pub fn try_new_with_client_service(
321 client_service: S,
322 base_path: &str,
323 ) -> Result<Self, ClientInitError>
324 {
325 Ok(Self {
326 client_service,
327 base_path: into_base_path(base_path, None)?,
328 marker: PhantomData,
329 })
330 }
331}
332
333#[derive(Debug)]
335pub enum ClientInitError {
336 InvalidScheme,
338
339 InvalidUri(hyper::http::uri::InvalidUri),
341
342 MissingHost,
344
345 #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
347 SslError(native_tls::Error),
348
349 #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
351 SslError(openssl::error::ErrorStack),
352}
353
354impl From<hyper::http::uri::InvalidUri> for ClientInitError {
355 fn from(err: hyper::http::uri::InvalidUri) -> ClientInitError {
356 ClientInitError::InvalidUri(err)
357 }
358}
359
360impl fmt::Display for ClientInitError {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 let s: &dyn fmt::Debug = self;
363 s.fmt(f)
364 }
365}
366
367impl Error for ClientInitError {
368 fn description(&self) -> &str {
369 "Failed to produce a hyper client."
370 }
371}
372
373#[async_trait]
374impl<S, C> Api<C> for Client<S, C> where
375 S: Service<
376 (Request<Body>, C),
377 Response=Response<Body>> + Clone + Sync + Send + 'static,
378 S::Future: Send + 'static,
379 S::Error: Into<crate::ServiceError> + fmt::Display,
380 C: Has<XSpanIdString> + Clone + Send + Sync + 'static,
381{
382 fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), crate::ServiceError>> {
383 match self.client_service.clone().poll_ready(cx) {
384 Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
385 Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)),
386 Poll::Pending => Poll::Pending,
387 }
388 }
389
390 async fn bobby_delete(
391 &self,
392 context: &C) -> Result<BobbyDeleteResponse, ApiError>
393 {
394 let mut client_service = self.client_service.clone();
395 let mut uri = format!(
396 "{}/bobby",
397 self.base_path
398 );
399
400 let query_string = {
402 let mut query_string = form_urlencoded::Serializer::new("".to_owned());
403 query_string.finish()
404 };
405 if !query_string.is_empty() {
406 uri += "?";
407 uri += &query_string;
408 }
409
410 let uri = match Uri::from_str(&uri) {
411 Ok(uri) => uri,
412 Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
413 };
414
415 let mut request = match Request::builder()
416 .method("DELETE")
417 .uri(uri)
418 .body(Body::empty()) {
419 Ok(req) => req,
420 Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
421 };
422
423 let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
424 request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
425 Ok(h) => h,
426 Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
427 });
428
429 let response = client_service.call((request, context.clone()))
430 .map_err(|e| ApiError(format!("No response received: {}", e))).await?;
431
432 match response.status().as_u16() {
433 200 => {
434 Ok(
435 BobbyDeleteResponse::DroppedAllData
436 )
437 }
438 409 => {
439 Ok(
440 BobbyDeleteResponse::WrongPassphraseProvided
441 )
442 }
443 code => {
444 let headers = response.headers().clone();
445 let body = response.into_body()
446 .take(100)
447 .into_raw().await;
448 Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
449 code,
450 headers,
451 match body {
452 Ok(body) => match String::from_utf8(body) {
453 Ok(body) => body,
454 Err(e) => format!("<Body was not UTF8: {:?}>", e),
455 },
456 Err(e) => format!("<Failed to read body: {}>", e),
457 }
458 )))
459 }
460 }
461 }
462
463 async fn game_post(
464 &self,
465 param_game_end_dto: models::GameEndDto,
466 context: &C) -> Result<GamePostResponse, ApiError>
467 {
468 let mut client_service = self.client_service.clone();
469 let mut uri = format!(
470 "{}/game",
471 self.base_path
472 );
473
474 let query_string = {
476 let mut query_string = form_urlencoded::Serializer::new("".to_owned());
477 query_string.finish()
478 };
479 if !query_string.is_empty() {
480 uri += "?";
481 uri += &query_string;
482 }
483
484 let uri = match Uri::from_str(&uri) {
485 Ok(uri) => uri,
486 Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
487 };
488
489 let mut request = match Request::builder()
490 .method("POST")
491 .uri(uri)
492 .body(Body::empty()) {
493 Ok(req) => req,
494 Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
495 };
496
497 let body = serde_json::to_string(¶m_game_end_dto).expect("impossible to fail to serialize");
500 *request.body_mut() = Body::from(body);
501
502 let header = "application/json";
503 request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) {
504 Ok(h) => h,
505 Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
506 });
507
508 let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
509 request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
510 Ok(h) => h,
511 Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
512 });
513
514 let response = client_service.call((request, context.clone()))
515 .map_err(|e| ApiError(format!("No response received: {}", e))).await?;
516
517 match response.status().as_u16() {
518 200 => {
519 let body = response.into_body();
520 let body = body
521 .into_raw()
522 .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?;
523
524 let body = str::from_utf8(&body)
525 .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?;
526 let body = serde_json::from_str::<models::ResultDto>(body)
527 .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?;
528
529
530 Ok(GamePostResponse::GameResultDetails
531 (body)
532 )
533 }
534 code => {
535 let headers = response.headers().clone();
536 let body = response.into_body()
537 .take(100)
538 .into_raw().await;
539 Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
540 code,
541 headers,
542 match body {
543 Ok(body) => match String::from_utf8(body) {
544 Ok(body) => body,
545 Err(e) => format!("<Body was not UTF8: {:?}>", e),
546 },
547 Err(e) => format!("<Failed to read body: {}>", e),
548 }
549 )))
550 }
551 }
552 }
553
554 async fn maps_get(
555 &self,
556 context: &C) -> Result<MapsGetResponse, ApiError>
557 {
558 let mut client_service = self.client_service.clone();
559 let mut uri = format!(
560 "{}/maps",
561 self.base_path
562 );
563
564 let query_string = {
566 let mut query_string = form_urlencoded::Serializer::new("".to_owned());
567 query_string.finish()
568 };
569 if !query_string.is_empty() {
570 uri += "?";
571 uri += &query_string;
572 }
573
574 let uri = match Uri::from_str(&uri) {
575 Ok(uri) => uri,
576 Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
577 };
578
579 let mut request = match Request::builder()
580 .method("GET")
581 .uri(uri)
582 .body(Body::empty()) {
583 Ok(req) => req,
584 Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
585 };
586
587 let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
588 request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
589 Ok(h) => h,
590 Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
591 });
592
593 let response = client_service.call((request, context.clone()))
594 .map_err(|e| ApiError(format!("No response received: {}", e))).await?;
595
596 match response.status().as_u16() {
597 200 => {
598 let body = response.into_body();
599 let body = body
600 .into_raw()
601 .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?;
602
603 let body = str::from_utf8(&body)
604 .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?;
605 let body = serde_json::from_str::<Vec<String>>(body)
606 .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?;
607
608
609 Ok(MapsGetResponse::ListOfTheIdsOfAllExistingMaps
610 (body)
611 )
612 }
613 500 => {
614 Ok(
615 MapsGetResponse::NoMapsInDatabase
616 )
617 }
618 code => {
619 let headers = response.headers().clone();
620 let body = response.into_body()
621 .take(100)
622 .into_raw().await;
623 Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
624 code,
625 headers,
626 match body {
627 Ok(body) => match String::from_utf8(body) {
628 Ok(body) => body,
629 Err(e) => format!("<Body was not UTF8: {:?}>", e),
630 },
631 Err(e) => format!("<Failed to read body: {}>", e),
632 }
633 )))
634 }
635 }
636 }
637
638 async fn register_post(
639 &self,
640 param_create_user_dto: models::CreateUserDto,
641 context: &C) -> Result<RegisterPostResponse, ApiError>
642 {
643 let mut client_service = self.client_service.clone();
644 let mut uri = format!(
645 "{}/register",
646 self.base_path
647 );
648
649 let query_string = {
651 let mut query_string = form_urlencoded::Serializer::new("".to_owned());
652 query_string.finish()
653 };
654 if !query_string.is_empty() {
655 uri += "?";
656 uri += &query_string;
657 }
658
659 let uri = match Uri::from_str(&uri) {
660 Ok(uri) => uri,
661 Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
662 };
663
664 let mut request = match Request::builder()
665 .method("POST")
666 .uri(uri)
667 .body(Body::empty()) {
668 Ok(req) => req,
669 Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
670 };
671
672 let body = serde_json::to_string(¶m_create_user_dto).expect("impossible to fail to serialize");
675 *request.body_mut() = Body::from(body);
676
677 let header = "application/json";
678 request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) {
679 Ok(h) => h,
680 Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e)))
681 });
682
683 let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
684 request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
685 Ok(h) => h,
686 Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
687 });
688
689 let response = client_service.call((request, context.clone()))
690 .map_err(|e| ApiError(format!("No response received: {}", e))).await?;
691
692 match response.status().as_u16() {
693 200 => {
694 Ok(
695 RegisterPostResponse::Created
696 )
697 }
698 409 => {
699 Ok(
700 RegisterPostResponse::UserWithThatIDDoesAlreadyExist
701 )
702 }
703 code => {
704 let headers = response.headers().clone();
705 let body = response.into_body()
706 .take(100)
707 .into_raw().await;
708 Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
709 code,
710 headers,
711 match body {
712 Ok(body) => match String::from_utf8(body) {
713 Ok(body) => body,
714 Err(e) => format!("<Body was not UTF8: {:?}>", e),
715 },
716 Err(e) => format!("<Failed to read body: {}>", e),
717 }
718 )))
719 }
720 }
721 }
722
723 async fn statistics_get(
724 &self,
725 context: &C) -> Result<StatisticsGetResponse, ApiError>
726 {
727 let mut client_service = self.client_service.clone();
728 let mut uri = format!(
729 "{}/statistics",
730 self.base_path
731 );
732
733 let query_string = {
735 let mut query_string = form_urlencoded::Serializer::new("".to_owned());
736 query_string.finish()
737 };
738 if !query_string.is_empty() {
739 uri += "?";
740 uri += &query_string;
741 }
742
743 let uri = match Uri::from_str(&uri) {
744 Ok(uri) => uri,
745 Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
746 };
747
748 let mut request = match Request::builder()
749 .method("GET")
750 .uri(uri)
751 .body(Body::empty()) {
752 Ok(req) => req,
753 Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
754 };
755
756 let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
757 request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
758 Ok(h) => h,
759 Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
760 });
761
762 let response = client_service.call((request, context.clone()))
763 .map_err(|e| ApiError(format!("No response received: {}", e))).await?;
764
765 match response.status().as_u16() {
766 200 => {
767 let body = response.into_body();
768 let body = body
769 .into_raw()
770 .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?;
771
772 let body = str::from_utf8(&body)
773 .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?;
774 let body = serde_json::from_str::<Vec<String>>(body)
775 .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?;
776
777
778 Ok(StatisticsGetResponse::GameResultDetails
779 (body)
780 )
781 }
782 code => {
783 let headers = response.headers().clone();
784 let body = response.into_body()
785 .take(100)
786 .into_raw().await;
787 Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
788 code,
789 headers,
790 match body {
791 Ok(body) => match String::from_utf8(body) {
792 Ok(body) => body,
793 Err(e) => format!("<Body was not UTF8: {:?}>", e),
794 },
795 Err(e) => format!("<Failed to read body: {}>", e),
796 }
797 )))
798 }
799 }
800 }
801
802 async fn map_level_get(
803 &self,
804 param_level: String,
805 context: &C) -> Result<MapLevelGetResponse, ApiError>
806 {
807 let mut client_service = self.client_service.clone();
808 let mut uri = format!(
809 "{}/map/{level}",
810 self.base_path
811 ,level=utf8_percent_encode(¶m_level.to_string(), ID_ENCODE_SET)
812 );
813
814 let query_string = {
816 let mut query_string = form_urlencoded::Serializer::new("".to_owned());
817 query_string.finish()
818 };
819 if !query_string.is_empty() {
820 uri += "?";
821 uri += &query_string;
822 }
823
824 let uri = match Uri::from_str(&uri) {
825 Ok(uri) => uri,
826 Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
827 };
828
829 let mut request = match Request::builder()
830 .method("GET")
831 .uri(uri)
832 .body(Body::empty()) {
833 Ok(req) => req,
834 Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
835 };
836
837 let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
838 request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
839 Ok(h) => h,
840 Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
841 });
842
843 let response = client_service.call((request, context.clone()))
844 .map_err(|e| ApiError(format!("No response received: {}", e))).await?;
845
846 match response.status().as_u16() {
847 200 => {
848 let body = response.into_body();
849 let body = body
850 .into_raw()
851 .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?;
852
853 let body = str::from_utf8(&body)
854 .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?;
855 let body = serde_json::from_str::<Vec<models::MapDto>>(body)
856 .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?;
857
858
859 Ok(MapLevelGetResponse::BeatMap
860 (body)
861 )
862 }
863 404 => {
864 Ok(
865 MapLevelGetResponse::ThisMapDoesNotExist
866 )
867 }
868 code => {
869 let headers = response.headers().clone();
870 let body = response.into_body()
871 .take(100)
872 .into_raw().await;
873 Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
874 code,
875 headers,
876 match body {
877 Ok(body) => match String::from_utf8(body) {
878 Ok(body) => body,
879 Err(e) => format!("<Body was not UTF8: {:?}>", e),
880 },
881 Err(e) => format!("<Failed to read body: {}>", e),
882 }
883 )))
884 }
885 }
886 }
887
888 async fn statistics_uuid_get(
889 &self,
890 param_uuid: String,
891 context: &C) -> Result<StatisticsUuidGetResponse, ApiError>
892 {
893 let mut client_service = self.client_service.clone();
894 let mut uri = format!(
895 "{}/statistics/{uuid}",
896 self.base_path
897 ,uuid=utf8_percent_encode(¶m_uuid.to_string(), ID_ENCODE_SET)
898 );
899
900 let query_string = {
902 let mut query_string = form_urlencoded::Serializer::new("".to_owned());
903 query_string.finish()
904 };
905 if !query_string.is_empty() {
906 uri += "?";
907 uri += &query_string;
908 }
909
910 let uri = match Uri::from_str(&uri) {
911 Ok(uri) => uri,
912 Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
913 };
914
915 let mut request = match Request::builder()
916 .method("GET")
917 .uri(uri)
918 .body(Body::empty()) {
919 Ok(req) => req,
920 Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
921 };
922
923 let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
924 request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
925 Ok(h) => h,
926 Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
927 });
928
929 let response = client_service.call((request, context.clone()))
930 .map_err(|e| ApiError(format!("No response received: {}", e))).await?;
931
932 match response.status().as_u16() {
933 200 => {
934 let body = response.into_body();
935 let body = body
936 .into_raw()
937 .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?;
938
939 let body = str::from_utf8(&body)
940 .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?;
941 let body = serde_json::from_str::<models::ResultDto>(body)
942 .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?;
943
944
945 Ok(StatisticsUuidGetResponse::GameResultDetails
946 (body)
947 )
948 }
949 404 => {
950 Ok(
951 StatisticsUuidGetResponse::ThisStatisticDoesNotExist
952 )
953 }
954 code => {
955 let headers = response.headers().clone();
956 let body = response.into_body()
957 .take(100)
958 .into_raw().await;
959 Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
960 code,
961 headers,
962 match body {
963 Ok(body) => match String::from_utf8(body) {
964 Ok(body) => body,
965 Err(e) => format!("<Body was not UTF8: {:?}>", e),
966 },
967 Err(e) => format!("<Failed to read body: {}>", e),
968 }
969 )))
970 }
971 }
972 }
973
974 async fn user_uuid_get(
975 &self,
976 param_uuid: String,
977 context: &C) -> Result<UserUuidGetResponse, ApiError>
978 {
979 let mut client_service = self.client_service.clone();
980 let mut uri = format!(
981 "{}/user/{uuid}",
982 self.base_path
983 ,uuid=utf8_percent_encode(¶m_uuid.to_string(), ID_ENCODE_SET)
984 );
985
986 let query_string = {
988 let mut query_string = form_urlencoded::Serializer::new("".to_owned());
989 query_string.finish()
990 };
991 if !query_string.is_empty() {
992 uri += "?";
993 uri += &query_string;
994 }
995
996 let uri = match Uri::from_str(&uri) {
997 Ok(uri) => uri,
998 Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
999 };
1000
1001 let mut request = match Request::builder()
1002 .method("GET")
1003 .uri(uri)
1004 .body(Body::empty()) {
1005 Ok(req) => req,
1006 Err(e) => return Err(ApiError(format!("Unable to create request: {}", e)))
1007 };
1008
1009 let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
1010 request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header {
1011 Ok(h) => h,
1012 Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e)))
1013 });
1014
1015 let response = client_service.call((request, context.clone()))
1016 .map_err(|e| ApiError(format!("No response received: {}", e))).await?;
1017
1018 match response.status().as_u16() {
1019 200 => {
1020 let body = response.into_body();
1021 let body = body
1022 .into_raw()
1023 .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?;
1024
1025 let body = str::from_utf8(&body)
1026 .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?;
1027 let body = serde_json::from_str::<models::UserDto>(body)
1028 .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?;
1029
1030
1031 Ok(UserUuidGetResponse::SuccessfullyFetchedUserData
1032 (body)
1033 )
1034 }
1035 404 => {
1036 Ok(
1037 UserUuidGetResponse::UserWithThatIDDoesExist
1038 )
1039 }
1040 code => {
1041 let headers = response.headers().clone();
1042 let body = response.into_body()
1043 .take(100)
1044 .into_raw().await;
1045 Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}",
1046 code,
1047 headers,
1048 match body {
1049 Ok(body) => match String::from_utf8(body) {
1050 Ok(body) => body,
1051 Err(e) => format!("<Body was not UTF8: {:?}>", e),
1052 },
1053 Err(e) => format!("<Failed to read body: {}>", e),
1054 }
1055 )))
1056 }
1057 }
1058 }
1059
1060}