1pub mod model;
2pub mod oauth;
3pub mod services;
4#[cfg(test)]
5mod tests;
6
7use std::sync::Mutex;
8
9use chrono::Utc;
10use reqwest::header::{HeaderMap, HeaderValue};
11use reqwest::{Body, Client, Response};
12use serde::Serialize;
13
14use model::{PSError, PSResult};
15
16use self::oauth::PSToken;
17
18#[derive(Debug)]
19pub struct PSServer {
21 pub url: String,
22 pub credentials: oauth::PSCredentials,
23 pub token: Mutex<Option<PSToken>>,
24 client: Client,
25}
26
27impl PSServer {
28 pub fn new(url: String, credentials: oauth::PSCredentials) -> Self {
31 PSServer {
32 url,
33 credentials,
34 token: Mutex::new(None),
35 client: Client::new(),
36 }
37 }
38
39 pub fn preauth(url: String, credentials: oauth::PSCredentials, token: PSToken) -> Self {
40 PSServer {
41 url,
42 credentials,
43 token: Mutex::new(Some(token)),
44 client: Client::new(),
45 }
46 }
47
48 fn format_url(&self, uri: &str) -> String {
50 format!("{}/{}", self.url, uri.trim_start_matches('/'))
51 }
52
53 async fn get<U: Into<String>>(
57 &self,
58 uri: U,
59 params: Option<Vec<(&str, &str)>>,
60 headers: Option<HeaderMap<HeaderValue>>,
61 ) -> PSResult<Response> {
62 let uri = uri.into();
63 let mut req = self.client.get(self.format_url(&uri));
64
65 if let Some(params) = params {
66 req = req.query(¶ms);
67 }
68 if let Some(headers) = headers {
69 req = req.headers(headers)
70 }
71
72 Ok(req.send().await?)
73 }
74
75 async fn post<U: Into<String>, T: Into<Body>>(
78 &self,
79 uri: U,
80 params: Option<Vec<(&str, &str)>>,
81 headers: Option<HeaderMap<HeaderValue>>,
82 body: Option<T>,
83 ) -> PSResult<Response> {
84 let uri = uri.into();
85 let mut req = self.client.post(self.format_url(&uri));
86
87 if let Some(params) = params {
88 req = req.query(¶ms);
89 }
90 if let Some(headers) = headers {
91 req = req.headers(headers);
92 }
93 if let Some(body) = body {
94 req = req.body(body);
95 }
96
97 Ok(req.send().await?)
98 }
99
100 async fn _post_form<F: Serialize + ?Sized>(
103 &self,
104 uri_slug: &str,
105 params: Option<Vec<(&str, &str)>>,
106 headers: Option<HeaderMap<HeaderValue>>,
107 form: Option<&F>,
108 ) -> PSResult<Response> {
109 let mut req = self.client.post(self.format_url(uri_slug));
110
111 if let Some(params) = params {
112 req = req.query(¶ms);
113 }
114 if let Some(headers) = headers {
115 req = req.headers(headers);
116 }
117 if let Some(form) = form {
118 req = req.form(form);
119 }
120
121 Ok(req.send().await?)
122 }
123
124 async fn put<U: Into<String>, T: Into<Body>>(
125 &self,
126 uri: U,
127 params: Option<Vec<(&str, &str)>>,
128 headers: Option<HeaderMap<HeaderValue>>,
129 body: Option<T>,
130 ) -> PSResult<Response> {
131 let uri = uri.into();
132 let mut req = self.client.put(self.format_url(&uri));
133
134 if let Some(params) = params {
135 req = req.query(¶ms);
136 }
137 if let Some(headers) = headers {
138 req = req.headers(headers);
139 }
140 if let Some(body) = body {
141 req = req.body(body);
142 }
143
144 Ok(req.send().await?)
145 }
146
147 fn valid_token(&self) -> bool {
151 if let Some(token) = (*self.token.lock().unwrap()).as_ref() {
152 token.expiry.gt(&Utc::now())
153 } else {
154 false
155 }
156 }
157
158 async fn get_token(&self) -> PSResult<PSToken> {
160 let resp = self
161 .client
162 .post(self.format_url("/ps/oauth/token"))
163 .form(&self.credentials.to_map())
164 .send()
165 .await?;
166
167 let resp_text = match resp.text().await {
168 Err(err) => {
169 return Err(PSError::TokenError {
170 msg: format!("Failed to get text from token response: {:?}", err),
171 })
172 }
173 Ok(txt) => txt,
174 };
175
176 let token_resp: oauth::TokenResponse = match serde_json::from_str(&resp_text) {
177 Err(err) => {
178 return Err(PSError::TokenError {
179 msg: format!(
180 "Failed to parse response as json: {:?}. Response was: {}",
181 err, &resp_text
182 ),
183 })
184 }
185 Ok(tr) => tr,
186 };
187 PSToken::expires_in(token_resp.access_token, token_resp.expires_in)
188 }
189
190 pub async fn update_token(&self) -> PSResult<HeaderValue> {
192 let header = if !self.valid_token() {
193 let new_token = self.get_token().await?;
194 self.token.lock().unwrap().insert(new_token).header.clone()
195 } else {
196 self.token.lock().unwrap().as_ref().unwrap().header.clone()
197 };
198 Ok(header)
199 }
200
201 pub async fn checked_get<U: Into<String>>(
206 &self,
207 uri: U,
208 params: Option<Vec<(&str, &str)>>,
209 headers: Option<HeaderMap<HeaderValue>>,
210 ) -> PSResult<Response> {
211 let token = self.update_token().await?;
212 let mut new_headers = headers.unwrap_or_default();
213 new_headers.insert("authorization", token.clone());
214 self.get(uri, params, Some(new_headers)).await
215 }
216
217 async fn checked_post<U: Into<String>, T: Into<Body>>(
218 &self,
219 uri: U,
220 params: Option<Vec<(&str, &str)>>,
221 headers: Option<HeaderMap<HeaderValue>>,
222 body: Option<T>,
223 ) -> PSResult<Response> {
224 let token = self.update_token().await?;
225 let mut new_headers = headers.unwrap_or_default();
226 new_headers.insert("authorization", token.clone());
227 self.post(uri, params, Some(new_headers), body).await
228 }
229
230 async fn _checked_post_form<F: Serialize + ?Sized>(
231 &self,
232 uri_slug: &str,
233 params: Option<Vec<(&str, &str)>>,
234 headers: Option<HeaderMap<HeaderValue>>,
235 form: Option<&F>,
236 ) -> PSResult<Response> {
237 let token = self.update_token().await?;
238 let mut new_headers = headers.unwrap_or_default();
239 new_headers.insert("authorization", token.clone());
240 self._post_form(uri_slug, params, Some(new_headers), form)
241 .await
242 }
243
244 async fn checked_put<U: Into<String>, T: Into<Body>>(
245 &self,
246 uri: U,
247 params: Option<Vec<(&str, &str)>>,
248 headers: Option<HeaderMap<HeaderValue>>,
249 body: Option<T>,
250 ) -> PSResult<Response> {
251 let token = self.update_token().await?;
252 let mut new_headers = headers.unwrap_or_default();
253 new_headers.insert("authorization", token.clone());
254 self.put(uri, params, Some(new_headers), body).await
255 }
256}