1#![allow(clippy::derive_partial_eq_without_eq)]
106#![allow(clippy::too_many_arguments)]
107#![allow(clippy::nonstandard_macro_braces)]
108#![allow(clippy::large_enum_variant)]
109#![allow(clippy::tabs_in_doc_comments)]
110#![allow(missing_docs)]
111#![cfg_attr(docsrs, feature(doc_cfg))]
112
113pub mod about;
114pub mod changes;
115pub mod channels;
116pub mod comments;
117pub mod drives;
118pub mod files;
119pub mod permissions;
120pub mod replies;
121pub mod revisions;
122pub mod teamdrives;
123pub mod traits;
124pub mod types;
125#[doc(hidden)]
126pub mod utils;
127
128pub use reqwest::{header::HeaderMap, StatusCode};
129
130#[derive(Debug)]
131pub struct Response<T> {
132 pub status: reqwest::StatusCode,
133 pub headers: reqwest::header::HeaderMap,
134 pub body: T,
135}
136
137impl<T> Response<T> {
138 pub fn new(status: reqwest::StatusCode, headers: reqwest::header::HeaderMap, body: T) -> Self {
139 Self {
140 status,
141 headers,
142 body,
143 }
144 }
145}
146
147type ClientResult<T> = Result<T, ClientError>;
148
149use thiserror::Error;
150
151#[derive(Debug, Error)]
153pub enum ClientError {
154 #[error("Refresh AuthToken is empty")]
157 EmptyRefreshToken,
158 #[error(transparent)]
160 FromUtf8Error(#[from] std::string::FromUtf8Error),
161
162 #[error("{name:?}: Drive not found")]
164 DriveNotFound { name: String },
165 #[error(transparent)]
167 ToStrError(#[from] reqwest::header::ToStrError),
168 #[error(transparent)]
170 UrlParserError(#[from] url::ParseError),
171 #[error(transparent)]
173 SerdeJsonError(#[from] serde_json::Error),
174 #[error(transparent)]
176 ReqwestError(#[from] reqwest::Error),
177 #[error(transparent)]
179 InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
180 #[cfg(feature = "middleware")]
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/drive/v3";
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/drive/v3"
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 #[cfg(feature = "middleware")]
252 client: reqwest_middleware::ClientWithMiddleware,
253 #[cfg(not(feature = "middleware"))]
254 client: reqwest::Client,
255}
256
257use schemars::JsonSchema;
258use serde::{Deserialize, Serialize};
259
260#[derive(Debug, JsonSchema, Clone, Default, Serialize, Deserialize)]
261pub struct AccessToken {
262 #[serde(
263 default,
264 skip_serializing_if = "String::is_empty",
265 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
266 )]
267 pub token_type: String,
268
269 #[serde(
270 default,
271 skip_serializing_if = "String::is_empty",
272 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
273 )]
274 pub access_token: String,
275 #[serde(default)]
276 pub expires_in: i64,
277
278 #[serde(
279 default,
280 skip_serializing_if = "String::is_empty",
281 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
282 )]
283 pub refresh_token: String,
284 #[serde(default, alias = "x_refresh_token_expires_in")]
285 pub refresh_token_expires_in: i64,
286
287 #[serde(
288 default,
289 skip_serializing_if = "String::is_empty",
290 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
291 )]
292 pub scope: String,
293}
294
295const REFRESH_THRESHOLD: Duration = Duration::from_secs(60);
299
300#[derive(Debug, Clone)]
301struct InnerToken {
302 access_token: String,
303 refresh_token: String,
304 expires_at: Option<Instant>,
305}
306
307impl Client {
308 pub fn new<I, K, R, T, Q>(
314 client_id: I,
315 client_secret: K,
316 redirect_uri: R,
317 token: T,
318 refresh_token: Q,
319 ) -> Self
320 where
321 I: ToString,
322 K: ToString,
323 R: ToString,
324 T: ToString,
325 Q: ToString,
326 {
327 let retry_policy =
329 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
330 let client = reqwest::Client::builder()
331 .redirect(reqwest::redirect::Policy::none())
332 .build();
333 match client {
334 Ok(c) => {
335 #[cfg(feature = "middleware")]
336 let client = {
337 reqwest_middleware::ClientBuilder::new(c)
338 .with(reqwest_tracing::TracingMiddleware::default())
340 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
342 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
343 |req: &reqwest::Request| req.try_clone().is_some(),
344 ))
345 .build()
346 };
347 #[cfg(not(feature = "middleware"))]
348 let client = c;
349
350 let host = RootDefaultServer::default().default_url().to_string();
351
352 Client {
353 host,
354 host_override: None,
355 client_id: client_id.to_string(),
356 client_secret: client_secret.to_string(),
357 redirect_uri: redirect_uri.to_string(),
358 token: Arc::new(RwLock::new(InnerToken {
359 access_token: token.to_string(),
360 refresh_token: refresh_token.to_string(),
361 expires_at: None,
362 })),
363
364 auto_refresh: false,
365 client,
366 }
367 }
368 Err(e) => panic!("creating reqwest client failed: {:?}", e),
369 }
370 }
371
372 pub fn set_auto_access_token_refresh(&mut self, enabled: bool) -> &mut Self {
374 self.auto_refresh = enabled;
375 self
376 }
377
378 pub async fn set_expires_at(&self, expires_at: Option<Instant>) -> &Self {
384 self.token.write().await.expires_at = expires_at;
385 self
386 }
387
388 pub async fn expires_at(&self) -> Option<Instant> {
391 self.token.read().await.expires_at
392 }
393
394 pub async fn set_expires_in(&self, expires_in: i64) -> &Self {
397 self.token.write().await.expires_at = Self::compute_expires_at(expires_in);
398 self
399 }
400
401 pub async fn expires_in(&self) -> Option<Duration> {
404 self.token
405 .read()
406 .await
407 .expires_at
408 .map(|i| i.duration_since(Instant::now()))
409 }
410
411 pub async fn is_expired(&self) -> Option<bool> {
414 self.token
415 .read()
416 .await
417 .expires_at
418 .map(|expiration| expiration <= Instant::now())
419 }
420
421 fn compute_expires_at(expires_in: i64) -> Option<Instant> {
422 let seconds_valid = expires_in
423 .try_into()
424 .ok()
425 .map(Duration::from_secs)
426 .and_then(|dur| dur.checked_sub(REFRESH_THRESHOLD))
427 .or_else(|| Some(Duration::from_secs(0)));
428
429 seconds_valid.map(|seconds_valid| Instant::now().add(seconds_valid))
430 }
431
432 pub fn with_host_override<H>(&mut self, host: H) -> &mut Self
434 where
435 H: ToString,
436 {
437 self.host_override = Some(host.to_string());
438 self
439 }
440
441 pub fn remove_host_override(&mut self) -> &mut Self {
443 self.host_override = None;
444 self
445 }
446
447 pub fn get_host_override(&self) -> Option<&str> {
448 self.host_override.as_deref()
449 }
450
451 pub(crate) fn url(&self, path: &str, host: Option<&str>) -> String {
452 format!(
453 "{}{}",
454 self.get_host_override()
455 .or(host)
456 .unwrap_or(self.host.as_str()),
457 path
458 )
459 }
460
461 pub async fn new_from_env<T, R>(token: T, refresh_token: R) -> Self
472 where
473 T: ToString,
474 R: ToString,
475 {
476 use base64::{engine::general_purpose::STANDARD, Engine};
477
478 let google_key = env::var("GOOGLE_KEY_ENCODED").unwrap_or_default();
479 let decoded_google_key = STANDARD.decode(google_key).unwrap();
480 let secret = yup_oauth2::parse_application_secret(decoded_google_key)
481 .expect("failed to read from google credential env var");
482
483 let client = reqwest::Client::builder()
484 .redirect(reqwest::redirect::Policy::none())
485 .build();
486 let retry_policy =
487 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
488
489 match client {
490 Ok(c) => {
491 #[cfg(feature = "middleware")]
492 let client = {
493 reqwest_middleware::ClientBuilder::new(c)
494 .with(reqwest_tracing::TracingMiddleware::default())
496 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
498 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
499 |req: &reqwest::Request| req.try_clone().is_some(),
500 ))
501 .build()
502 };
503 #[cfg(not(feature = "middleware"))]
504 let client = c;
505 let host = RootDefaultServer::default().default_url().to_string();
506
507 Client {
508 host,
509 host_override: None,
510 client_id: secret.client_id.to_string(),
511 client_secret: secret.client_secret.to_string(),
512 redirect_uri: secret.redirect_uris[0].to_string(),
513 token: Arc::new(RwLock::new(InnerToken {
514 access_token: token.to_string(),
515 refresh_token: refresh_token.to_string(),
516 expires_at: None,
517 })),
518 auto_refresh: false,
519 client,
520 }
521 }
522 Err(e) => panic!("creating reqwest client failed: {:?}", e),
523 }
524 }
525
526 pub fn user_consent_url(&self, scopes: &[String]) -> String {
529 let state = uuid::Uuid::new_v4();
530
531 let url = format!(
532 "{}?client_id={}&access_type=offline&response_type=code&redirect_uri={}&state={}",
533 USER_CONSENT_ENDPOINT, self.client_id, self.redirect_uri, state
534 );
535
536 if scopes.is_empty() {
537 return url;
538 }
539
540 format!("{}&scope={}", url, scopes.join(" "))
542 }
543
544 pub async fn refresh_access_token(&self) -> ClientResult<AccessToken> {
547 let response = {
548 let refresh_token = &self.token.read().await.refresh_token;
549
550 if refresh_token.is_empty() {
551 return Err(ClientError::EmptyRefreshToken);
552 }
553
554 let mut headers = reqwest::header::HeaderMap::new();
555 headers.append(
556 reqwest::header::ACCEPT,
557 reqwest::header::HeaderValue::from_static("application/json"),
558 );
559
560 let params = [
561 ("grant_type", "refresh_token"),
562 ("refresh_token", refresh_token),
563 ("client_id", &self.client_id),
564 ("client_secret", &self.client_secret),
565 ("redirect_uri", &self.redirect_uri),
566 ];
567 let client = reqwest::Client::new();
568 client
569 .post(TOKEN_ENDPOINT)
570 .headers(headers)
571 .form(¶ms)
572 .basic_auth(&self.client_id, Some(&self.client_secret))
573 .send()
574 .await?
575 };
576
577 let t: AccessToken = response.json().await?;
579
580 let refresh_token = self.token.read().await.refresh_token.clone();
581
582 *self.token.write().await = InnerToken {
583 access_token: t.access_token.clone(),
584 refresh_token,
585 expires_at: Self::compute_expires_at(t.expires_in),
586 };
587
588 Ok(t)
589 }
590
591 pub async fn get_access_token(&mut self, code: &str, state: &str) -> ClientResult<AccessToken> {
594 let mut headers = reqwest::header::HeaderMap::new();
595 headers.append(
596 reqwest::header::ACCEPT,
597 reqwest::header::HeaderValue::from_static("application/json"),
598 );
599
600 let params = [
601 ("grant_type", "authorization_code"),
602 ("code", code),
603 ("client_id", &self.client_id),
604 ("client_secret", &self.client_secret),
605 ("redirect_uri", &self.redirect_uri),
606 ("state", state),
607 ];
608 let client = reqwest::Client::new();
609 let resp = client
610 .post(TOKEN_ENDPOINT)
611 .headers(headers)
612 .form(¶ms)
613 .basic_auth(&self.client_id, Some(&self.client_secret))
614 .send()
615 .await?;
616
617 let t: AccessToken = resp.json().await?;
619
620 *self.token.write().await = InnerToken {
621 access_token: t.access_token.clone(),
622 refresh_token: t.refresh_token.clone(),
623 expires_at: Self::compute_expires_at(t.expires_in),
624 };
625
626 Ok(t)
627 }
628
629 async fn url_and_auth(&self, uri: &str) -> ClientResult<(reqwest::Url, Option<String>)> {
630 let parsed_url = uri.parse::<reqwest::Url>()?;
631
632 let auth = format!("Bearer {}", self.token.read().await.access_token);
633 Ok((parsed_url, Some(auth)))
634 }
635
636 async fn make_request(
637 &self,
638 method: &reqwest::Method,
639 uri: &str,
640 message: Message,
641 ) -> ClientResult<reqwest::Request> {
642 let (url, auth) = self.url_and_auth(uri).await?;
643
644 let instance = <&Client>::clone(&self);
645
646 let mut req = instance.client.request(method.clone(), url);
647
648 req = req.header(
650 reqwest::header::ACCEPT,
651 reqwest::header::HeaderValue::from_static("application/json"),
652 );
653
654 if let Some(content_type) = &message.content_type {
655 req = req.header(
656 reqwest::header::CONTENT_TYPE,
657 reqwest::header::HeaderValue::from_str(content_type).unwrap(),
658 );
659 } else {
660 req = req.header(
661 reqwest::header::CONTENT_TYPE,
662 reqwest::header::HeaderValue::from_static("application/json"),
663 );
664 }
665
666 if let Some(auth_str) = auth {
667 req = req.header(http::header::AUTHORIZATION, &*auth_str);
668 }
669
670 if let Some(body) = message.body {
671 req = req.body(body);
672 }
673
674 Ok(req.build()?)
675 }
676
677 async fn request_raw(
678 &self,
679 method: reqwest::Method,
680 uri: &str,
681 message: Message,
682 ) -> ClientResult<reqwest::Response> {
683 if self.auto_refresh {
684 let expired = self.is_expired().await;
685
686 match expired {
687 Some(true) => {
690 self.refresh_access_token().await?;
691 }
692
693 Some(false) => (),
698
699 None => (),
707 }
708 }
709
710 let req = self.make_request(&method, uri, message).await?;
711 let resp = self.client.execute(req).await?;
712
713 Ok(resp)
714 }
715
716 async fn request<Out>(
717 &self,
718 method: reqwest::Method,
719 uri: &str,
720 message: Message,
721 ) -> ClientResult<crate::Response<Out>>
722 where
723 Out: serde::de::DeserializeOwned + 'static + Send,
724 {
725 let response = self.request_raw(method, uri, message).await?;
726
727 let status = response.status();
728 let headers = response.headers().clone();
729
730 let response_body = response.bytes().await?;
731
732 if status.is_success() {
733 log::debug!("Received successful response. Read payload.");
734 let parsed_response = if status == http::StatusCode::NO_CONTENT
735 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
736 {
737 serde_json::from_str("null")?
738 } else {
739 serde_json::from_slice::<Out>(&response_body)?
740 };
741 Ok(crate::Response::new(status, headers, parsed_response))
742 } else {
743 let error = if response_body.is_empty() {
744 ClientError::HttpError {
745 status,
746 headers,
747 error: "empty response".into(),
748 }
749 } else {
750 ClientError::HttpError {
751 status,
752 headers,
753 error: String::from_utf8_lossy(&response_body).into(),
754 }
755 };
756
757 Err(error)
758 }
759 }
760
761 async fn request_with_links<Out>(
762 &self,
763 method: http::Method,
764 uri: &str,
765 message: Message,
766 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Out>)>
767 where
768 Out: serde::de::DeserializeOwned + 'static + Send,
769 {
770 let response = self.request_raw(method, uri, message).await?;
771
772 let status = response.status();
773 let headers = response.headers().clone();
774 let link = response
775 .headers()
776 .get(http::header::LINK)
777 .and_then(|l| l.to_str().ok())
778 .and_then(|l| parse_link_header::parse(l).ok())
779 .as_ref()
780 .and_then(crate::utils::next_link);
781
782 let response_body = response.bytes().await?;
783
784 if status.is_success() {
785 log::debug!("Received successful response. Read payload.");
786
787 let parsed_response = if status == http::StatusCode::NO_CONTENT
788 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
789 {
790 serde_json::from_str("null")?
791 } else {
792 serde_json::from_slice::<Out>(&response_body)?
793 };
794 Ok((link, crate::Response::new(status, headers, parsed_response)))
795 } else {
796 let error = if response_body.is_empty() {
797 ClientError::HttpError {
798 status,
799 headers,
800 error: "empty response".into(),
801 }
802 } else {
803 ClientError::HttpError {
804 status,
805 headers,
806 error: String::from_utf8_lossy(&response_body).into(),
807 }
808 };
809 Err(error)
810 }
811 }
812
813 #[allow(dead_code)]
815 async fn post_form<Out>(
816 &self,
817 uri: &str,
818 form: reqwest::multipart::Form,
819 ) -> ClientResult<crate::Response<Out>>
820 where
821 Out: serde::de::DeserializeOwned + 'static + Send,
822 {
823 let (url, auth) = self.url_and_auth(uri).await?;
824
825 let instance = <&Client>::clone(&self);
826
827 let mut req = instance.client.request(http::Method::POST, url);
828
829 req = req.header(
831 reqwest::header::ACCEPT,
832 reqwest::header::HeaderValue::from_static("application/json"),
833 );
834
835 if let Some(auth_str) = auth {
836 req = req.header(http::header::AUTHORIZATION, &*auth_str);
837 }
838
839 req = req.multipart(form);
840
841 let response = req.send().await?;
842
843 let status = response.status();
844 let headers = response.headers().clone();
845
846 let response_body = response.bytes().await?;
847
848 if status.is_success() {
849 log::debug!("Received successful response. Read payload.");
850 let parsed_response = if status == http::StatusCode::NO_CONTENT
851 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
852 {
853 serde_json::from_str("null")?
854 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
855 let s = String::from_utf8(response_body.to_vec())?;
857 serde_json::from_value(serde_json::json!(&s))?
858 } else {
859 serde_json::from_slice::<Out>(&response_body)?
860 };
861 Ok(crate::Response::new(status, headers, parsed_response))
862 } else {
863 let error = if response_body.is_empty() {
864 ClientError::HttpError {
865 status,
866 headers,
867 error: "empty response".into(),
868 }
869 } else {
870 ClientError::HttpError {
871 status,
872 headers,
873 error: String::from_utf8_lossy(&response_body).into(),
874 }
875 };
876
877 Err(error)
878 }
879 }
880
881 #[allow(dead_code)]
883 async fn request_with_accept_mime<Out>(
884 &self,
885 method: reqwest::Method,
886 uri: &str,
887 accept_mime_type: &str,
888 ) -> ClientResult<crate::Response<Out>>
889 where
890 Out: serde::de::DeserializeOwned + 'static + Send,
891 {
892 let (url, auth) = self.url_and_auth(uri).await?;
893
894 let instance = <&Client>::clone(&self);
895
896 let mut req = instance.client.request(method, url);
897
898 req = req.header(
900 reqwest::header::ACCEPT,
901 reqwest::header::HeaderValue::from_str(accept_mime_type)?,
902 );
903
904 if let Some(auth_str) = auth {
905 req = req.header(http::header::AUTHORIZATION, &*auth_str);
906 }
907
908 let response = req.send().await?;
909
910 let status = response.status();
911 let headers = response.headers().clone();
912
913 let response_body = response.bytes().await?;
914
915 if status.is_success() {
916 log::debug!("Received successful response. Read payload.");
917 let parsed_response = if status == http::StatusCode::NO_CONTENT
918 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
919 {
920 serde_json::from_str("null")?
921 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
922 let s = String::from_utf8(response_body.to_vec())?;
924 serde_json::from_value(serde_json::json!(&s))?
925 } else {
926 serde_json::from_slice::<Out>(&response_body)?
927 };
928 Ok(crate::Response::new(status, headers, parsed_response))
929 } else {
930 let error = if response_body.is_empty() {
931 ClientError::HttpError {
932 status,
933 headers,
934 error: "empty response".into(),
935 }
936 } else {
937 ClientError::HttpError {
938 status,
939 headers,
940 error: String::from_utf8_lossy(&response_body).into(),
941 }
942 };
943
944 Err(error)
945 }
946 }
947
948 #[allow(dead_code)]
950 async fn request_with_mime<Out>(
951 &self,
952 method: reqwest::Method,
953 uri: &str,
954 content: &[u8],
955 mime_type: &str,
956 ) -> ClientResult<crate::Response<Out>>
957 where
958 Out: serde::de::DeserializeOwned + 'static + Send,
959 {
960 let (url, auth) = self.url_and_auth(uri).await?;
961
962 let instance = <&Client>::clone(&self);
963
964 let mut req = instance.client.request(method, url);
965
966 req = req.header(
968 reqwest::header::ACCEPT,
969 reqwest::header::HeaderValue::from_static("application/json"),
970 );
971 req = req.header(
972 reqwest::header::CONTENT_TYPE,
973 reqwest::header::HeaderValue::from_bytes(mime_type.as_bytes()).unwrap(),
974 );
975 req = req.header(
977 reqwest::header::HeaderName::from_static("x-upload-content-type"),
978 reqwest::header::HeaderValue::from_static("application/octet-stream"),
979 );
980 req = req.header(
981 reqwest::header::HeaderName::from_static("x-upload-content-length"),
982 reqwest::header::HeaderValue::from_bytes(format!("{}", content.len()).as_bytes())
983 .unwrap(),
984 );
985
986 if let Some(auth_str) = auth {
987 req = req.header(http::header::AUTHORIZATION, &*auth_str);
988 }
989
990 if content.len() > 1 {
991 let b = bytes::Bytes::copy_from_slice(content);
992 req = req.body(b);
994 }
995
996 let response = req.send().await?;
997
998 let status = response.status();
999 let headers = response.headers().clone();
1000
1001 let response_body = response.bytes().await?;
1002
1003 if status.is_success() {
1004 log::debug!("Received successful response. Read payload.");
1005 let parsed_response = if status == http::StatusCode::NO_CONTENT
1006 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
1007 {
1008 serde_json::from_str("null")?
1009 } else {
1010 serde_json::from_slice::<Out>(&response_body)?
1011 };
1012 Ok(crate::Response::new(status, headers, parsed_response))
1013 } else {
1014 let error = if response_body.is_empty() {
1015 ClientError::HttpError {
1016 status,
1017 headers,
1018 error: "empty response".into(),
1019 }
1020 } else {
1021 ClientError::HttpError {
1022 status,
1023 headers,
1024 error: String::from_utf8_lossy(&response_body).into(),
1025 }
1026 };
1027
1028 Err(error)
1029 }
1030 }
1031
1032 async fn request_entity<D>(
1033 &self,
1034 method: http::Method,
1035 uri: &str,
1036 message: Message,
1037 ) -> ClientResult<crate::Response<D>>
1038 where
1039 D: serde::de::DeserializeOwned + 'static + Send,
1040 {
1041 let r = self.request(method, uri, message).await?;
1042 Ok(r)
1043 }
1044
1045 #[allow(dead_code)]
1046 async fn get<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1047 where
1048 D: serde::de::DeserializeOwned + 'static + Send,
1049 {
1050 self.request_entity(http::Method::GET, uri, message).await
1051 }
1052
1053 #[allow(dead_code)]
1054 async fn get_all_pages<D>(&self, uri: &str, _message: Message) -> ClientResult<Response<Vec<D>>>
1055 where
1056 D: serde::de::DeserializeOwned + 'static + Send,
1057 {
1058 self.unfold(uri).await
1060 }
1061
1062 #[allow(dead_code)]
1064 async fn unfold<D>(&self, uri: &str) -> ClientResult<crate::Response<Vec<D>>>
1065 where
1066 D: serde::de::DeserializeOwned + 'static + Send,
1067 {
1068 let mut global_items = Vec::new();
1069 let (new_link, mut response) = self.get_pages(uri).await?;
1070 let mut link = new_link;
1071 while !response.body.is_empty() {
1072 global_items.append(&mut response.body);
1073 if let Some(url) = &link {
1075 let url = reqwest::Url::parse(&url.0)?;
1076 let (new_link, new_response) = self.get_pages_url(&url).await?;
1077 link = new_link;
1078 response = new_response;
1079 }
1080 }
1081
1082 Ok(Response::new(
1083 response.status,
1084 response.headers,
1085 global_items,
1086 ))
1087 }
1088
1089 #[allow(dead_code)]
1090 async fn get_pages<D>(
1091 &self,
1092 uri: &str,
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, uri, Message::default())
1098 .await
1099 }
1100
1101 #[allow(dead_code)]
1102 async fn get_pages_url<D>(
1103 &self,
1104 url: &reqwest::Url,
1105 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1106 where
1107 D: serde::de::DeserializeOwned + 'static + Send,
1108 {
1109 self.request_with_links(http::Method::GET, url.as_str(), Message::default())
1110 .await
1111 }
1112
1113 #[allow(dead_code)]
1114 async fn post<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1115 where
1116 D: serde::de::DeserializeOwned + 'static + Send,
1117 {
1118 self.request_entity(http::Method::POST, uri, message).await
1119 }
1120
1121 #[allow(dead_code)]
1122 async fn patch<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1123 where
1124 D: serde::de::DeserializeOwned + 'static + Send,
1125 {
1126 self.request_entity(http::Method::PATCH, uri, message).await
1127 }
1128
1129 #[allow(dead_code)]
1130 async fn put<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1131 where
1132 D: serde::de::DeserializeOwned + 'static + Send,
1133 {
1134 self.request_entity(http::Method::PUT, uri, message).await
1135 }
1136
1137 #[allow(dead_code)]
1138 async fn delete<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1139 where
1140 D: serde::de::DeserializeOwned + 'static + Send,
1141 {
1142 self.request_entity(http::Method::DELETE, uri, message)
1143 .await
1144 }
1145
1146 pub fn about(&self) -> about::About {
1148 about::About::new(self.clone())
1149 }
1150
1151 pub fn changes(&self) -> changes::Changes {
1153 changes::Changes::new(self.clone())
1154 }
1155
1156 pub fn channels(&self) -> channels::Channels {
1158 channels::Channels::new(self.clone())
1159 }
1160
1161 pub fn comments(&self) -> comments::Comments {
1163 comments::Comments::new(self.clone())
1164 }
1165
1166 pub fn drives(&self) -> drives::Drives {
1168 drives::Drives::new(self.clone())
1169 }
1170
1171 pub fn files(&self) -> files::Files {
1173 files::Files::new(self.clone())
1174 }
1175
1176 pub fn permissions(&self) -> permissions::Permissions {
1178 permissions::Permissions::new(self.clone())
1179 }
1180
1181 pub fn replies(&self) -> replies::Replies {
1183 replies::Replies::new(self.clone())
1184 }
1185
1186 pub fn revisions(&self) -> revisions::Revisions {
1188 revisions::Revisions::new(self.clone())
1189 }
1190
1191 pub fn teamdrives(&self) -> teamdrives::Teamdrives {
1193 teamdrives::Teamdrives::new(self.clone())
1194 }
1195}