1use {
2 log::{debug, error},
3 reqwest::{RequestBuilder, Response, StatusCode},
4 serde::de::DeserializeOwned,
5 smbcloud_model::{
6 account::SmbAuthorization,
7 error_codes::{ErrorCode, ErrorResponse},
8 login::AccountStatus,
9 },
10};
11
12#[cfg(debug_assertions)]
14const LOG_RESPONSE_BODY: bool = true; #[cfg(not(debug_assertions))]
16const LOG_RESPONSE_BODY: bool = false;
17
18#[cfg(not(target_arch = "wasm32"))]
24pub async fn check_internet_connection() -> bool {
25 debug!("Checking internet connection");
26 let client = reqwest::Client::builder()
27 .build();
29
30 if let Err(e) = client {
31 error!("Failed to create client for connectivity check: {:?}", e);
32 return false;
33 }
34
35 if let Ok(client) = client {
36 match client.get("https://dns.google").send().await {
37 Ok(response) => {
38 debug!(
39 "Internet connection check successful: {}",
40 response.status()
41 );
42 response.status().is_success()
43 }
44 Err(e) => {
45 error!("Internet connection check failed: {:?}", e);
46 false
47 }
48 }
49 } else {
50 false
51 }
52}
53
54#[cfg(target_arch = "wasm32")]
55pub async fn check_internet_connection() -> bool {
56 true
57}
58
59pub async fn parse_error_response<T: DeserializeOwned>(
60 response: Response,
61) -> Result<T, ErrorResponse> {
62 let error_response_body = match response.text().await {
63 Ok(body) => body,
64 Err(e) => {
65 error!("Failed to get response body: {:?}", e);
66 return Err(ErrorResponse::Error {
67 error_code: ErrorCode::NetworkError,
68 message: ErrorCode::NetworkError.message(None).to_string(),
69 });
70 }
71 };
72
73 if LOG_RESPONSE_BODY {
74 debug!(
75 "Parse Error >>>> {:?}",
76 serde_json::to_string_pretty(&error_response_body)
77 );
78 }
79
80 let error_response = match serde_json::from_str(&error_response_body) {
81 Ok(error_response) => error_response,
82 Err(e) => {
83 error!("Failed to parse error response: {:?}", e);
84 return Err(ErrorResponse::Error {
85 error_code: ErrorCode::ParseError,
86 message: ErrorCode::ParseError.message(None).to_string(),
87 });
88 }
89 };
90 Err(error_response)
93}
94
95pub async fn request_login(builder: RequestBuilder) -> Result<AccountStatus, ErrorResponse> {
96 let response = builder.send().await;
97 let response = match response {
98 Ok(response) => response,
99 Err(e) => {
100 error!("request_login: Failed to get response: {:?}", e);
101 return Err(ErrorResponse::Error {
102 error_code: ErrorCode::NetworkError,
103 message: ErrorCode::NetworkError.message(None).to_string(),
104 });
105 }
106 };
107
108 if LOG_RESPONSE_BODY {
109 debug!("request_login: Parse >>>> {:?}", response.status());
110 }
111
112 match (response.status(), response.headers().get("Authorization")) {
113 (StatusCode::OK, Some(token)) => {
114 let access_token = match token.to_str() {
116 Ok(token) => token.to_string(),
117 Err(_) => {
118 return Err(ErrorResponse::Error {
119 error_code: ErrorCode::NetworkError,
120 message: ErrorCode::NetworkError.message(None).to_string(),
121 });
122 }
123 };
124 Ok(AccountStatus::Ready { access_token })
125 }
126 (StatusCode::OK, None) => {
127 let error_response = match parse_error_response::<ErrorResponse>(response).await {
129 Ok(error) => error,
130 Err(_) => return Ok(AccountStatus::NotFound),
131 };
132 match error_response {
133 ErrorResponse::Error {
134 error_code,
135 message: _,
136 } => match error_code {
137 ErrorCode::EmailNotVerified => Ok(AccountStatus::Incomplete {
138 status: smbcloud_model::account::ErrorCode::EmailUnverified,
139 }),
140 ErrorCode::PasswordNotSet => Ok(AccountStatus::Incomplete {
141 status: smbcloud_model::account::ErrorCode::PasswordNotSet,
142 }),
143 ErrorCode::Unknown => Ok(AccountStatus::Ready {
144 access_token: "tokenization".to_string(),
145 }),
146 _ => Ok(AccountStatus::NotFound),
147 },
148 }
149 }
150 (StatusCode::NOT_FOUND, _) => {
151 Ok(AccountStatus::NotFound)
153 }
154 (StatusCode::UNPROCESSABLE_ENTITY, _) => {
155 let body_text = match response.text().await {
156 Ok(text) => text,
157 Err(_) => {
158 return Err(ErrorResponse::Error {
159 error_code: ErrorCode::NetworkError,
160 message: ErrorCode::NetworkError.message(None).to_string(),
161 });
162 }
163 };
164
165 let result: SmbAuthorization = match serde_json::from_str(&body_text) {
166 Ok(res) => res,
167 Err(_) => {
168 let message = serde_json::from_str::<serde_json::Value>(&body_text)
170 .ok()
171 .and_then(|v| {
172 v.get("message")
173 .and_then(serde_json::Value::as_str)
174 .map(ToOwned::to_owned)
175 })
176 .unwrap_or_else(|| ErrorCode::NetworkError.message(None).to_string());
177 return Err(ErrorResponse::Error {
178 error_code: ErrorCode::NetworkError,
179 message,
180 });
181 }
182 };
183
184 let error_code = match result.error_code {
185 Some(code) => code,
186 None => {
187 return Err(ErrorResponse::Error {
190 error_code: ErrorCode::NetworkError,
191 message: result.message,
192 });
193 }
194 };
195 Ok(AccountStatus::Incomplete { status: error_code })
196 }
197 (StatusCode::UNAUTHORIZED, _) => {
198 let body_text = match response.text().await {
199 Ok(text) => text,
200 Err(_) => {
201 return Err(ErrorResponse::Error {
202 error_code: ErrorCode::NetworkError,
203 message: ErrorCode::NetworkError.message(None).to_string(),
204 });
205 }
206 };
207
208 if let Ok(result) = serde_json::from_str::<SmbAuthorization>(&body_text) {
210 let error_code = match result.error_code {
211 Some(code) => code,
212 None => {
213 return Err(ErrorResponse::Error {
215 error_code: ErrorCode::Unauthorized,
216 message: result.message,
217 });
218 }
219 };
220 return Err(ErrorResponse::Error {
221 error_code: ErrorCode::Unauthorized,
222 message: error_code.to_string(),
223 });
224 }
225
226 if let Ok(generic) = serde_json::from_str::<serde_json::Value>(&body_text) {
228 let extracted = generic
229 .get("message")
230 .or_else(|| generic.get("error"))
231 .and_then(serde_json::Value::as_str)
232 .unwrap_or("Sign in failed.");
233 return Err(ErrorResponse::Error {
234 error_code: ErrorCode::Unauthorized,
235 message: extracted.to_string(),
236 });
237 }
238
239 Err(ErrorResponse::Error {
240 error_code: ErrorCode::Unauthorized,
241 message: "Sign in failed.".to_string(),
242 })
243 }
244 (status, _) => parse_error_response(response)
245 .await
246 .map_err(|_| ErrorResponse::Error {
247 error_code: ErrorCode::NetworkError,
248 message: format!("Unexpected login response status: {}", status),
249 }),
250 }
251}
252
253pub async fn request<R: DeserializeOwned>(builder: RequestBuilder) -> Result<R, ErrorResponse> {
254 if !check_internet_connection().await {
256 error!("No internet connection available");
257 return Err(ErrorResponse::Error {
258 error_code: ErrorCode::NetworkError,
259 message: "No internet connection. Please check your network settings and try again."
260 .to_string(),
261 });
262 }
263
264 let response = builder.send().await;
265 let response = match response {
266 Ok(response) => response,
267 Err(e) => {
268 error!("Failed to get response: {:?}", e);
269 return Err(ErrorResponse::Error {
270 error_code: ErrorCode::NetworkError,
271 message: ErrorCode::NetworkError.message(None).to_string(),
272 });
273 }
274 };
275 let response = match response.status() {
276 reqwest::StatusCode::OK | reqwest::StatusCode::CREATED => response,
277 status => {
278 error!("Failed to get response: {:?}", status);
279 return parse_error_response(response).await;
281 }
282 };
283
284 let response_body = match response.text().await {
285 Ok(body) => body,
286 Err(e) => {
287 error!("Failed to get response body: {:?}", e);
288 return Err(ErrorResponse::Error {
289 error_code: ErrorCode::NetworkError,
290 message: ErrorCode::NetworkError.message(None).to_string(),
291 });
292 }
293 };
294
295 if LOG_RESPONSE_BODY {
296 debug!(
297 "Parse >>>> {:?}",
298 serde_json::to_string_pretty(&response_body)
299 );
300 }
301
302 let response = match serde_json::from_str::<R>(&response_body) {
303 Ok(response) => response,
304 Err(e) => {
305 error!("Failed to parse response: {:?}", e);
306 return Err(ErrorResponse::Error {
307 error_code: ErrorCode::ParseError,
308 message: e.to_string(),
309 });
310 }
311 };
312
313 Ok(response)
314}