ecli_server_codegen/client/
mod.rs

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