1#![allow(clippy::derive_partial_eq_without_eq)]
105#![allow(clippy::too_many_arguments)]
106#![allow(clippy::nonstandard_macro_braces)]
107#![allow(clippy::large_enum_variant)]
108#![allow(clippy::tabs_in_doc_comments)]
109#![allow(missing_docs)]
110#![cfg_attr(docsrs, feature(doc_cfg))]
111
112pub mod asps;
113pub mod channels;
114pub mod chromeosdevices;
115pub mod customer;
116pub mod customers;
117pub mod domain_aliases;
118pub mod domains;
119pub mod groups;
120pub mod members;
121pub mod mobiledevices;
122pub mod orgunits;
123pub mod privileges;
124pub mod resources;
125pub mod role_assignments;
126pub mod roles;
127pub mod schemas;
128pub mod tokens;
129pub mod two_step_verification;
130pub mod types;
131pub mod users;
132#[doc(hidden)]
133pub mod utils;
134pub mod verification_codes;
135
136pub use reqwest::{header::HeaderMap, StatusCode};
137
138#[derive(Debug)]
139pub struct Response<T> {
140 pub status: reqwest::StatusCode,
141 pub headers: reqwest::header::HeaderMap,
142 pub body: T,
143}
144
145impl<T> Response<T> {
146 pub fn new(status: reqwest::StatusCode, headers: reqwest::header::HeaderMap, body: T) -> Self {
147 Self {
148 status,
149 headers,
150 body,
151 }
152 }
153}
154
155type ClientResult<T> = Result<T, ClientError>;
156
157use thiserror::Error;
158
159#[derive(Debug, Error)]
161pub enum ClientError {
162 #[error("Refresh AuthToken is empty")]
165 EmptyRefreshToken,
166 #[error(transparent)]
168 FromUtf8Error(#[from] std::string::FromUtf8Error),
169 #[error(transparent)]
171 UrlParserError(#[from] url::ParseError),
172 #[error(transparent)]
174 SerdeJsonError(#[from] serde_json::Error),
175 #[error(transparent)]
177 ReqwestError(#[from] reqwest::Error),
178 #[error(transparent)]
180 InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
181 #[error(transparent)]
183 ReqwestMiddleWareError(#[from] reqwest_middleware::Error),
184 #[error("HTTP Error. Code: {status}, message: {error}")]
186 HttpError {
187 status: http::StatusCode,
188 headers: reqwest::header::HeaderMap,
189 error: String,
190 },
191}
192
193pub const FALLBACK_HOST: &str = "https://www.googleapis.com";
194
195mod progenitor_support {
196 use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
197
198 const PATH_SET: &AsciiSet = &CONTROLS
199 .add(b' ')
200 .add(b'"')
201 .add(b'#')
202 .add(b'<')
203 .add(b'>')
204 .add(b'?')
205 .add(b'`')
206 .add(b'{')
207 .add(b'}');
208
209 #[allow(dead_code)]
210 pub(crate) fn encode_path(pc: &str) -> String {
211 utf8_percent_encode(pc, PATH_SET).to_string()
212 }
213}
214
215#[derive(Debug, Default)]
216pub(crate) struct Message {
217 pub body: Option<reqwest::Body>,
218 pub content_type: Option<String>,
219}
220
221use std::convert::TryInto;
222use std::env;
223use std::ops::Add;
224use std::sync::Arc;
225use std::time::{Duration, Instant};
226use tokio::sync::RwLock;
227
228const TOKEN_ENDPOINT: &str = "https://oauth2.googleapis.com/token";
229const USER_CONSENT_ENDPOINT: &str = "https://accounts.google.com/o/oauth2/v2/auth";
230
231#[derive(Debug, Default, Clone)]
232pub struct RootDefaultServer {}
233
234impl RootDefaultServer {
235 pub fn default_url(&self) -> &str {
236 "https://www.googleapis.com"
237 }
238}
239
240#[derive(Clone)]
242pub struct Client {
243 host: String,
244 host_override: Option<String>,
245 token: Arc<RwLock<InnerToken>>,
246 client_id: String,
247 client_secret: String,
248 redirect_uri: String,
249
250 auto_refresh: bool,
251 client: reqwest_middleware::ClientWithMiddleware,
252}
253
254use schemars::JsonSchema;
255use serde::{Deserialize, Serialize};
256
257#[derive(Debug, JsonSchema, Clone, Default, Serialize, Deserialize)]
258pub struct AccessToken {
259 #[serde(
260 default,
261 skip_serializing_if = "String::is_empty",
262 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
263 )]
264 pub token_type: String,
265
266 #[serde(
267 default,
268 skip_serializing_if = "String::is_empty",
269 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
270 )]
271 pub access_token: String,
272 #[serde(default)]
273 pub expires_in: i64,
274
275 #[serde(
276 default,
277 skip_serializing_if = "String::is_empty",
278 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
279 )]
280 pub refresh_token: String,
281 #[serde(default, alias = "x_refresh_token_expires_in")]
282 pub refresh_token_expires_in: i64,
283
284 #[serde(
285 default,
286 skip_serializing_if = "String::is_empty",
287 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
288 )]
289 pub scope: String,
290}
291
292const REFRESH_THRESHOLD: Duration = Duration::from_secs(60);
296
297#[derive(Debug, Clone)]
298struct InnerToken {
299 access_token: String,
300 refresh_token: String,
301 expires_at: Option<Instant>,
302}
303
304impl Client {
305 pub fn new<I, K, R, T, Q>(
311 client_id: I,
312 client_secret: K,
313 redirect_uri: R,
314 token: T,
315 refresh_token: Q,
316 ) -> Self
317 where
318 I: ToString,
319 K: ToString,
320 R: ToString,
321 T: ToString,
322 Q: ToString,
323 {
324 let retry_policy =
326 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
327 let client = reqwest::Client::builder()
328 .redirect(reqwest::redirect::Policy::none())
329 .build();
330 match client {
331 Ok(c) => {
332 let client = reqwest_middleware::ClientBuilder::new(c)
333 .with(reqwest_tracing::TracingMiddleware::default())
335 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
337 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
338 |req: &reqwest::Request| req.try_clone().is_some(),
339 ))
340 .build();
341
342 let host = RootDefaultServer::default().default_url().to_string();
343
344 Client {
345 host,
346 host_override: None,
347 client_id: client_id.to_string(),
348 client_secret: client_secret.to_string(),
349 redirect_uri: redirect_uri.to_string(),
350 token: Arc::new(RwLock::new(InnerToken {
351 access_token: token.to_string(),
352 refresh_token: refresh_token.to_string(),
353 expires_at: None,
354 })),
355
356 auto_refresh: false,
357 client,
358 }
359 }
360 Err(e) => panic!("creating reqwest client failed: {:?}", e),
361 }
362 }
363
364 pub fn set_auto_access_token_refresh(&mut self, enabled: bool) -> &mut Self {
366 self.auto_refresh = enabled;
367 self
368 }
369
370 pub async fn set_expires_at(&self, expires_at: Option<Instant>) -> &Self {
376 self.token.write().await.expires_at = expires_at;
377 self
378 }
379
380 pub async fn expires_at(&self) -> Option<Instant> {
383 self.token.read().await.expires_at
384 }
385
386 pub async fn set_expires_in(&self, expires_in: i64) -> &Self {
389 self.token.write().await.expires_at = Self::compute_expires_at(expires_in);
390 self
391 }
392
393 pub async fn expires_in(&self) -> Option<Duration> {
396 self.token
397 .read()
398 .await
399 .expires_at
400 .map(|i| i.duration_since(Instant::now()))
401 }
402
403 pub async fn is_expired(&self) -> Option<bool> {
406 self.token
407 .read()
408 .await
409 .expires_at
410 .map(|expiration| expiration <= Instant::now())
411 }
412
413 fn compute_expires_at(expires_in: i64) -> Option<Instant> {
414 let seconds_valid = expires_in
415 .try_into()
416 .ok()
417 .map(Duration::from_secs)
418 .and_then(|dur| dur.checked_sub(REFRESH_THRESHOLD))
419 .or_else(|| Some(Duration::from_secs(0)));
420
421 seconds_valid.map(|seconds_valid| Instant::now().add(seconds_valid))
422 }
423
424 pub fn with_host_override<H>(&mut self, host: H) -> &mut Self
426 where
427 H: ToString,
428 {
429 self.host_override = Some(host.to_string());
430 self
431 }
432
433 pub fn remove_host_override(&mut self) -> &mut Self {
435 self.host_override = None;
436 self
437 }
438
439 pub fn get_host_override(&self) -> Option<&str> {
440 self.host_override.as_deref()
441 }
442
443 pub(crate) fn url(&self, path: &str, host: Option<&str>) -> String {
444 format!(
445 "{}{}",
446 self.get_host_override()
447 .or(host)
448 .unwrap_or(self.host.as_str()),
449 path
450 )
451 }
452
453 pub async fn new_from_env<T, R>(token: T, refresh_token: R) -> Self
464 where
465 T: ToString,
466 R: ToString,
467 {
468 use base64::{engine::general_purpose::STANDARD, Engine};
469
470 let google_key = env::var("GOOGLE_KEY_ENCODED").unwrap_or_default();
471 let decoded_google_key = STANDARD.decode(google_key).unwrap();
472 let secret = yup_oauth2::parse_application_secret(decoded_google_key)
473 .expect("failed to read from google credential env var");
474
475 let client = reqwest::Client::builder()
476 .redirect(reqwest::redirect::Policy::none())
477 .build();
478 let retry_policy =
479 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
480
481 match client {
482 Ok(c) => {
483 let client = reqwest_middleware::ClientBuilder::new(c)
484 .with(reqwest_tracing::TracingMiddleware::default())
486 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
488 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
489 |req: &reqwest::Request| req.try_clone().is_some(),
490 ))
491 .build();
492
493 let host = RootDefaultServer::default().default_url().to_string();
494
495 Client {
496 host,
497 host_override: None,
498 client_id: secret.client_id.to_string(),
499 client_secret: secret.client_secret.to_string(),
500 redirect_uri: secret.redirect_uris[0].to_string(),
501 token: Arc::new(RwLock::new(InnerToken {
502 access_token: token.to_string(),
503 refresh_token: refresh_token.to_string(),
504 expires_at: None,
505 })),
506 auto_refresh: false,
507 client,
508 }
509 }
510 Err(e) => panic!("creating reqwest client failed: {:?}", e),
511 }
512 }
513
514 pub fn user_consent_url(&self, scopes: &[String]) -> String {
517 let state = uuid::Uuid::new_v4();
518
519 let url = format!(
520 "{}?client_id={}&access_type=offline&response_type=code&redirect_uri={}&state={}",
521 USER_CONSENT_ENDPOINT, self.client_id, self.redirect_uri, state
522 );
523
524 if scopes.is_empty() {
525 return url;
526 }
527
528 format!("{}&scope={}", url, scopes.join(" "))
530 }
531
532 pub async fn refresh_access_token(&self) -> ClientResult<AccessToken> {
535 let response = {
536 let refresh_token = &self.token.read().await.refresh_token;
537
538 if refresh_token.is_empty() {
539 return Err(ClientError::EmptyRefreshToken);
540 }
541
542 let mut headers = reqwest::header::HeaderMap::new();
543 headers.append(
544 reqwest::header::ACCEPT,
545 reqwest::header::HeaderValue::from_static("application/json"),
546 );
547
548 let params = [
549 ("grant_type", "refresh_token"),
550 ("refresh_token", refresh_token),
551 ("client_id", &self.client_id),
552 ("client_secret", &self.client_secret),
553 ("redirect_uri", &self.redirect_uri),
554 ];
555 let client = reqwest::Client::new();
556 client
557 .post(TOKEN_ENDPOINT)
558 .headers(headers)
559 .form(¶ms)
560 .basic_auth(&self.client_id, Some(&self.client_secret))
561 .send()
562 .await?
563 };
564
565 let t: AccessToken = response.json().await?;
567
568 let refresh_token = self.token.read().await.refresh_token.clone();
569
570 *self.token.write().await = InnerToken {
571 access_token: t.access_token.clone(),
572 refresh_token,
573 expires_at: Self::compute_expires_at(t.expires_in),
574 };
575
576 Ok(t)
577 }
578
579 pub async fn get_access_token(&mut self, code: &str, state: &str) -> ClientResult<AccessToken> {
582 let mut headers = reqwest::header::HeaderMap::new();
583 headers.append(
584 reqwest::header::ACCEPT,
585 reqwest::header::HeaderValue::from_static("application/json"),
586 );
587
588 let params = [
589 ("grant_type", "authorization_code"),
590 ("code", code),
591 ("client_id", &self.client_id),
592 ("client_secret", &self.client_secret),
593 ("redirect_uri", &self.redirect_uri),
594 ("state", state),
595 ];
596 let client = reqwest::Client::new();
597 let resp = client
598 .post(TOKEN_ENDPOINT)
599 .headers(headers)
600 .form(¶ms)
601 .basic_auth(&self.client_id, Some(&self.client_secret))
602 .send()
603 .await?;
604
605 let t: AccessToken = resp.json().await?;
607
608 *self.token.write().await = InnerToken {
609 access_token: t.access_token.clone(),
610 refresh_token: t.refresh_token.clone(),
611 expires_at: Self::compute_expires_at(t.expires_in),
612 };
613
614 Ok(t)
615 }
616
617 async fn url_and_auth(&self, uri: &str) -> ClientResult<(reqwest::Url, Option<String>)> {
618 let parsed_url = uri.parse::<reqwest::Url>()?;
619
620 let auth = format!("Bearer {}", self.token.read().await.access_token);
621 Ok((parsed_url, Some(auth)))
622 }
623
624 async fn make_request(
625 &self,
626 method: &reqwest::Method,
627 uri: &str,
628 message: Message,
629 ) -> ClientResult<reqwest::Request> {
630 let (url, auth) = self.url_and_auth(uri).await?;
631
632 let instance = <&Client>::clone(&self);
633
634 let mut req = instance.client.request(method.clone(), url);
635
636 req = req.header(
638 reqwest::header::ACCEPT,
639 reqwest::header::HeaderValue::from_static("application/json"),
640 );
641
642 if let Some(content_type) = &message.content_type {
643 req = req.header(
644 reqwest::header::CONTENT_TYPE,
645 reqwest::header::HeaderValue::from_str(content_type).unwrap(),
646 );
647 } else {
648 req = req.header(
649 reqwest::header::CONTENT_TYPE,
650 reqwest::header::HeaderValue::from_static("application/json"),
651 );
652 }
653
654 if let Some(auth_str) = auth {
655 req = req.header(http::header::AUTHORIZATION, &*auth_str);
656 }
657
658 if let Some(body) = message.body {
659 req = req.body(body);
660 }
661
662 Ok(req.build()?)
663 }
664
665 async fn request_raw(
666 &self,
667 method: reqwest::Method,
668 uri: &str,
669 message: Message,
670 ) -> ClientResult<reqwest::Response> {
671 if self.auto_refresh {
672 let expired = self.is_expired().await;
673
674 match expired {
675 Some(true) => {
678 self.refresh_access_token().await?;
679 }
680
681 Some(false) => (),
686
687 None => (),
695 }
696 }
697
698 let req = self.make_request(&method, uri, message).await?;
699 let resp = self.client.execute(req).await?;
700
701 Ok(resp)
702 }
703
704 async fn request<Out>(
705 &self,
706 method: reqwest::Method,
707 uri: &str,
708 message: Message,
709 ) -> ClientResult<crate::Response<Out>>
710 where
711 Out: serde::de::DeserializeOwned + 'static + Send,
712 {
713 let response = self.request_raw(method, uri, message).await?;
714
715 let status = response.status();
716 let headers = response.headers().clone();
717
718 let response_body = response.bytes().await?;
719
720 if status.is_success() {
721 log::debug!("Received successful response. Read payload.");
722 let parsed_response = if status == http::StatusCode::NO_CONTENT
723 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
724 {
725 serde_json::from_str("null")?
726 } else {
727 serde_json::from_slice::<Out>(&response_body)?
728 };
729 Ok(crate::Response::new(status, headers, parsed_response))
730 } else {
731 let error = if response_body.is_empty() {
732 ClientError::HttpError {
733 status,
734 headers,
735 error: "empty response".into(),
736 }
737 } else {
738 ClientError::HttpError {
739 status,
740 headers,
741 error: String::from_utf8_lossy(&response_body).into(),
742 }
743 };
744
745 Err(error)
746 }
747 }
748
749 async fn request_with_links<Out>(
750 &self,
751 method: http::Method,
752 uri: &str,
753 message: Message,
754 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Out>)>
755 where
756 Out: serde::de::DeserializeOwned + 'static + Send,
757 {
758 let response = self.request_raw(method, uri, message).await?;
759
760 let status = response.status();
761 let headers = response.headers().clone();
762 let link = response
763 .headers()
764 .get(http::header::LINK)
765 .and_then(|l| l.to_str().ok())
766 .and_then(|l| parse_link_header::parse(l).ok())
767 .as_ref()
768 .and_then(crate::utils::next_link);
769
770 let response_body = response.bytes().await?;
771
772 if status.is_success() {
773 log::debug!("Received successful response. Read payload.");
774
775 let parsed_response = if status == http::StatusCode::NO_CONTENT
776 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
777 {
778 serde_json::from_str("null")?
779 } else {
780 serde_json::from_slice::<Out>(&response_body)?
781 };
782 Ok((link, crate::Response::new(status, headers, parsed_response)))
783 } else {
784 let error = if response_body.is_empty() {
785 ClientError::HttpError {
786 status,
787 headers,
788 error: "empty response".into(),
789 }
790 } else {
791 ClientError::HttpError {
792 status,
793 headers,
794 error: String::from_utf8_lossy(&response_body).into(),
795 }
796 };
797 Err(error)
798 }
799 }
800
801 #[allow(dead_code)]
803 async fn post_form<Out>(
804 &self,
805 uri: &str,
806 form: reqwest::multipart::Form,
807 ) -> ClientResult<crate::Response<Out>>
808 where
809 Out: serde::de::DeserializeOwned + 'static + Send,
810 {
811 let (url, auth) = self.url_and_auth(uri).await?;
812
813 let instance = <&Client>::clone(&self);
814
815 let mut req = instance.client.request(http::Method::POST, url);
816
817 req = req.header(
819 reqwest::header::ACCEPT,
820 reqwest::header::HeaderValue::from_static("application/json"),
821 );
822
823 if let Some(auth_str) = auth {
824 req = req.header(http::header::AUTHORIZATION, &*auth_str);
825 }
826
827 req = req.multipart(form);
828
829 let response = req.send().await?;
830
831 let status = response.status();
832 let headers = response.headers().clone();
833
834 let response_body = response.bytes().await?;
835
836 if status.is_success() {
837 log::debug!("Received successful response. Read payload.");
838 let parsed_response = if status == http::StatusCode::NO_CONTENT
839 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
840 {
841 serde_json::from_str("null")?
842 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
843 let s = String::from_utf8(response_body.to_vec())?;
845 serde_json::from_value(serde_json::json!(&s))?
846 } else {
847 serde_json::from_slice::<Out>(&response_body)?
848 };
849 Ok(crate::Response::new(status, headers, parsed_response))
850 } else {
851 let error = if response_body.is_empty() {
852 ClientError::HttpError {
853 status,
854 headers,
855 error: "empty response".into(),
856 }
857 } else {
858 ClientError::HttpError {
859 status,
860 headers,
861 error: String::from_utf8_lossy(&response_body).into(),
862 }
863 };
864
865 Err(error)
866 }
867 }
868
869 #[allow(dead_code)]
871 async fn request_with_accept_mime<Out>(
872 &self,
873 method: reqwest::Method,
874 uri: &str,
875 accept_mime_type: &str,
876 ) -> ClientResult<crate::Response<Out>>
877 where
878 Out: serde::de::DeserializeOwned + 'static + Send,
879 {
880 let (url, auth) = self.url_and_auth(uri).await?;
881
882 let instance = <&Client>::clone(&self);
883
884 let mut req = instance.client.request(method, url);
885
886 req = req.header(
888 reqwest::header::ACCEPT,
889 reqwest::header::HeaderValue::from_str(accept_mime_type)?,
890 );
891
892 if let Some(auth_str) = auth {
893 req = req.header(http::header::AUTHORIZATION, &*auth_str);
894 }
895
896 let response = req.send().await?;
897
898 let status = response.status();
899 let headers = response.headers().clone();
900
901 let response_body = response.bytes().await?;
902
903 if status.is_success() {
904 log::debug!("Received successful response. Read payload.");
905 let parsed_response = if status == http::StatusCode::NO_CONTENT
906 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
907 {
908 serde_json::from_str("null")?
909 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
910 let s = String::from_utf8(response_body.to_vec())?;
912 serde_json::from_value(serde_json::json!(&s))?
913 } else {
914 serde_json::from_slice::<Out>(&response_body)?
915 };
916 Ok(crate::Response::new(status, headers, parsed_response))
917 } else {
918 let error = if response_body.is_empty() {
919 ClientError::HttpError {
920 status,
921 headers,
922 error: "empty response".into(),
923 }
924 } else {
925 ClientError::HttpError {
926 status,
927 headers,
928 error: String::from_utf8_lossy(&response_body).into(),
929 }
930 };
931
932 Err(error)
933 }
934 }
935
936 #[allow(dead_code)]
938 async fn request_with_mime<Out>(
939 &self,
940 method: reqwest::Method,
941 uri: &str,
942 content: &[u8],
943 mime_type: &str,
944 ) -> ClientResult<crate::Response<Out>>
945 where
946 Out: serde::de::DeserializeOwned + 'static + Send,
947 {
948 let (url, auth) = self.url_and_auth(uri).await?;
949
950 let instance = <&Client>::clone(&self);
951
952 let mut req = instance.client.request(method, url);
953
954 req = req.header(
956 reqwest::header::ACCEPT,
957 reqwest::header::HeaderValue::from_static("application/json"),
958 );
959 req = req.header(
960 reqwest::header::CONTENT_TYPE,
961 reqwest::header::HeaderValue::from_bytes(mime_type.as_bytes()).unwrap(),
962 );
963 req = req.header(
965 reqwest::header::HeaderName::from_static("x-upload-content-type"),
966 reqwest::header::HeaderValue::from_static("application/octet-stream"),
967 );
968 req = req.header(
969 reqwest::header::HeaderName::from_static("x-upload-content-length"),
970 reqwest::header::HeaderValue::from_bytes(format!("{}", content.len()).as_bytes())
971 .unwrap(),
972 );
973
974 if let Some(auth_str) = auth {
975 req = req.header(http::header::AUTHORIZATION, &*auth_str);
976 }
977
978 if content.len() > 1 {
979 let b = bytes::Bytes::copy_from_slice(content);
980 req = req.body(b);
982 }
983
984 let response = req.send().await?;
985
986 let status = response.status();
987 let headers = response.headers().clone();
988
989 let response_body = response.bytes().await?;
990
991 if status.is_success() {
992 log::debug!("Received successful response. Read payload.");
993 let parsed_response = if status == http::StatusCode::NO_CONTENT
994 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
995 {
996 serde_json::from_str("null")?
997 } else {
998 serde_json::from_slice::<Out>(&response_body)?
999 };
1000 Ok(crate::Response::new(status, headers, parsed_response))
1001 } else {
1002 let error = if response_body.is_empty() {
1003 ClientError::HttpError {
1004 status,
1005 headers,
1006 error: "empty response".into(),
1007 }
1008 } else {
1009 ClientError::HttpError {
1010 status,
1011 headers,
1012 error: String::from_utf8_lossy(&response_body).into(),
1013 }
1014 };
1015
1016 Err(error)
1017 }
1018 }
1019
1020 async fn request_entity<D>(
1021 &self,
1022 method: http::Method,
1023 uri: &str,
1024 message: Message,
1025 ) -> ClientResult<crate::Response<D>>
1026 where
1027 D: serde::de::DeserializeOwned + 'static + Send,
1028 {
1029 let r = self.request(method, uri, message).await?;
1030 Ok(r)
1031 }
1032
1033 #[allow(dead_code)]
1034 async fn get<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1035 where
1036 D: serde::de::DeserializeOwned + 'static + Send,
1037 {
1038 self.request_entity(http::Method::GET, uri, message).await
1039 }
1040
1041 #[allow(dead_code)]
1042 async fn get_all_pages<D>(&self, uri: &str, _message: Message) -> ClientResult<Response<Vec<D>>>
1043 where
1044 D: serde::de::DeserializeOwned + 'static + Send,
1045 {
1046 self.unfold(uri).await
1048 }
1049
1050 #[allow(dead_code)]
1052 async fn unfold<D>(&self, uri: &str) -> ClientResult<crate::Response<Vec<D>>>
1053 where
1054 D: serde::de::DeserializeOwned + 'static + Send,
1055 {
1056 let mut global_items = Vec::new();
1057 let (new_link, mut response) = self.get_pages(uri).await?;
1058 let mut link = new_link;
1059 while !response.body.is_empty() {
1060 global_items.append(&mut response.body);
1061 if let Some(url) = &link {
1063 let url = reqwest::Url::parse(&url.0)?;
1064 let (new_link, new_response) = self.get_pages_url(&url).await?;
1065 link = new_link;
1066 response = new_response;
1067 }
1068 }
1069
1070 Ok(Response::new(
1071 response.status,
1072 response.headers,
1073 global_items,
1074 ))
1075 }
1076
1077 #[allow(dead_code)]
1078 async fn get_pages<D>(
1079 &self,
1080 uri: &str,
1081 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1082 where
1083 D: serde::de::DeserializeOwned + 'static + Send,
1084 {
1085 self.request_with_links(http::Method::GET, uri, Message::default())
1086 .await
1087 }
1088
1089 #[allow(dead_code)]
1090 async fn get_pages_url<D>(
1091 &self,
1092 url: &reqwest::Url,
1093 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1094 where
1095 D: serde::de::DeserializeOwned + 'static + Send,
1096 {
1097 self.request_with_links(http::Method::GET, url.as_str(), Message::default())
1098 .await
1099 }
1100
1101 #[allow(dead_code)]
1102 async fn post<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1103 where
1104 D: serde::de::DeserializeOwned + 'static + Send,
1105 {
1106 self.request_entity(http::Method::POST, uri, message).await
1107 }
1108
1109 #[allow(dead_code)]
1110 async fn patch<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1111 where
1112 D: serde::de::DeserializeOwned + 'static + Send,
1113 {
1114 self.request_entity(http::Method::PATCH, uri, message).await
1115 }
1116
1117 #[allow(dead_code)]
1118 async fn put<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1119 where
1120 D: serde::de::DeserializeOwned + 'static + Send,
1121 {
1122 self.request_entity(http::Method::PUT, uri, message).await
1123 }
1124
1125 #[allow(dead_code)]
1126 async fn delete<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1127 where
1128 D: serde::de::DeserializeOwned + 'static + Send,
1129 {
1130 self.request_entity(http::Method::DELETE, uri, message)
1131 .await
1132 }
1133
1134 pub fn asps(&self) -> asps::Asps {
1136 asps::Asps::new(self.clone())
1137 }
1138
1139 pub fn channels(&self) -> channels::Channels {
1141 channels::Channels::new(self.clone())
1142 }
1143
1144 pub fn chromeosdevices(&self) -> chromeosdevices::Chromeosdevices {
1146 chromeosdevices::Chromeosdevices::new(self.clone())
1147 }
1148
1149 pub fn customer(&self) -> customer::Customer {
1151 customer::Customer::new(self.clone())
1152 }
1153
1154 pub fn customers(&self) -> customers::Customers {
1156 customers::Customers::new(self.clone())
1157 }
1158
1159 pub fn domain_aliases(&self) -> domain_aliases::DomainAliases {
1161 domain_aliases::DomainAliases::new(self.clone())
1162 }
1163
1164 pub fn domains(&self) -> domains::Domains {
1166 domains::Domains::new(self.clone())
1167 }
1168
1169 pub fn groups(&self) -> groups::Groups {
1171 groups::Groups::new(self.clone())
1172 }
1173
1174 pub fn members(&self) -> members::Members {
1176 members::Members::new(self.clone())
1177 }
1178
1179 pub fn mobiledevices(&self) -> mobiledevices::Mobiledevices {
1181 mobiledevices::Mobiledevices::new(self.clone())
1182 }
1183
1184 pub fn orgunits(&self) -> orgunits::Orgunits {
1186 orgunits::Orgunits::new(self.clone())
1187 }
1188
1189 pub fn privileges(&self) -> privileges::Privileges {
1191 privileges::Privileges::new(self.clone())
1192 }
1193
1194 pub fn resources(&self) -> resources::Resources {
1196 resources::Resources::new(self.clone())
1197 }
1198
1199 pub fn role_assignments(&self) -> role_assignments::RoleAssignments {
1201 role_assignments::RoleAssignments::new(self.clone())
1202 }
1203
1204 pub fn roles(&self) -> roles::Roles {
1206 roles::Roles::new(self.clone())
1207 }
1208
1209 pub fn schemas(&self) -> schemas::Schemas {
1211 schemas::Schemas::new(self.clone())
1212 }
1213
1214 pub fn tokens(&self) -> tokens::Tokens {
1216 tokens::Tokens::new(self.clone())
1217 }
1218
1219 pub fn two_step_verification(&self) -> two_step_verification::TwoStepVerification {
1221 two_step_verification::TwoStepVerification::new(self.clone())
1222 }
1223
1224 pub fn users(&self) -> users::Users {
1226 users::Users::new(self.clone())
1227 }
1228
1229 pub fn verification_codes(&self) -> verification_codes::VerificationCodes {
1231 verification_codes::VerificationCodes::new(self.clone())
1232 }
1233}