qcs_api_client_openapi/apis/
translation_api.rs

1// Copyright 2022 Rigetti Computing
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*
16 * Rigetti QCS API
17 *
18 * # Introduction  This is the documentation for the Rigetti QCS HTTP API.  You can find out more about Rigetti at [https://rigetti.com](https://rigetti.com), and also interact with QCS via the web at [https://qcs.rigetti.com](https://qcs.rigetti.com).  This API is documented in **OpenAPI format** and so is compatible with the dozens of language-specific client generators available [here](https://github.com/OpenAPITools/openapi-generator) and elsewhere on the web.  # Principles  This API follows REST design principles where appropriate, and otherwise an HTTP RPC paradigm. We adhere to the Google [API Improvement Proposals](https://google.aip.dev/general) where reasonable to provide a consistent, intuitive developer experience. HTTP response codes match their specifications, and error messages fit a common format.  # Authentication  All access to the QCS API requires OAuth2 authentication provided by Okta. You can request access [here](https://www.rigetti.com/get-quantum). Once you have a user account, you can download your access token from QCS [here](https://qcs.rigetti.com/auth/token).   That access token is valid for 24 hours after issuance. The value of `access_token` within the JSON file is the token used for authentication (don't use the entire JSON file).  Authenticate requests using the `Authorization` header and a `Bearer` prefix:  ``` curl --header \"Authorization: Bearer eyJraW...Iow\" ```  # Quantum Processor Access  Access to the quantum processors themselves is not yet provided directly by this HTTP API, but is instead performed over ZeroMQ/[rpcq](https://github.com/rigetti/rpcq). Until that changes, we suggest using [pyquil](https://github.com/rigetti/pyquil) to build and execute quantum programs via the Legacy API.  # Legacy API  Our legacy HTTP API remains accessible at https://forest-server.qcs.rigetti.com, and it shares a source of truth with this API's services. You can use either service with the same user account and means of authentication. We strongly recommend using the API documented here, as the legacy API is on the path to deprecation.
19 *
20 * The version of the OpenAPI document: 2020-07-31
21 * Contact: support@rigetti.com
22 * Generated by: https://openapi-generator.tech
23 */
24
25use super::{configuration, Error};
26use crate::apis::ResponseContent;
27use ::qcs_api_client_common::backoff::{
28    duration_from_io_error, duration_from_reqwest_error, duration_from_response, ExponentialBackoff,
29};
30#[cfg(feature = "tracing")]
31use qcs_api_client_common::configuration::TokenRefresher;
32use reqwest::StatusCode;
33use serde::{Deserialize, Serialize};
34
35/// struct for typed errors of method [`get_quilt_calibrations`]
36#[derive(Debug, Clone, Serialize, Deserialize)]
37#[serde(untagged)]
38pub enum GetQuiltCalibrationsError {
39    Status404(crate::models::Error),
40    Status422(crate::models::ValidationError),
41    UnknownValue(serde_json::Value),
42}
43
44/// struct for typed errors of method [`translate_native_quil_to_encrypted_binary`]
45#[derive(Debug, Clone, Serialize, Deserialize)]
46#[serde(untagged)]
47pub enum TranslateNativeQuilToEncryptedBinaryError {
48    Status400(crate::models::Error),
49    Status404(crate::models::Error),
50    Status422(crate::models::ValidationError),
51    UnknownValue(serde_json::Value),
52}
53
54async fn get_quilt_calibrations_inner(
55    configuration: &configuration::Configuration,
56    backoff: &mut ExponentialBackoff,
57    quantum_processor_id: &str,
58) -> Result<crate::models::GetQuiltCalibrationsResponse, Error<GetQuiltCalibrationsError>> {
59    let local_var_configuration = configuration;
60
61    let local_var_client = &local_var_configuration.client;
62
63    let local_var_uri_str = format!(
64        "{}/v1/quantumProcessors/{quantumProcessorId}/quiltCalibrations",
65        local_var_configuration.qcs_config.api_url(),
66        quantumProcessorId = crate::apis::urlencode(quantum_processor_id)
67    );
68    let mut local_var_req_builder =
69        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
70
71    #[cfg(feature = "tracing")]
72    {
73        // Ignore parsing errors if the URL is invalid for some reason.
74        // If it is invalid, it will turn up as an error later when actually making the request.
75        let local_var_do_tracing =
76            local_var_uri_str
77                .parse::<::url::Url>()
78                .ok()
79                .map_or(true, |url| {
80                    configuration
81                        .qcs_config
82                        .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
83                });
84
85        if local_var_do_tracing {
86            ::tracing::debug!(
87                url=%local_var_uri_str,
88                method="GET",
89                "making get_quilt_calibrations request",
90            );
91        }
92    }
93
94    // Use the QCS Bearer token if a client OAuthSession is present,
95    // but do not require one when the security schema says it is optional.
96    {
97        use qcs_api_client_common::configuration::TokenError;
98
99        #[allow(
100            clippy::nonminimal_bool,
101            clippy::eq_op,
102            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
103        )]
104        let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
105
106        let token = local_var_configuration
107            .qcs_config
108            .get_bearer_access_token()
109            .await;
110
111        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
112            // the client is configured without any OAuthSession, but this call does not require one.
113            #[cfg(feature = "tracing")]
114            tracing::debug!(
115                "No client credentials found, but this call does not require authentication."
116            );
117        } else {
118            local_var_req_builder = local_var_req_builder.bearer_auth(token?);
119        }
120    }
121
122    let local_var_req = local_var_req_builder.build()?;
123    let local_var_resp = local_var_client.execute(local_var_req).await?;
124
125    let local_var_status = local_var_resp.status();
126
127    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
128        let local_var_content = local_var_resp.text().await?;
129        serde_json::from_str(&local_var_content).map_err(Error::from)
130    } else {
131        let local_var_retry_delay =
132            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
133        let local_var_content = local_var_resp.text().await?;
134        let local_var_entity: Option<GetQuiltCalibrationsError> =
135            serde_json::from_str(&local_var_content).ok();
136        let local_var_error = ResponseContent {
137            status: local_var_status,
138            content: local_var_content,
139            entity: local_var_entity,
140            retry_delay: local_var_retry_delay,
141        };
142        Err(Error::ResponseError(local_var_error))
143    }
144}
145
146/// Retrieve the calibration data used for client-side Quilt generation.
147pub async fn get_quilt_calibrations(
148    configuration: &configuration::Configuration,
149    quantum_processor_id: &str,
150) -> Result<crate::models::GetQuiltCalibrationsResponse, Error<GetQuiltCalibrationsError>> {
151    let mut backoff = configuration.backoff.clone();
152    let mut refreshed_credentials = false;
153    let method = reqwest::Method::GET;
154    loop {
155        let result =
156            get_quilt_calibrations_inner(configuration, &mut backoff, quantum_processor_id.clone())
157                .await;
158
159        match result {
160            Ok(result) => return Ok(result),
161            Err(Error::ResponseError(response)) => {
162                if !refreshed_credentials
163                    && matches!(
164                        response.status,
165                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
166                    )
167                {
168                    configuration.qcs_config.refresh().await?;
169                    refreshed_credentials = true;
170                    continue;
171                } else if let Some(duration) = response.retry_delay {
172                    tokio::time::sleep(duration).await;
173                    continue;
174                }
175
176                return Err(Error::ResponseError(response));
177            }
178            Err(Error::Reqwest(error)) => {
179                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
180                    tokio::time::sleep(duration).await;
181                    continue;
182                }
183
184                return Err(Error::Reqwest(error));
185            }
186            Err(Error::Io(error)) => {
187                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
188                    tokio::time::sleep(duration).await;
189                    continue;
190                }
191
192                return Err(Error::Io(error));
193            }
194            Err(error) => return Err(error),
195        }
196    }
197}
198async fn translate_native_quil_to_encrypted_binary_inner(
199    configuration: &configuration::Configuration,
200    backoff: &mut ExponentialBackoff,
201    quantum_processor_id: &str,
202    translate_native_quil_to_encrypted_binary_request: crate::models::TranslateNativeQuilToEncryptedBinaryRequest,
203) -> Result<
204    crate::models::TranslateNativeQuilToEncryptedBinaryResponse,
205    Error<TranslateNativeQuilToEncryptedBinaryError>,
206> {
207    let local_var_configuration = configuration;
208
209    let local_var_client = &local_var_configuration.client;
210
211    let local_var_uri_str = format!(
212        "{}/v1/quantumProcessors/{quantumProcessorId}:translateNativeQuilToEncryptedBinary",
213        local_var_configuration.qcs_config.api_url(),
214        quantumProcessorId = crate::apis::urlencode(quantum_processor_id)
215    );
216    let mut local_var_req_builder =
217        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
218
219    #[cfg(feature = "tracing")]
220    {
221        // Ignore parsing errors if the URL is invalid for some reason.
222        // If it is invalid, it will turn up as an error later when actually making the request.
223        let local_var_do_tracing =
224            local_var_uri_str
225                .parse::<::url::Url>()
226                .ok()
227                .map_or(true, |url| {
228                    configuration
229                        .qcs_config
230                        .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
231                });
232
233        if local_var_do_tracing {
234            ::tracing::debug!(
235                url=%local_var_uri_str,
236                method="POST",
237                "making translate_native_quil_to_encrypted_binary request",
238            );
239        }
240    }
241
242    // Use the QCS Bearer token if a client OAuthSession is present,
243    // but do not require one when the security schema says it is optional.
244    {
245        use qcs_api_client_common::configuration::TokenError;
246
247        #[allow(
248            clippy::nonminimal_bool,
249            clippy::eq_op,
250            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
251        )]
252        let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
253
254        let token = local_var_configuration
255            .qcs_config
256            .get_bearer_access_token()
257            .await;
258
259        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
260            // the client is configured without any OAuthSession, but this call does not require one.
261            #[cfg(feature = "tracing")]
262            tracing::debug!(
263                "No client credentials found, but this call does not require authentication."
264            );
265        } else {
266            local_var_req_builder = local_var_req_builder.bearer_auth(token?);
267        }
268    }
269
270    local_var_req_builder =
271        local_var_req_builder.json(&translate_native_quil_to_encrypted_binary_request);
272
273    let local_var_req = local_var_req_builder.build()?;
274    let local_var_resp = local_var_client.execute(local_var_req).await?;
275
276    let local_var_status = local_var_resp.status();
277
278    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
279        let local_var_content = local_var_resp.text().await?;
280        serde_json::from_str(&local_var_content).map_err(Error::from)
281    } else {
282        let local_var_retry_delay =
283            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
284        let local_var_content = local_var_resp.text().await?;
285        let local_var_entity: Option<TranslateNativeQuilToEncryptedBinaryError> =
286            serde_json::from_str(&local_var_content).ok();
287        let local_var_error = ResponseContent {
288            status: local_var_status,
289            content: local_var_content,
290            entity: local_var_entity,
291            retry_delay: local_var_retry_delay,
292        };
293        Err(Error::ResponseError(local_var_error))
294    }
295}
296
297/// Compile Rigetti-native Quil code to encrypted binary form, ready for execution on a Rigetti Quantum Processor.
298pub async fn translate_native_quil_to_encrypted_binary(
299    configuration: &configuration::Configuration,
300    quantum_processor_id: &str,
301    translate_native_quil_to_encrypted_binary_request: crate::models::TranslateNativeQuilToEncryptedBinaryRequest,
302) -> Result<
303    crate::models::TranslateNativeQuilToEncryptedBinaryResponse,
304    Error<TranslateNativeQuilToEncryptedBinaryError>,
305> {
306    let mut backoff = configuration.backoff.clone();
307    let mut refreshed_credentials = false;
308    let method = reqwest::Method::POST;
309    loop {
310        let result = translate_native_quil_to_encrypted_binary_inner(
311            configuration,
312            &mut backoff,
313            quantum_processor_id.clone(),
314            translate_native_quil_to_encrypted_binary_request.clone(),
315        )
316        .await;
317
318        match result {
319            Ok(result) => return Ok(result),
320            Err(Error::ResponseError(response)) => {
321                if !refreshed_credentials
322                    && matches!(
323                        response.status,
324                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
325                    )
326                {
327                    configuration.qcs_config.refresh().await?;
328                    refreshed_credentials = true;
329                    continue;
330                } else if let Some(duration) = response.retry_delay {
331                    tokio::time::sleep(duration).await;
332                    continue;
333                }
334
335                return Err(Error::ResponseError(response));
336            }
337            Err(Error::Reqwest(error)) => {
338                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
339                    tokio::time::sleep(duration).await;
340                    continue;
341                }
342
343                return Err(Error::Reqwest(error));
344            }
345            Err(Error::Io(error)) => {
346                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
347                    tokio::time::sleep(duration).await;
348                    continue;
349                }
350
351                return Err(Error::Io(error));
352            }
353            Err(error) => return Err(error),
354        }
355    }
356}