1#![allow(clippy::derive_partial_eq_without_eq)]
108#![allow(clippy::too_many_arguments)]
109#![allow(clippy::nonstandard_macro_braces)]
110#![allow(clippy::large_enum_variant)]
111#![allow(clippy::tabs_in_doc_comments)]
112#![allow(missing_docs)]
113#![cfg_attr(docsrs, feature(doc_cfg))]
114
115pub mod accounts;
116pub mod archiving;
117pub mod billing;
118pub mod chat_channels;
119pub mod chat_channels_account_level;
120pub mod chat_messages;
121pub mod chatbot_messages;
122pub mod cloud_recording;
123pub mod common_area_phones;
124pub mod contacts;
125pub mod dashboards;
126pub mod deprecated_api_endpoints;
127pub mod devices;
128pub mod groups;
129pub mod im_chat;
130pub mod im_groups;
131pub mod meetings;
132pub mod pac;
133pub mod phone;
134pub mod phone_auto_receptionists;
135pub mod phone_blocked_list;
136pub mod phone_call_queues;
137pub mod phone_devices;
138pub mod phone_reports;
139pub mod phone_shared_line_groups;
140pub mod phone_site;
141pub mod reports;
142pub mod roles;
143pub mod rooms;
144pub mod rooms_account;
145pub mod rooms_devices;
146pub mod rooms_location;
147pub mod sip_connected_audio;
148pub mod sip_phone;
149pub mod tracking_field;
150pub mod tsp;
151pub mod types;
152pub mod users;
153#[doc(hidden)]
154pub mod utils;
155pub mod webinars;
156
157pub use reqwest::{header::HeaderMap, StatusCode};
158
159#[derive(Debug)]
160pub struct Response<T> {
161 pub status: reqwest::StatusCode,
162 pub headers: reqwest::header::HeaderMap,
163 pub body: T,
164}
165
166impl<T> Response<T> {
167 pub fn new(status: reqwest::StatusCode, headers: reqwest::header::HeaderMap, body: T) -> Self {
168 Self {
169 status,
170 headers,
171 body,
172 }
173 }
174}
175
176type ClientResult<T> = Result<T, ClientError>;
177
178use thiserror::Error;
179
180#[derive(Debug, Error)]
182pub enum ClientError {
183 #[error("Refresh AuthToken is empty")]
186 EmptyRefreshToken,
187 #[error(transparent)]
189 FromUtf8Error(#[from] std::string::FromUtf8Error),
190 #[error(transparent)]
192 UrlParserError(#[from] url::ParseError),
193 #[error(transparent)]
195 SerdeJsonError(#[from] serde_json::Error),
196 #[error(transparent)]
198 ReqwestError(#[from] reqwest::Error),
199 #[error(transparent)]
201 InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
202 #[error(transparent)]
204 ReqwestMiddleWareError(#[from] reqwest_middleware::Error),
205 #[error("HTTP Error. Code: {status}, message: {error}")]
207 HttpError {
208 status: http::StatusCode,
209 headers: reqwest::header::HeaderMap,
210 error: String,
211 },
212}
213
214pub const FALLBACK_HOST: &str = "https://api.zoom.us/v2";
215
216mod progenitor_support {
217 use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
218
219 const PATH_SET: &AsciiSet = &CONTROLS
220 .add(b' ')
221 .add(b'"')
222 .add(b'#')
223 .add(b'<')
224 .add(b'>')
225 .add(b'?')
226 .add(b'`')
227 .add(b'{')
228 .add(b'}');
229
230 #[allow(dead_code)]
231 pub(crate) fn encode_path(pc: &str) -> String {
232 utf8_percent_encode(pc, PATH_SET).to_string()
233 }
234}
235
236#[derive(Debug, Default)]
237pub(crate) struct Message {
238 pub body: Option<reqwest::Body>,
239 pub content_type: Option<String>,
240}
241
242use std::convert::TryInto;
243use std::env;
244use std::ops::Add;
245use std::sync::Arc;
246use std::time::{Duration, Instant};
247use tokio::sync::RwLock;
248
249const TOKEN_ENDPOINT: &str = "https://zoom.us/oauth/token";
250const USER_CONSENT_ENDPOINT: &str = "https://zoom.us/oauth/authorize";
251
252#[derive(Clone)]
254pub struct Client {
255 host: String,
256 host_override: Option<String>,
257 token: Arc<RwLock<InnerToken>>,
258 client_id: String,
259 client_secret: String,
260 redirect_uri: String,
261
262 auto_refresh: bool,
263 client: reqwest_middleware::ClientWithMiddleware,
264}
265
266use schemars::JsonSchema;
267use serde::{Deserialize, Serialize};
268
269#[derive(Debug, JsonSchema, Clone, Default, Serialize, Deserialize)]
270pub struct AccessToken {
271 #[serde(
272 default,
273 skip_serializing_if = "String::is_empty",
274 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
275 )]
276 pub token_type: String,
277
278 #[serde(
279 default,
280 skip_serializing_if = "String::is_empty",
281 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
282 )]
283 pub access_token: String,
284 #[serde(default)]
285 pub 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 refresh_token: String,
293 #[serde(default, alias = "x_refresh_token_expires_in")]
294 pub refresh_token_expires_in: i64,
295
296 #[serde(
297 default,
298 skip_serializing_if = "String::is_empty",
299 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
300 )]
301 pub scope: String,
302}
303
304const REFRESH_THRESHOLD: Duration = Duration::from_secs(60);
308
309#[derive(Debug, Clone)]
310struct InnerToken {
311 access_token: String,
312 refresh_token: String,
313 expires_at: Option<Instant>,
314}
315
316impl Client {
317 pub fn new<I, K, R, T, Q>(
323 client_id: I,
324 client_secret: K,
325 redirect_uri: R,
326 token: T,
327 refresh_token: Q,
328 ) -> Self
329 where
330 I: ToString,
331 K: ToString,
332 R: ToString,
333 T: ToString,
334 Q: ToString,
335 {
336 let retry_policy =
338 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
339 let client = reqwest::Client::builder()
340 .redirect(reqwest::redirect::Policy::none())
341 .build();
342 match client {
343 Ok(c) => {
344 let client = reqwest_middleware::ClientBuilder::new(c)
345 .with(reqwest_tracing::TracingMiddleware::default())
347 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
349 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
350 |req: &reqwest::Request| req.try_clone().is_some(),
351 ))
352 .build();
353
354 let host = FALLBACK_HOST.to_string();
355
356 Client {
357 host,
358 host_override: None,
359 client_id: client_id.to_string(),
360 client_secret: client_secret.to_string(),
361 redirect_uri: redirect_uri.to_string(),
362 token: Arc::new(RwLock::new(InnerToken {
363 access_token: token.to_string(),
364 refresh_token: refresh_token.to_string(),
365 expires_at: None,
366 })),
367
368 auto_refresh: false,
369 client,
370 }
371 }
372 Err(e) => panic!("creating reqwest client failed: {:?}", e),
373 }
374 }
375
376 pub fn set_auto_access_token_refresh(&mut self, enabled: bool) -> &mut Self {
378 self.auto_refresh = enabled;
379 self
380 }
381
382 pub async fn set_expires_at(&self, expires_at: Option<Instant>) -> &Self {
388 self.token.write().await.expires_at = expires_at;
389 self
390 }
391
392 pub async fn expires_at(&self) -> Option<Instant> {
395 self.token.read().await.expires_at
396 }
397
398 pub async fn set_expires_in(&self, expires_in: i64) -> &Self {
401 self.token.write().await.expires_at = Self::compute_expires_at(expires_in);
402 self
403 }
404
405 pub async fn expires_in(&self) -> Option<Duration> {
408 self.token
409 .read()
410 .await
411 .expires_at
412 .map(|i| i.duration_since(Instant::now()))
413 }
414
415 pub async fn is_expired(&self) -> Option<bool> {
418 self.token
419 .read()
420 .await
421 .expires_at
422 .map(|expiration| expiration <= Instant::now())
423 }
424
425 fn compute_expires_at(expires_in: i64) -> Option<Instant> {
426 let seconds_valid = expires_in
427 .try_into()
428 .ok()
429 .map(Duration::from_secs)
430 .and_then(|dur| dur.checked_sub(REFRESH_THRESHOLD))
431 .or_else(|| Some(Duration::from_secs(0)));
432
433 seconds_valid.map(|seconds_valid| Instant::now().add(seconds_valid))
434 }
435
436 pub fn with_host_override<H>(&mut self, host: H) -> &mut Self
438 where
439 H: ToString,
440 {
441 self.host_override = Some(host.to_string());
442 self
443 }
444
445 pub fn remove_host_override(&mut self) -> &mut Self {
447 self.host_override = None;
448 self
449 }
450
451 pub fn get_host_override(&self) -> Option<&str> {
452 self.host_override.as_deref()
453 }
454
455 pub(crate) fn url(&self, path: &str, host: Option<&str>) -> String {
456 format!(
457 "{}{}",
458 self.get_host_override()
459 .or(host)
460 .unwrap_or(self.host.as_str()),
461 path
462 )
463 }
464
465 pub fn new_from_env<T, R>(token: T, refresh_token: R) -> Self
476 where
477 T: ToString,
478 R: ToString,
479 {
480 let client_id = env::var("ZOOM_CLIENT_ID").expect("must set ZOOM_CLIENT_ID");
481 let client_secret = env::var("ZOOM_CLIENT_SECRET").expect("must set ZOOM_CLIENT_SECRET");
482 let redirect_uri = env::var("ZOOM_REDIRECT_URI").expect("must set ZOOM_REDIRECT_URI");
483
484 Client::new(client_id, client_secret, redirect_uri, token, refresh_token)
485 }
486
487 pub fn user_consent_url(&self, scopes: &[String]) -> String {
490 let state = uuid::Uuid::new_v4();
491
492 let url = format!(
493 "{}?client_id={}&response_type=code&redirect_uri={}&state={}",
494 USER_CONSENT_ENDPOINT, self.client_id, self.redirect_uri, state
495 );
496
497 if scopes.is_empty() {
498 return url;
499 }
500
501 format!("{}&scope={}", url, scopes.join(" "))
503 }
504
505 pub async fn refresh_access_token(&self) -> ClientResult<AccessToken> {
508 let response = {
509 let refresh_token = &self.token.read().await.refresh_token;
510
511 if refresh_token.is_empty() {
512 return Err(ClientError::EmptyRefreshToken);
513 }
514
515 let mut headers = reqwest::header::HeaderMap::new();
516 headers.append(
517 reqwest::header::ACCEPT,
518 reqwest::header::HeaderValue::from_static("application/json"),
519 );
520
521 let params = [
522 ("grant_type", "refresh_token"),
523 ("refresh_token", refresh_token),
524 ("client_id", &self.client_id),
525 ("client_secret", &self.client_secret),
526 ("redirect_uri", &self.redirect_uri),
527 ];
528 let client = reqwest::Client::new();
529 client
530 .post(TOKEN_ENDPOINT)
531 .headers(headers)
532 .form(¶ms)
533 .basic_auth(&self.client_id, Some(&self.client_secret))
534 .send()
535 .await?
536 };
537
538 let t: AccessToken = response.json().await?;
540
541 let refresh_token = self.token.read().await.refresh_token.clone();
542
543 *self.token.write().await = InnerToken {
544 access_token: t.access_token.clone(),
545 refresh_token,
546 expires_at: Self::compute_expires_at(t.expires_in),
547 };
548
549 Ok(t)
550 }
551
552 pub async fn get_access_token(&mut self, code: &str, state: &str) -> ClientResult<AccessToken> {
555 let mut headers = reqwest::header::HeaderMap::new();
556 headers.append(
557 reqwest::header::ACCEPT,
558 reqwest::header::HeaderValue::from_static("application/json"),
559 );
560
561 let params = [
562 ("grant_type", "authorization_code"),
563 ("code", code),
564 ("client_id", &self.client_id),
565 ("client_secret", &self.client_secret),
566 ("redirect_uri", &self.redirect_uri),
567 ("state", state),
568 ];
569 let client = reqwest::Client::new();
570 let resp = client
571 .post(TOKEN_ENDPOINT)
572 .headers(headers)
573 .form(¶ms)
574 .basic_auth(&self.client_id, Some(&self.client_secret))
575 .send()
576 .await?;
577
578 let t: AccessToken = resp.json().await?;
580
581 *self.token.write().await = InnerToken {
582 access_token: t.access_token.clone(),
583 refresh_token: t.refresh_token.clone(),
584 expires_at: Self::compute_expires_at(t.expires_in),
585 };
586
587 Ok(t)
588 }
589
590 async fn url_and_auth(&self, uri: &str) -> ClientResult<(reqwest::Url, Option<String>)> {
591 let parsed_url = uri.parse::<reqwest::Url>()?;
592
593 let auth = format!("Bearer {}", self.token.read().await.access_token);
594 Ok((parsed_url, Some(auth)))
595 }
596
597 async fn make_request(
598 &self,
599 method: &reqwest::Method,
600 uri: &str,
601 message: Message,
602 ) -> ClientResult<reqwest::Request> {
603 let (url, auth) = self.url_and_auth(uri).await?;
604
605 let instance = <&Client>::clone(&self);
606
607 let mut req = instance.client.request(method.clone(), url);
608
609 req = req.header(
611 reqwest::header::ACCEPT,
612 reqwest::header::HeaderValue::from_static("application/json"),
613 );
614
615 if let Some(content_type) = &message.content_type {
616 req = req.header(
617 reqwest::header::CONTENT_TYPE,
618 reqwest::header::HeaderValue::from_str(content_type).unwrap(),
619 );
620 } else {
621 req = req.header(
622 reqwest::header::CONTENT_TYPE,
623 reqwest::header::HeaderValue::from_static("application/json"),
624 );
625 }
626
627 if let Some(auth_str) = auth {
628 req = req.header(http::header::AUTHORIZATION, &*auth_str);
629 }
630
631 if let Some(body) = message.body {
632 req = req.body(body);
633 }
634
635 Ok(req.build()?)
636 }
637
638 async fn request_raw(
639 &self,
640 method: reqwest::Method,
641 uri: &str,
642 message: Message,
643 ) -> ClientResult<reqwest::Response> {
644 if self.auto_refresh {
645 let expired = self.is_expired().await;
646
647 match expired {
648 Some(true) => {
651 self.refresh_access_token().await?;
652 }
653
654 Some(false) => (),
659
660 None => (),
668 }
669 }
670
671 let req = self.make_request(&method, uri, message).await?;
672 let resp = self.client.execute(req).await?;
673
674 Ok(resp)
675 }
676
677 async fn request<Out>(
678 &self,
679 method: reqwest::Method,
680 uri: &str,
681 message: Message,
682 ) -> ClientResult<crate::Response<Out>>
683 where
684 Out: serde::de::DeserializeOwned + 'static + Send,
685 {
686 let response = self.request_raw(method, uri, message).await?;
687
688 let status = response.status();
689 let headers = response.headers().clone();
690
691 let response_body = response.bytes().await?;
692
693 if status.is_success() {
694 log::debug!("Received successful response. Read payload.");
695 let parsed_response = if status == http::StatusCode::NO_CONTENT
696 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
697 {
698 serde_json::from_str("null")?
699 } else {
700 serde_json::from_slice::<Out>(&response_body)?
701 };
702 Ok(crate::Response::new(status, headers, parsed_response))
703 } else {
704 let error = if response_body.is_empty() {
705 ClientError::HttpError {
706 status,
707 headers,
708 error: "empty response".into(),
709 }
710 } else {
711 ClientError::HttpError {
712 status,
713 headers,
714 error: String::from_utf8_lossy(&response_body).into(),
715 }
716 };
717
718 Err(error)
719 }
720 }
721
722 async fn request_with_links<Out>(
723 &self,
724 method: http::Method,
725 uri: &str,
726 message: Message,
727 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Out>)>
728 where
729 Out: serde::de::DeserializeOwned + 'static + Send,
730 {
731 let response = self.request_raw(method, uri, message).await?;
732
733 let status = response.status();
734 let headers = response.headers().clone();
735 let link = response
736 .headers()
737 .get(http::header::LINK)
738 .and_then(|l| l.to_str().ok())
739 .and_then(|l| parse_link_header::parse(l).ok())
740 .as_ref()
741 .and_then(crate::utils::next_link);
742
743 let response_body = response.bytes().await?;
744
745 if status.is_success() {
746 log::debug!("Received successful response. Read payload.");
747
748 let parsed_response = if status == http::StatusCode::NO_CONTENT
749 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
750 {
751 serde_json::from_str("null")?
752 } else {
753 serde_json::from_slice::<Out>(&response_body)?
754 };
755 Ok((link, crate::Response::new(status, headers, parsed_response)))
756 } else {
757 let error = if response_body.is_empty() {
758 ClientError::HttpError {
759 status,
760 headers,
761 error: "empty response".into(),
762 }
763 } else {
764 ClientError::HttpError {
765 status,
766 headers,
767 error: String::from_utf8_lossy(&response_body).into(),
768 }
769 };
770 Err(error)
771 }
772 }
773
774 #[allow(dead_code)]
776 async fn post_form<Out>(
777 &self,
778 uri: &str,
779 form: reqwest::multipart::Form,
780 ) -> ClientResult<crate::Response<Out>>
781 where
782 Out: serde::de::DeserializeOwned + 'static + Send,
783 {
784 let (url, auth) = self.url_and_auth(uri).await?;
785
786 let instance = <&Client>::clone(&self);
787
788 let mut req = instance.client.request(http::Method::POST, url);
789
790 req = req.header(
792 reqwest::header::ACCEPT,
793 reqwest::header::HeaderValue::from_static("application/json"),
794 );
795
796 if let Some(auth_str) = auth {
797 req = req.header(http::header::AUTHORIZATION, &*auth_str);
798 }
799
800 req = req.multipart(form);
801
802 let response = req.send().await?;
803
804 let status = response.status();
805 let headers = response.headers().clone();
806
807 let response_body = response.bytes().await?;
808
809 if status.is_success() {
810 log::debug!("Received successful response. Read payload.");
811 let parsed_response = if status == http::StatusCode::NO_CONTENT
812 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
813 {
814 serde_json::from_str("null")?
815 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
816 let s = String::from_utf8(response_body.to_vec())?;
818 serde_json::from_value(serde_json::json!(&s))?
819 } else {
820 serde_json::from_slice::<Out>(&response_body)?
821 };
822 Ok(crate::Response::new(status, headers, parsed_response))
823 } else {
824 let error = if response_body.is_empty() {
825 ClientError::HttpError {
826 status,
827 headers,
828 error: "empty response".into(),
829 }
830 } else {
831 ClientError::HttpError {
832 status,
833 headers,
834 error: String::from_utf8_lossy(&response_body).into(),
835 }
836 };
837
838 Err(error)
839 }
840 }
841
842 #[allow(dead_code)]
844 async fn request_with_accept_mime<Out>(
845 &self,
846 method: reqwest::Method,
847 uri: &str,
848 accept_mime_type: &str,
849 ) -> ClientResult<crate::Response<Out>>
850 where
851 Out: serde::de::DeserializeOwned + 'static + Send,
852 {
853 let (url, auth) = self.url_and_auth(uri).await?;
854
855 let instance = <&Client>::clone(&self);
856
857 let mut req = instance.client.request(method, url);
858
859 req = req.header(
861 reqwest::header::ACCEPT,
862 reqwest::header::HeaderValue::from_str(accept_mime_type)?,
863 );
864
865 if let Some(auth_str) = auth {
866 req = req.header(http::header::AUTHORIZATION, &*auth_str);
867 }
868
869 let response = req.send().await?;
870
871 let status = response.status();
872 let headers = response.headers().clone();
873
874 let response_body = response.bytes().await?;
875
876 if status.is_success() {
877 log::debug!("Received successful response. Read payload.");
878 let parsed_response = if status == http::StatusCode::NO_CONTENT
879 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
880 {
881 serde_json::from_str("null")?
882 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
883 let s = String::from_utf8(response_body.to_vec())?;
885 serde_json::from_value(serde_json::json!(&s))?
886 } else {
887 serde_json::from_slice::<Out>(&response_body)?
888 };
889 Ok(crate::Response::new(status, headers, parsed_response))
890 } else {
891 let error = if response_body.is_empty() {
892 ClientError::HttpError {
893 status,
894 headers,
895 error: "empty response".into(),
896 }
897 } else {
898 ClientError::HttpError {
899 status,
900 headers,
901 error: String::from_utf8_lossy(&response_body).into(),
902 }
903 };
904
905 Err(error)
906 }
907 }
908
909 #[allow(dead_code)]
911 async fn request_with_mime<Out>(
912 &self,
913 method: reqwest::Method,
914 uri: &str,
915 content: &[u8],
916 mime_type: &str,
917 ) -> ClientResult<crate::Response<Out>>
918 where
919 Out: serde::de::DeserializeOwned + 'static + Send,
920 {
921 let (url, auth) = self.url_and_auth(uri).await?;
922
923 let instance = <&Client>::clone(&self);
924
925 let mut req = instance.client.request(method, url);
926
927 req = req.header(
929 reqwest::header::ACCEPT,
930 reqwest::header::HeaderValue::from_static("application/json"),
931 );
932 req = req.header(
933 reqwest::header::CONTENT_TYPE,
934 reqwest::header::HeaderValue::from_bytes(mime_type.as_bytes()).unwrap(),
935 );
936 req = req.header(
938 reqwest::header::HeaderName::from_static("x-upload-content-type"),
939 reqwest::header::HeaderValue::from_static("application/octet-stream"),
940 );
941 req = req.header(
942 reqwest::header::HeaderName::from_static("x-upload-content-length"),
943 reqwest::header::HeaderValue::from_bytes(format!("{}", content.len()).as_bytes())
944 .unwrap(),
945 );
946
947 if let Some(auth_str) = auth {
948 req = req.header(http::header::AUTHORIZATION, &*auth_str);
949 }
950
951 if content.len() > 1 {
952 let b = bytes::Bytes::copy_from_slice(content);
953 req = req.body(b);
955 }
956
957 let response = req.send().await?;
958
959 let status = response.status();
960 let headers = response.headers().clone();
961
962 let response_body = response.bytes().await?;
963
964 if status.is_success() {
965 log::debug!("Received successful response. Read payload.");
966 let parsed_response = if status == http::StatusCode::NO_CONTENT
967 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
968 {
969 serde_json::from_str("null")?
970 } else {
971 serde_json::from_slice::<Out>(&response_body)?
972 };
973 Ok(crate::Response::new(status, headers, parsed_response))
974 } else {
975 let error = if response_body.is_empty() {
976 ClientError::HttpError {
977 status,
978 headers,
979 error: "empty response".into(),
980 }
981 } else {
982 ClientError::HttpError {
983 status,
984 headers,
985 error: String::from_utf8_lossy(&response_body).into(),
986 }
987 };
988
989 Err(error)
990 }
991 }
992
993 async fn request_entity<D>(
994 &self,
995 method: http::Method,
996 uri: &str,
997 message: Message,
998 ) -> ClientResult<crate::Response<D>>
999 where
1000 D: serde::de::DeserializeOwned + 'static + Send,
1001 {
1002 let r = self.request(method, uri, message).await?;
1003 Ok(r)
1004 }
1005
1006 #[allow(dead_code)]
1007 async fn get<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1008 where
1009 D: serde::de::DeserializeOwned + 'static + Send,
1010 {
1011 self.request_entity(http::Method::GET, uri, message).await
1012 }
1013
1014 #[allow(dead_code)]
1015 async fn get_all_pages<D>(&self, uri: &str, _message: Message) -> ClientResult<Response<Vec<D>>>
1016 where
1017 D: serde::de::DeserializeOwned + 'static + Send,
1018 {
1019 self.unfold(uri).await
1021 }
1022
1023 #[allow(dead_code)]
1025 async fn unfold<D>(&self, uri: &str) -> ClientResult<crate::Response<Vec<D>>>
1026 where
1027 D: serde::de::DeserializeOwned + 'static + Send,
1028 {
1029 let mut global_items = Vec::new();
1030 let (new_link, mut response) = self.get_pages(uri).await?;
1031 let mut link = new_link;
1032 while !response.body.is_empty() {
1033 global_items.append(&mut response.body);
1034 if let Some(url) = &link {
1036 let url = reqwest::Url::parse(&url.0)?;
1037 let (new_link, new_response) = self.get_pages_url(&url).await?;
1038 link = new_link;
1039 response = new_response;
1040 }
1041 }
1042
1043 Ok(Response::new(
1044 response.status,
1045 response.headers,
1046 global_items,
1047 ))
1048 }
1049
1050 #[allow(dead_code)]
1051 async fn get_pages<D>(
1052 &self,
1053 uri: &str,
1054 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1055 where
1056 D: serde::de::DeserializeOwned + 'static + Send,
1057 {
1058 self.request_with_links(http::Method::GET, uri, Message::default())
1059 .await
1060 }
1061
1062 #[allow(dead_code)]
1063 async fn get_pages_url<D>(
1064 &self,
1065 url: &reqwest::Url,
1066 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1067 where
1068 D: serde::de::DeserializeOwned + 'static + Send,
1069 {
1070 self.request_with_links(http::Method::GET, url.as_str(), Message::default())
1071 .await
1072 }
1073
1074 #[allow(dead_code)]
1075 async fn post<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1076 where
1077 D: serde::de::DeserializeOwned + 'static + Send,
1078 {
1079 self.request_entity(http::Method::POST, uri, message).await
1080 }
1081
1082 #[allow(dead_code)]
1083 async fn patch<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1084 where
1085 D: serde::de::DeserializeOwned + 'static + Send,
1086 {
1087 self.request_entity(http::Method::PATCH, uri, message).await
1088 }
1089
1090 #[allow(dead_code)]
1091 async fn put<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1092 where
1093 D: serde::de::DeserializeOwned + 'static + Send,
1094 {
1095 self.request_entity(http::Method::PUT, uri, message).await
1096 }
1097
1098 #[allow(dead_code)]
1099 async fn delete<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1100 where
1101 D: serde::de::DeserializeOwned + 'static + Send,
1102 {
1103 self.request_entity(http::Method::DELETE, uri, message)
1104 .await
1105 }
1106
1107 pub fn accounts(&self) -> accounts::Accounts {
1108 accounts::Accounts::new(self.clone())
1109 }
1110
1111 pub fn archiving(&self) -> archiving::Archiving {
1112 archiving::Archiving::new(self.clone())
1113 }
1114
1115 pub fn billing(&self) -> billing::Billing {
1116 billing::Billing::new(self.clone())
1117 }
1118
1119 pub fn chat_channels(&self) -> chat_channels::ChatChannels {
1120 chat_channels::ChatChannels::new(self.clone())
1121 }
1122
1123 pub fn chat_channels_account_level(
1124 &self,
1125 ) -> chat_channels_account_level::ChatChannelsAccountLevel {
1126 chat_channels_account_level::ChatChannelsAccountLevel::new(self.clone())
1127 }
1128
1129 pub fn chat_messages(&self) -> chat_messages::ChatMessages {
1130 chat_messages::ChatMessages::new(self.clone())
1131 }
1132
1133 pub fn chatbot_messages(&self) -> chatbot_messages::ChatbotMessages {
1134 chatbot_messages::ChatbotMessages::new(self.clone())
1135 }
1136
1137 pub fn cloud_recording(&self) -> cloud_recording::CloudRecording {
1138 cloud_recording::CloudRecording::new(self.clone())
1139 }
1140
1141 pub fn common_area_phones(&self) -> common_area_phones::CommonAreaPhones {
1142 common_area_phones::CommonAreaPhones::new(self.clone())
1143 }
1144
1145 pub fn contacts(&self) -> contacts::Contacts {
1146 contacts::Contacts::new(self.clone())
1147 }
1148
1149 pub fn dashboards(&self) -> dashboards::Dashboards {
1150 dashboards::Dashboards::new(self.clone())
1151 }
1152
1153 pub fn deprecated_api_endpoints(&self) -> deprecated_api_endpoints::DeprecatedApiEndpoints {
1154 deprecated_api_endpoints::DeprecatedApiEndpoints::new(self.clone())
1155 }
1156
1157 pub fn devices(&self) -> devices::Devices {
1158 devices::Devices::new(self.clone())
1159 }
1160
1161 pub fn groups(&self) -> groups::Groups {
1162 groups::Groups::new(self.clone())
1163 }
1164
1165 pub fn im_chat(&self) -> im_chat::ImChat {
1166 im_chat::ImChat::new(self.clone())
1167 }
1168
1169 pub fn im_groups(&self) -> im_groups::ImGroups {
1170 im_groups::ImGroups::new(self.clone())
1171 }
1172
1173 pub fn meetings(&self) -> meetings::Meetings {
1174 meetings::Meetings::new(self.clone())
1175 }
1176
1177 pub fn pac(&self) -> pac::Pac {
1178 pac::Pac::new(self.clone())
1179 }
1180
1181 pub fn phone(&self) -> phone::Phone {
1182 phone::Phone::new(self.clone())
1183 }
1184
1185 pub fn phone_auto_receptionists(&self) -> phone_auto_receptionists::PhoneAutoReceptionists {
1186 phone_auto_receptionists::PhoneAutoReceptionists::new(self.clone())
1187 }
1188
1189 pub fn phone_blocked_list(&self) -> phone_blocked_list::PhoneBlockedList {
1190 phone_blocked_list::PhoneBlockedList::new(self.clone())
1191 }
1192
1193 pub fn phone_call_queues(&self) -> phone_call_queues::PhoneCallQueues {
1194 phone_call_queues::PhoneCallQueues::new(self.clone())
1195 }
1196
1197 pub fn phone_devices(&self) -> phone_devices::PhoneDevices {
1198 phone_devices::PhoneDevices::new(self.clone())
1199 }
1200
1201 pub fn phone_reports(&self) -> phone_reports::PhoneReports {
1202 phone_reports::PhoneReports::new(self.clone())
1203 }
1204
1205 pub fn phone_shared_line_groups(&self) -> phone_shared_line_groups::PhoneSharedLineGroups {
1206 phone_shared_line_groups::PhoneSharedLineGroups::new(self.clone())
1207 }
1208
1209 pub fn phone_site(&self) -> phone_site::PhoneSite {
1210 phone_site::PhoneSite::new(self.clone())
1211 }
1212
1213 pub fn reports(&self) -> reports::Reports {
1214 reports::Reports::new(self.clone())
1215 }
1216
1217 pub fn roles(&self) -> roles::Roles {
1218 roles::Roles::new(self.clone())
1219 }
1220
1221 pub fn rooms(&self) -> rooms::Rooms {
1222 rooms::Rooms::new(self.clone())
1223 }
1224
1225 pub fn rooms_account(&self) -> rooms_account::RoomsAccount {
1226 rooms_account::RoomsAccount::new(self.clone())
1227 }
1228
1229 pub fn rooms_devices(&self) -> rooms_devices::RoomsDevices {
1230 rooms_devices::RoomsDevices::new(self.clone())
1231 }
1232
1233 pub fn rooms_location(&self) -> rooms_location::RoomsLocation {
1234 rooms_location::RoomsLocation::new(self.clone())
1235 }
1236
1237 pub fn sip_connected_audio(&self) -> sip_connected_audio::SipConnectedAudio {
1238 sip_connected_audio::SipConnectedAudio::new(self.clone())
1239 }
1240
1241 pub fn sip_phone(&self) -> sip_phone::SipPhone {
1242 sip_phone::SipPhone::new(self.clone())
1243 }
1244
1245 pub fn tracking_field(&self) -> tracking_field::TrackingField {
1246 tracking_field::TrackingField::new(self.clone())
1247 }
1248
1249 pub fn tsp(&self) -> tsp::Tsp {
1250 tsp::Tsp::new(self.clone())
1251 }
1252
1253 pub fn users(&self) -> users::Users {
1254 users::Users::new(self.clone())
1255 }
1256
1257 pub fn webinars(&self) -> webinars::Webinars {
1258 webinars::Webinars::new(self.clone())
1259 }
1260}