phemios_core/
network_request.rs1use super::*;
3impl Client {
4 pub fn request(
6 &self,
7 method: &str,
8 path: &str,
9 query: &[(&str, &str)],
10 body: Option<&Value>,
11 ) -> Result<Value, String> {
12 self.request_admitted(method, path, query, body, || Ok(()))
13 }
14 pub fn request_admitted(
17 &self,
18 method: &str,
19 path: &str,
20 query: &[(&str, &str)],
21 body: Option<&Value>,
22 current: impl Fn() -> Result<(), String>,
23 ) -> Result<Value, String> {
24 current()?;
25 if !allowed(method, path) {
26 return Err("Opération native non prise en charge.".into());
27 }
28 let url = format!("{}{}", self.server, path);
29 let response = if method == "GET" {
30 read_response(
31 || {
32 let mut request = self
33 .agent
34 .get(&url)
35 .header("Authorization", format!("Bearer {}", self.token));
36 for (key, value) in query {
37 request = request.query(key, value);
38 }
39 request
40 .call()
41 .map_err(|_| "Impossible de joindre Aède.".to_string())
42 },
43 ¤t,
44 )
45 } else if method == "DELETE" {
46 let mut request = self
47 .agent
48 .delete(&url)
49 .header("Authorization", format!("Bearer {}", self.token));
50 for (key, value) in query {
51 request = request.query(key, value);
52 }
53 (if path == "/api/me/v1/history" {
54 let data = body.unwrap_or(&Value::Null).to_string();
55 if data.len() > 1024 {
56 return Err("Confirmation trop grande.".into());
57 }
58 request
59 .force_send_body()
60 .header("Content-Type", "application/json")
61 .send(data.as_bytes())
62 } else {
63 request.call()
64 })
65 .map_err(|_| "Impossible de joindre Aède.".to_string())
66 } else {
67 let data = body.map(Value::to_string).unwrap_or_default();
69 if data.len() > 16 * 1024 {
70 return Err("Requête trop grande.".into());
71 }
72 let mut request = if method == "PATCH" {
73 self.agent.patch(&url)
74 } else if method == "PUT" {
75 self.agent.put(&url)
76 } else {
77 self.agent.post(&url)
78 };
79 request = request
80 .header("Authorization", format!("Bearer {}", self.token))
81 .header("Content-Type", "application/json");
82 for (key, value) in query {
83 request = request.query(key, value);
84 }
85 request
86 .send(data.as_bytes())
87 .map_err(|_| "Impossible de joindre Aède.".to_string())
88 }?;
89 current()?;
90 if !response.status().is_success() {
91 let status = response.status().as_u16();
92 let mut response = response;
93 let detail = response
94 .body_mut()
95 .with_config()
96 .limit(8192)
97 .read_to_vec()
98 .ok()
99 .and_then(|bytes| serde_json::from_slice(&bytes).ok());
100 current()?;
101 return Err(errors::request_failure(
102 status,
103 method,
104 path,
105 body.is_some_and(|v| v["create_only"] == true),
106 detail.as_ref(),
107 ));
108 }
109 let result = decode(&bytes(response, JSON_LIMIT)?);
110 current()?;
111 result
112 }
113}
114
115pub(super) fn read_response<E>(
117 call: impl Fn() -> Result<ureq::http::Response<ureq::Body>, E>,
118 current: impl Fn() -> Result<(), E>,
119) -> Result<ureq::http::Response<ureq::Body>, E> {
120 for attempt in 0..4 {
121 current()?;
122 let response = call();
123 current()?;
124 let response = response?;
125 if !matches!(response.status().as_u16(), 409 | 429 | 503) {
126 return Ok(response);
127 }
128 drop(response);
129 std::thread::sleep(Duration::from_millis(150 << attempt));
130 }
131 current()?;
132 let response = call();
133 current()?;
134 response
135}
136
137#[cfg(test)]
138#[path = "network_request_test_support.rs"]
139mod test_support;
140#[cfg(test)]
141#[path = "network_request_tests.rs"]
142mod tests;