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