1use super::{ContentType, Error, configuration};
26use crate::{apis::ResponseContent, models};
27use ::qcs_api_client_common::backoff::{
28 BackoffBuilder, ExponentialBackoff, duration_from_io_error, duration_from_reqwest_error,
29 duration_from_response,
30};
31#[cfg(feature = "tracing")]
32use qcs_api_client_common::configuration::tokens::TokenRefresher;
33use qcs_dependencies_client::reqwest::{self, StatusCode};
34use serde::{Deserialize, Serialize};
35
36#[cfg(feature = "clap")]
37#[allow(unused, reason = "not used in all templates, but required in some")]
38use ::{miette::IntoDiagnostic as _, qcs_api_client_common::clap_utils::JsonMaybeStdin};
39
40#[cfg(feature = "clap")]
42#[derive(Debug, clap::Args)]
43pub struct CreateEndpointClapParams {
44 pub create_endpoint_parameters: JsonMaybeStdin<crate::models::CreateEndpointParameters>,
45}
46
47#[cfg(feature = "clap")]
48impl CreateEndpointClapParams {
49 pub async fn execute(
50 self,
51 configuration: &configuration::Configuration,
52 ) -> Result<models::Endpoint, miette::Error> {
53 let request = self.create_endpoint_parameters.into_inner().into_inner();
54
55 create_endpoint(configuration, request)
56 .await
57 .into_diagnostic()
58 }
59}
60
61#[cfg(feature = "clap")]
63#[derive(Debug, clap::Args)]
64pub struct ListEndpointsClapParams {
65 #[arg(long)]
67 pub filter: Option<String>,
68 #[arg(long)]
69 pub page_size: Option<i64>,
70 #[arg(long)]
71 pub page_token: Option<String>,
72}
73
74#[cfg(feature = "clap")]
75impl ListEndpointsClapParams {
76 pub async fn execute(
77 self,
78 configuration: &configuration::Configuration,
79 ) -> Result<models::ListEndpointsResponse, miette::Error> {
80 list_endpoints(
81 configuration,
82 self.filter.as_deref(),
83 self.page_size,
84 self.page_token.as_deref(),
85 )
86 .await
87 .into_diagnostic()
88 }
89}
90
91#[cfg(feature = "clap")]
93#[derive(Debug, clap::Args)]
94pub struct RestartEndpointClapParams {
95 #[arg(long)]
96 pub endpoint_id: String,
97 pub restart_endpoint_request: Option<JsonMaybeStdin<crate::models::RestartEndpointRequest>>,
98}
99
100#[cfg(feature = "clap")]
101impl RestartEndpointClapParams {
102 pub async fn execute(
103 self,
104 configuration: &configuration::Configuration,
105 ) -> Result<(), miette::Error> {
106 let request = self
107 .restart_endpoint_request
108 .map(|body| body.into_inner().into_inner());
109
110 restart_endpoint(configuration, self.endpoint_id.as_str(), request)
111 .await
112 .into_diagnostic()
113 }
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
118#[serde(untagged)]
119pub enum CreateEndpointError {
120 Status400(models::Error),
121 Status404(models::Error),
122 Status422(models::ValidationError),
123 UnknownValue(serde_json::Value),
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128#[serde(untagged)]
129pub enum ListEndpointsError {
130 Status422(models::ValidationError),
131 UnknownValue(serde_json::Value),
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
136#[serde(untagged)]
137pub enum RestartEndpointError {
138 Status403(models::Error),
139 Status422(models::ValidationError),
140 UnknownValue(serde_json::Value),
141}
142
143async fn create_endpoint_inner(
144 configuration: &configuration::Configuration,
145 backoff: &mut ExponentialBackoff,
146 create_endpoint_parameters: crate::models::CreateEndpointParameters,
147) -> Result<models::Endpoint, Error<CreateEndpointError>> {
148 let local_var_configuration = configuration;
149 let p_body_create_endpoint_parameters = create_endpoint_parameters;
151
152 let local_var_client = &local_var_configuration.client;
153
154 let local_var_uri_str = format!(
155 "{}/v1/endpoints",
156 local_var_configuration.qcs_config.api_url()
157 );
158 let mut local_var_req_builder =
159 local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
160
161 #[cfg(feature = "tracing")]
162 {
163 let local_var_do_tracing = local_var_uri_str
166 .parse::<::url::Url>()
167 .ok()
168 .is_none_or(|url| {
169 configuration
170 .qcs_config
171 .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
172 });
173
174 if local_var_do_tracing {
175 ::tracing::debug!(
176 url=%local_var_uri_str,
177 method="POST",
178 "making create_endpoint request",
179 );
180 }
181 }
182
183 {
186 use qcs_api_client_common::configuration::TokenError;
187
188 #[allow(
189 clippy::nonminimal_bool,
190 clippy::eq_op,
191 reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
192 )]
193 let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
194
195 let token = local_var_configuration
196 .qcs_config
197 .get_bearer_access_token()
198 .await;
199
200 if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
201 #[cfg(feature = "tracing")]
203 tracing::debug!(
204 "No client credentials found, but this call does not require authentication."
205 );
206 } else {
207 local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
208 }
209 }
210
211 local_var_req_builder = local_var_req_builder.json(&p_body_create_endpoint_parameters);
212
213 let local_var_req = local_var_req_builder.build()?;
214 let local_var_resp = local_var_client.execute(local_var_req).await?;
215
216 let local_var_status = local_var_resp.status();
217 let local_var_raw_content_type = local_var_resp
218 .headers()
219 .get("content-type")
220 .and_then(|v| v.to_str().ok())
221 .unwrap_or("application/octet-stream")
222 .to_string();
223 let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
224
225 if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
226 let local_var_content = local_var_resp.text().await?;
227 match local_var_content_type {
228 ContentType::Json => serde_path_to_error::deserialize(
229 &mut serde_json::Deserializer::from_str(&local_var_content),
230 )
231 .map_err(Error::from),
232 ContentType::Text => Err(Error::InvalidContentType {
233 content_type: local_var_raw_content_type,
234 return_type: "models::Endpoint",
235 }),
236 ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
237 content_type: unknown_type,
238 return_type: "models::Endpoint",
239 }),
240 }
241 } else {
242 let local_var_retry_delay =
243 duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
244 let local_var_content = local_var_resp.text().await?;
245 let local_var_entity: Option<CreateEndpointError> =
246 serde_json::from_str(&local_var_content).ok();
247 let local_var_error = ResponseContent {
248 status: local_var_status,
249 content: local_var_content,
250 entity: local_var_entity,
251 retry_delay: local_var_retry_delay,
252 };
253 Err(Error::ResponseError(local_var_error))
254 }
255}
256
257pub async fn create_endpoint(
259 configuration: &configuration::Configuration,
260 create_endpoint_parameters: crate::models::CreateEndpointParameters,
261) -> Result<models::Endpoint, Error<CreateEndpointError>> {
262 let mut backoff = configuration.backoff.build();
263 let mut refreshed_credentials = false;
264 let method = reqwest::Method::POST;
265 loop {
266 let result = create_endpoint_inner(
267 configuration,
268 &mut backoff,
269 create_endpoint_parameters.clone(),
270 )
271 .await;
272
273 match result {
274 Ok(result) => return Ok(result),
275 Err(Error::ResponseError(response)) => {
276 if !refreshed_credentials
277 && matches!(
278 response.status,
279 StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
280 )
281 {
282 match configuration.qcs_config.refresh().await {
284 Ok(_) => {
285 refreshed_credentials = true;
286 continue;
287 }
288 Err(::qcs_api_client_common::configuration::TokenError::Write {
289 error,
290 oauth_session: _,
291 }) => {
292 #[cfg(feature = "tracing")]
295 tracing::warn!(
296 "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
297 error
298 );
299 refreshed_credentials = true;
300 continue;
301 }
302 Err(e) => return Err(e.into()),
303 }
304 } else if let Some(duration) = response.retry_delay {
305 tokio::time::sleep(duration).await;
306 continue;
307 }
308
309 return Err(Error::ResponseError(response));
310 }
311 Err(Error::Reqwest(error)) => {
312 if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
313 tokio::time::sleep(duration).await;
314 continue;
315 }
316
317 return Err(Error::Reqwest(error));
318 }
319 Err(Error::Io(error)) => {
320 if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
321 tokio::time::sleep(duration).await;
322 continue;
323 }
324
325 return Err(Error::Io(error));
326 }
327 Err(error) => return Err(error),
328 }
329 }
330}
331async fn list_endpoints_inner(
332 configuration: &configuration::Configuration,
333 backoff: &mut ExponentialBackoff,
334 filter: Option<&str>,
335 page_size: Option<i64>,
336 page_token: Option<&str>,
337) -> Result<models::ListEndpointsResponse, Error<ListEndpointsError>> {
338 let local_var_configuration = configuration;
339 let p_query_filter = filter;
341 let p_query_page_size = page_size;
342 let p_query_page_token = page_token;
343
344 let local_var_client = &local_var_configuration.client;
345
346 let local_var_uri_str = format!(
347 "{}/v1/endpoints",
348 local_var_configuration.qcs_config.api_url()
349 );
350 let mut local_var_req_builder =
351 local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
352
353 #[cfg(feature = "tracing")]
354 {
355 let local_var_do_tracing = local_var_uri_str
358 .parse::<::url::Url>()
359 .ok()
360 .is_none_or(|url| {
361 configuration
362 .qcs_config
363 .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
364 });
365
366 if local_var_do_tracing {
367 ::tracing::debug!(
368 url=%local_var_uri_str,
369 method="GET",
370 "making list_endpoints request",
371 );
372 }
373 }
374
375 if let Some(ref local_var_str) = p_query_filter {
376 local_var_req_builder =
377 local_var_req_builder.query(&[("filter", &local_var_str.to_string())]);
378 }
379 if let Some(ref local_var_str) = p_query_page_size {
380 local_var_req_builder =
381 local_var_req_builder.query(&[("pageSize", &local_var_str.to_string())]);
382 }
383 if let Some(ref local_var_str) = p_query_page_token {
384 local_var_req_builder =
385 local_var_req_builder.query(&[("pageToken", &local_var_str.to_string())]);
386 }
387
388 {
391 use qcs_api_client_common::configuration::TokenError;
392
393 #[allow(
394 clippy::nonminimal_bool,
395 clippy::eq_op,
396 reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
397 )]
398 let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
399
400 let token = local_var_configuration
401 .qcs_config
402 .get_bearer_access_token()
403 .await;
404
405 if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
406 #[cfg(feature = "tracing")]
408 tracing::debug!(
409 "No client credentials found, but this call does not require authentication."
410 );
411 } else {
412 local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
413 }
414 }
415
416 let local_var_req = local_var_req_builder.build()?;
417 let local_var_resp = local_var_client.execute(local_var_req).await?;
418
419 let local_var_status = local_var_resp.status();
420 let local_var_raw_content_type = local_var_resp
421 .headers()
422 .get("content-type")
423 .and_then(|v| v.to_str().ok())
424 .unwrap_or("application/octet-stream")
425 .to_string();
426 let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
427
428 if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
429 let local_var_content = local_var_resp.text().await?;
430 match local_var_content_type {
431 ContentType::Json => serde_path_to_error::deserialize(
432 &mut serde_json::Deserializer::from_str(&local_var_content),
433 )
434 .map_err(Error::from),
435 ContentType::Text => Err(Error::InvalidContentType {
436 content_type: local_var_raw_content_type,
437 return_type: "models::ListEndpointsResponse",
438 }),
439 ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
440 content_type: unknown_type,
441 return_type: "models::ListEndpointsResponse",
442 }),
443 }
444 } else {
445 let local_var_retry_delay =
446 duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
447 let local_var_content = local_var_resp.text().await?;
448 let local_var_entity: Option<ListEndpointsError> =
449 serde_json::from_str(&local_var_content).ok();
450 let local_var_error = ResponseContent {
451 status: local_var_status,
452 content: local_var_content,
453 entity: local_var_entity,
454 retry_delay: local_var_retry_delay,
455 };
456 Err(Error::ResponseError(local_var_error))
457 }
458}
459
460pub async fn list_endpoints(
462 configuration: &configuration::Configuration,
463 filter: Option<&str>,
464 page_size: Option<i64>,
465 page_token: Option<&str>,
466) -> Result<models::ListEndpointsResponse, Error<ListEndpointsError>> {
467 let mut backoff = configuration.backoff.build();
468 let mut refreshed_credentials = false;
469 let method = reqwest::Method::GET;
470 loop {
471 let result = list_endpoints_inner(
472 configuration,
473 &mut backoff,
474 filter.clone(),
475 page_size.clone(),
476 page_token.clone(),
477 )
478 .await;
479
480 match result {
481 Ok(result) => return Ok(result),
482 Err(Error::ResponseError(response)) => {
483 if !refreshed_credentials
484 && matches!(
485 response.status,
486 StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
487 )
488 {
489 match configuration.qcs_config.refresh().await {
491 Ok(_) => {
492 refreshed_credentials = true;
493 continue;
494 }
495 Err(::qcs_api_client_common::configuration::TokenError::Write {
496 error,
497 oauth_session: _,
498 }) => {
499 #[cfg(feature = "tracing")]
502 tracing::warn!(
503 "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
504 error
505 );
506 refreshed_credentials = true;
507 continue;
508 }
509 Err(e) => return Err(e.into()),
510 }
511 } else if let Some(duration) = response.retry_delay {
512 tokio::time::sleep(duration).await;
513 continue;
514 }
515
516 return Err(Error::ResponseError(response));
517 }
518 Err(Error::Reqwest(error)) => {
519 if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
520 tokio::time::sleep(duration).await;
521 continue;
522 }
523
524 return Err(Error::Reqwest(error));
525 }
526 Err(Error::Io(error)) => {
527 if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
528 tokio::time::sleep(duration).await;
529 continue;
530 }
531
532 return Err(Error::Io(error));
533 }
534 Err(error) => return Err(error),
535 }
536 }
537}
538async fn restart_endpoint_inner(
539 configuration: &configuration::Configuration,
540 backoff: &mut ExponentialBackoff,
541 endpoint_id: &str,
542 restart_endpoint_request: Option<crate::models::RestartEndpointRequest>,
543) -> Result<(), Error<RestartEndpointError>> {
544 let local_var_configuration = configuration;
545 let p_path_endpoint_id = endpoint_id;
547 let p_body_restart_endpoint_request = restart_endpoint_request;
548
549 let local_var_client = &local_var_configuration.client;
550
551 let local_var_uri_str = format!(
552 "{}/v1/endpoints/{endpointId}:restart",
553 local_var_configuration.qcs_config.api_url(),
554 endpointId = crate::apis::urlencode(p_path_endpoint_id)
555 );
556 let mut local_var_req_builder =
557 local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
558
559 #[cfg(feature = "tracing")]
560 {
561 let local_var_do_tracing = local_var_uri_str
564 .parse::<::url::Url>()
565 .ok()
566 .is_none_or(|url| {
567 configuration
568 .qcs_config
569 .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
570 });
571
572 if local_var_do_tracing {
573 ::tracing::debug!(
574 url=%local_var_uri_str,
575 method="POST",
576 "making restart_endpoint request",
577 );
578 }
579 }
580
581 {
584 use qcs_api_client_common::configuration::TokenError;
585
586 #[allow(
587 clippy::nonminimal_bool,
588 clippy::eq_op,
589 reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
590 )]
591 let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
592
593 let token = local_var_configuration
594 .qcs_config
595 .get_bearer_access_token()
596 .await;
597
598 if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
599 #[cfg(feature = "tracing")]
601 tracing::debug!(
602 "No client credentials found, but this call does not require authentication."
603 );
604 } else {
605 local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
606 }
607 }
608
609 local_var_req_builder = local_var_req_builder.json(&p_body_restart_endpoint_request);
610
611 let local_var_req = local_var_req_builder.build()?;
612 let local_var_resp = local_var_client.execute(local_var_req).await?;
613
614 let local_var_status = local_var_resp.status();
615
616 if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
617 Ok(())
618 } else {
619 let local_var_retry_delay =
620 duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
621 let local_var_content = local_var_resp.text().await?;
622 let local_var_entity: Option<RestartEndpointError> =
623 serde_json::from_str(&local_var_content).ok();
624 let local_var_error = ResponseContent {
625 status: local_var_status,
626 content: local_var_content,
627 entity: local_var_entity,
628 retry_delay: local_var_retry_delay,
629 };
630 Err(Error::ResponseError(local_var_error))
631 }
632}
633
634pub async fn restart_endpoint(
636 configuration: &configuration::Configuration,
637 endpoint_id: &str,
638 restart_endpoint_request: Option<crate::models::RestartEndpointRequest>,
639) -> Result<(), Error<RestartEndpointError>> {
640 let mut backoff = configuration.backoff.build();
641 let mut refreshed_credentials = false;
642 let method = reqwest::Method::POST;
643 loop {
644 let result = restart_endpoint_inner(
645 configuration,
646 &mut backoff,
647 endpoint_id.clone(),
648 restart_endpoint_request.clone(),
649 )
650 .await;
651
652 match result {
653 Ok(result) => return Ok(result),
654 Err(Error::ResponseError(response)) => {
655 if !refreshed_credentials
656 && matches!(
657 response.status,
658 StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
659 )
660 {
661 match configuration.qcs_config.refresh().await {
663 Ok(_) => {
664 refreshed_credentials = true;
665 continue;
666 }
667 Err(::qcs_api_client_common::configuration::TokenError::Write {
668 error,
669 oauth_session: _,
670 }) => {
671 #[cfg(feature = "tracing")]
674 tracing::warn!(
675 "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
676 error
677 );
678 refreshed_credentials = true;
679 continue;
680 }
681 Err(e) => return Err(e.into()),
682 }
683 } else if let Some(duration) = response.retry_delay {
684 tokio::time::sleep(duration).await;
685 continue;
686 }
687
688 return Err(Error::ResponseError(response));
689 }
690 Err(Error::Reqwest(error)) => {
691 if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
692 tokio::time::sleep(duration).await;
693 continue;
694 }
695
696 return Err(Error::Reqwest(error));
697 }
698 Err(Error::Io(error)) => {
699 if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
700 tokio::time::sleep(duration).await;
701 continue;
702 }
703
704 return Err(Error::Io(error));
705 }
706 Err(error) => return Err(error),
707 }
708 }
709}