rust_wistia/api/upload/
client.rs1use crate::constants::{ENV_VAR_NAME, UPLOAD_API};
2use crate::https::{get_https_client, tls};
3use crate::log::debug;
4use crate::models::*;
5use crate::status::raise_for_status;
6use crate::types::Result;
7use crate::utils::into_struct_from_slice;
8use crate::RustWistiaError;
9
10use std::env::var;
11use std::time::Instant;
12
13use hyper::body::HttpBody;
14use hyper::client::HttpConnector;
15use hyper::{Body, Client, Request};
16use serde_urlencoded::to_string;
17
18#[derive(Clone)]
30pub struct UploadClient<B = Body> {
31 pub access_token: String,
37 client: Client<tls::HttpsConnector<HttpConnector>, B>,
39}
40
41impl<B: HttpBody + Send + 'static> From<String> for UploadClient<B>
42where
43 <B as HttpBody>::Data: Send,
44 <B as HttpBody>::Error: Into<Box<(dyn std::error::Error + Send + Sync + 'static)>>,
45{
46 fn from(token: String) -> Self {
48 Self {
49 access_token: token,
50 client: get_https_client(),
51 }
52 }
53}
54
55impl<B: HttpBody + Send + 'static> From<&str> for UploadClient<B>
56where
57 <B as HttpBody>::Data: Send,
58 <B as HttpBody>::Error: Into<Box<(dyn std::error::Error + Send + Sync + 'static)>>,
59{
60 fn from(token: &str) -> Self {
62 Self {
63 access_token: token.to_string(),
64 client: get_https_client(),
65 }
66 }
67}
68
69impl<B: HttpBody + Send + 'static> UploadClient<B>
70where
71 <B as HttpBody>::Data: Send,
72 <B as HttpBody>::Error: Into<Box<(dyn std::error::Error + Send + Sync + 'static)>>,
73{
74 pub fn from_env() -> Result<Self> {
79 let token = match var(ENV_VAR_NAME) {
80 Ok(val) => Ok(val),
81 Err(_) => Err(RustWistiaError::EnvVarNotFound {
82 name: ENV_VAR_NAME.to_owned(),
83 }),
84 }?;
85
86 Ok(Self::from(token))
87 }
88
89 pub fn from_token(token: &str) -> Self {
93 Self::from(token)
94 }
95
96 pub fn build_url(params: UploadRequest) -> Result<String> {
98 let query = to_string(params)?;
99
100 let mut url = String::with_capacity(UPLOAD_API.len() + 1 + query.len());
102 url.push_str(UPLOAD_API);
103 url.push('?');
104 url.push_str(query.as_str());
105
106 Ok(url)
107 }
108
109 pub async fn make_request<'a>(
111 &'a self,
112 url: &'a str,
113 req: Request<B>,
114 ) -> Result<UploadResponse> {
115 let start = Instant::now();
116 let mut resp = self.client.request(req).await?;
117 debug!("Call Upload API completed {:.2?}", start.elapsed());
118
119 raise_for_status(url, &mut resp).await?;
120
121 into_struct_from_slice(resp).await
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use serde::{Deserialize, Serialize};
128
129 #[test]
130 fn test_url_encoded_with_struct() {
131 #[derive(Deserialize, Serialize, PartialEq, Debug)]
132 struct Meal<'a> {
133 bread: &'a str,
134 cheese: &'a str,
135 meat: &'a str,
136 fat: &'a str,
137 }
138
139 let m = Meal {
140 bread: "baguette",
141 cheese: "comté",
142 meat: "ham",
143 fat: "butter",
144 };
145
146 assert_eq!(
147 serde_urlencoded::to_string::<Meal>(m),
148 Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned())
149 );
150 }
151}