torrust_index/web/api/client/v1/
http.rs1use std::time::Duration;
2
3use reqwest::{multipart, Error};
4use serde::Serialize;
5
6use super::connection_info::ConnectionInfo;
7use super::responses::{BinaryResponse, TextResponse};
8
9pub type ReqwestQuery = Vec<ReqwestQueryParam>;
10pub type ReqwestQueryParam = (String, String);
11
12#[derive(Default, Debug)]
14pub struct Query {
15 params: Vec<QueryParam>,
16}
17
18impl Query {
19 #[must_use]
20 pub fn empty() -> Self {
21 Self { params: vec![] }
22 }
23
24 #[must_use]
25 pub fn with_params(params: Vec<QueryParam>) -> Self {
26 Self { params }
27 }
28
29 pub fn add_param(&mut self, param: QueryParam) {
30 self.params.push(param);
31 }
32}
33
34impl From<Query> for ReqwestQuery {
35 fn from(url_search_params: Query) -> Self {
36 url_search_params
37 .params
38 .iter()
39 .map(|param| ReqwestQueryParam::from((*param).clone()))
40 .collect()
41 }
42}
43
44#[derive(Clone, Debug)]
46pub struct QueryParam {
47 name: String,
48 value: String,
49}
50
51impl QueryParam {
52 #[must_use]
53 pub fn new(name: &str, value: &str) -> Self {
54 Self {
55 name: name.to_string(),
56 value: value.to_string(),
57 }
58 }
59}
60
61impl From<QueryParam> for ReqwestQueryParam {
62 fn from(param: QueryParam) -> Self {
63 (param.name, param.value)
64 }
65}
66
67pub struct Http {
69 connection_info: ConnectionInfo,
70 timeout: Duration,
73}
74
75impl Http {
76 #[must_use]
77 pub fn new(connection_info: ConnectionInfo) -> Self {
78 Self {
79 connection_info,
80 timeout: Duration::from_secs(5),
81 }
82 }
83
84 pub async fn get(&self, path: &str, params: Query) -> Result<TextResponse, Error> {
89 let response = match &self.connection_info.token {
90 Some(token) => {
91 reqwest::Client::builder()
92 .timeout(self.timeout)
93 .build()?
94 .get(self.base_url(path).clone())
95 .query(&ReqwestQuery::from(params))
96 .bearer_auth(token)
97 .send()
98 .await?
99 }
100 None => {
101 reqwest::Client::builder()
102 .timeout(self.timeout)
103 .build()?
104 .get(self.base_url(path).clone())
105 .query(&ReqwestQuery::from(params))
106 .send()
107 .await?
108 }
109 };
110
111 Ok(TextResponse::from(response).await)
112 }
113
114 pub async fn get_binary(&self, path: &str, params: Query) -> Result<BinaryResponse, Error> {
119 let response = match &self.connection_info.token {
120 Some(token) => {
121 reqwest::Client::builder()
122 .timeout(self.timeout)
123 .build()?
124 .get(self.base_url(path).clone())
125 .query(&ReqwestQuery::from(params))
126 .bearer_auth(token)
127 .send()
128 .await?
129 }
130 None => {
131 reqwest::Client::builder()
132 .timeout(self.timeout)
133 .build()?
134 .get(self.base_url(path).clone())
135 .query(&ReqwestQuery::from(params))
136 .send()
137 .await?
138 }
139 };
140
141 Ok(BinaryResponse::from(response).await)
146 }
147
148 pub async fn inner_get(&self, path: &str) -> Result<reqwest::Response, reqwest::Error> {
153 reqwest::Client::builder()
154 .timeout(self.timeout)
155 .build()?
156 .get(self.base_url(path).clone())
157 .send()
158 .await
159 }
160
161 pub async fn post<T: Serialize + ?Sized>(&self, path: &str, form: &T) -> Result<TextResponse, reqwest::Error> {
166 let response = match &self.connection_info.token {
167 Some(token) => {
168 reqwest::Client::new()
169 .post(self.base_url(path).clone())
170 .bearer_auth(token)
171 .json(&form)
172 .send()
173 .await?
174 }
175 None => {
176 reqwest::Client::new()
177 .post(self.base_url(path).clone())
178 .json(&form)
179 .send()
180 .await?
181 }
182 };
183
184 Ok(TextResponse::from(response).await)
185 }
186
187 pub async fn post_multipart(&self, path: &str, form: multipart::Form) -> Result<TextResponse, reqwest::Error> {
192 let response = match &self.connection_info.token {
193 Some(token) => {
194 reqwest::Client::builder()
195 .timeout(self.timeout)
196 .build()?
197 .post(self.base_url(path).clone())
198 .multipart(form)
199 .bearer_auth(token)
200 .send()
201 .await?
202 }
203 None => {
204 reqwest::Client::builder()
205 .timeout(self.timeout)
206 .build()?
207 .post(self.base_url(path).clone())
208 .multipart(form)
209 .send()
210 .await?
211 }
212 };
213
214 Ok(TextResponse::from(response).await)
215 }
216
217 pub async fn put<T: Serialize + ?Sized>(&self, path: &str, form: &T) -> Result<TextResponse, reqwest::Error> {
222 let response = match &self.connection_info.token {
223 Some(token) => {
224 reqwest::Client::new()
225 .put(self.base_url(path).clone())
226 .bearer_auth(token)
227 .json(&form)
228 .send()
229 .await?
230 }
231 None => {
232 reqwest::Client::new()
233 .put(self.base_url(path).clone())
234 .json(&form)
235 .send()
236 .await?
237 }
238 };
239
240 Ok(TextResponse::from(response).await)
241 }
242
243 pub async fn delete(&self, path: &str) -> Result<TextResponse, reqwest::Error> {
248 let response = match &self.connection_info.token {
249 Some(token) => {
250 reqwest::Client::new()
251 .delete(self.base_url(path).clone())
252 .bearer_auth(token)
253 .send()
254 .await?
255 }
256 None => reqwest::Client::new().delete(self.base_url(path).clone()).send().await?,
257 };
258
259 Ok(TextResponse::from(response).await)
260 }
261
262 pub async fn delete_with_body<T: Serialize + ?Sized>(&self, path: &str, form: &T) -> Result<TextResponse, reqwest::Error> {
267 let response = match &self.connection_info.token {
268 Some(token) => {
269 reqwest::Client::new()
270 .delete(self.base_url(path).clone())
271 .bearer_auth(token)
272 .json(&form)
273 .send()
274 .await?
275 }
276 None => {
277 reqwest::Client::new()
278 .delete(self.base_url(path).clone())
279 .json(&form)
280 .send()
281 .await?
282 }
283 };
284
285 Ok(TextResponse::from(response).await)
286 }
287
288 fn base_url(&self, path: &str) -> String {
289 format!(
290 "{}://{}{}{path}",
291 &self.connection_info.scheme, &self.connection_info.bind_address, &self.connection_info.base_path
292 )
293 }
294}