escouade_plugin_kit/
errors.rs1use crate::i18n::Lang;
6use crate::tr_in;
7use serde_json::Value;
8
9#[derive(Debug)]
11pub struct HttpError {
12 pub status: u16,
13 pub message: String,
14}
15
16impl std::fmt::Display for HttpError {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 f.write_str(&self.message)
19 }
20}
21
22impl std::error::Error for HttpError {}
23
24#[derive(Debug)]
26pub struct Refused(pub String);
27
28impl std::fmt::Display for Refused {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.write_str(&self.0)
31 }
32}
33
34impl std::error::Error for Refused {}
35
36pub fn http_error_in(lang: Lang, name: &str, status: u16, body: &str) -> String {
38 let tail = said(body).map(|m| format!(" — {m}")).unwrap_or_default();
39 match status {
40 401 => tr_in!(
41 lang,
42 "{name} refuse ces identifiants (401){tail}",
43 "{name} refuses these credentials (401){tail}"
44 ),
45 403 => tr_in!(
46 lang,
47 "{name} refuse l'accès (403){tail}",
48 "{name} denies access (403){tail}"
49 ),
50 404 => tr_in!(
51 lang,
52 "{name} : introuvable (404){tail}",
53 "{name}: not found (404){tail}"
54 ),
55 429 => tr_in!(
56 lang,
57 "{name} limite les requêtes (429) : réessaie dans un moment",
58 "{name} limits the requests (429): try again in a moment"
59 ),
60 _ => tr_in!(
61 lang,
62 "{name} : erreur {status}{tail}",
63 "{name}: error {status}{tail}"
64 ),
65 }
66}
67
68pub fn said(body: &str) -> Option<String> {
71 let body = body.trim();
72 let msg = match serde_json::from_str::<Value>(body) {
73 Ok(Value::String(s)) => s,
74 Ok(v) => v["errorMessages"][0]
75 .as_str()
76 .map(str::to_string)
77 .or_else(|| {
78 v["errors"]
79 .as_object()
80 .and_then(|o| o.values().find_map(|e| e.as_str().map(str::to_string)))
81 })
82 .or_else(|| v["errors"][0]["message"].as_str().map(str::to_string))
83 .or_else(|| v["message"].as_str().map(str::to_string))
84 .or_else(|| v["error"].as_str().map(str::to_string))
85 .or_else(|| v["error"]["message"].as_str().map(str::to_string))
87 .or_else(|| v["err"].as_str().map(str::to_string))?,
88 Err(_) if body.starts_with('<') => return None,
89 Err(_) => body.lines().next()?.to_string(),
90 };
91 let msg = msg.trim();
92 (!msg.is_empty()).then(|| first_line(msg))
93}
94
95pub fn first_line(e: &str) -> String {
97 let line = e
98 .lines()
99 .map(str::trim)
100 .find(|l| !l.is_empty())
101 .map(str::to_string)
102 .unwrap_or_else(|| crate::tr!("erreur inconnue", "unknown error"));
103 truncate(&line, 200)
104}
105
106pub fn truncate(s: &str, max: usize) -> String {
108 if s.len() <= max {
109 return s.to_string();
110 }
111 let mut end = max;
112 while !s.is_char_boundary(end) {
113 end -= 1;
114 }
115 format!("{}…", &s[..end])
116}