smbcloud_network/
network.rs

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//use std::time::Duration;
13#[cfg(debug_assertions)]
14const LOG_RESPONSE_BODY: bool = false; // You know what to do here.
15#[cfg(not(debug_assertions))]
16const LOG_RESPONSE_BODY: bool = false;
17
18/// Check if there is an active internet connection
19///
20/// This function attempts to connect to a reliable server (dns.google)
21/// with a short timeout. Returns true if the connection was successful.
22pub async fn check_internet_connection() -> bool {
23    debug!("Checking internet connection");
24    let client = reqwest::Client::builder()
25        //.timeout(Duration::from_secs(5)) Does not work on wasm32
26        .build();
27
28    if let Err(e) = client {
29        error!("Failed to create client for connectivity check: {:?}", e);
30        return false;
31    }
32
33    if let Ok(client) = client {
34        match client.get("https://dns.google").send().await {
35            Ok(response) => {
36                debug!(
37                    "Internet connection check successful: {}",
38                    response.status()
39                );
40                response.status().is_success()
41            }
42            Err(e) => {
43                error!("Internet connection check failed: {:?}", e);
44                false
45            }
46        }
47    } else {
48        false
49    }
50}
51
52pub async fn parse_error_response<T: DeserializeOwned>(
53    response: Response,
54) -> Result<T, ErrorResponse> {
55    let response_body = match response.text().await {
56        Ok(body) => body,
57        Err(e) => {
58            error!("Failed to get response body: {:?}", e);
59            return Err(ErrorResponse::Error {
60                error_code: ErrorCode::NetworkError,
61                message: ErrorCode::NetworkError.message(None).to_string(),
62            });
63        }
64    };
65
66    if LOG_RESPONSE_BODY {
67        println!();
68        println!("Parse Error >>>>");
69        println!("{:?}", serde_json::to_string_pretty(&response_body));
70        println!("Parse Error >>>>");
71        println!();
72    }
73
74    let e = match serde_json::from_str::<ErrorResponse>(&response_body) {
75        Ok(json) => json,
76        Err(e) => {
77            error!("Failed to parse error response: {:?}", e);
78            return Err(ErrorResponse::Error {
79                error_code: ErrorCode::ParseError,
80                message: ErrorCode::ParseError.message(None).to_string(),
81            });
82        }
83    };
84    error!("Error response: {:?}", e);
85    Err(e)
86}
87
88pub async fn request_login(builder: RequestBuilder) -> Result<AccountStatus, ErrorResponse> {
89    let response = builder.send().await;
90    let response = match response {
91        Ok(response) => response,
92        Err(e) => {
93            error!("Failed to get response: {:?}", e);
94            return Err(ErrorResponse::Error {
95                error_code: ErrorCode::NetworkError,
96                message: ErrorCode::NetworkError.message(None).to_string(),
97            });
98        }
99    };
100
101    let response = match response.status() {
102        reqwest::StatusCode::OK
103        | reqwest::StatusCode::NOT_FOUND
104        | reqwest::StatusCode::UNPROCESSABLE_ENTITY => response,
105        status => {
106            error!(
107                "Response are neither OK, NOT_FOUND, or UNPROCESSABLE_ENTITY: {:?}",
108                status
109            );
110            return parse_error_response(response).await;
111        }
112    };
113
114    if LOG_RESPONSE_BODY {
115        println!();
116        println!("Parse >>>>");
117        println!("{:?}", &response.status());
118        println!("Parse >>>>");
119        println!();
120    }
121
122    match (response.status(), response.headers().get("Authorization")) {
123        (StatusCode::OK, Some(token)) => {
124            // Login successful, let's get the access token for real.
125            let access_token = match token.to_str() {
126                Ok(token) => token.to_string(),
127                Err(_) => {
128                    return Err(ErrorResponse::Error {
129                        error_code: ErrorCode::NetworkError,
130                        message: ErrorCode::NetworkError.message(None).to_string(),
131                    });
132                }
133            };
134            Ok(AccountStatus::Ready { access_token })
135        }
136        (StatusCode::NOT_FOUND, _) => {
137            // Account not found
138            Ok(AccountStatus::NotFound)
139        }
140        (StatusCode::UNPROCESSABLE_ENTITY, _) => {
141            // Account found but email not verified / password not set.
142            let result: SmbAuthorization = match response.json().await {
143                Ok(res) => res,
144                Err(_) => {
145                    return Err(ErrorResponse::Error {
146                        error_code: ErrorCode::NetworkError,
147                        message: ErrorCode::NetworkError.message(None).to_string(),
148                    });
149                }
150            };
151            // println!("Result: {:#?}", &result);
152            let error_code = match result.error_code {
153                Some(code) => code,
154                None => {
155                    return Err(ErrorResponse::Error {
156                        error_code: ErrorCode::NetworkError,
157                        message: ErrorCode::NetworkError.message(None).to_string(),
158                    });
159                }
160            };
161            Ok(AccountStatus::Incomplete { status: error_code })
162        }
163        _ => Err(ErrorResponse::Error {
164            error_code: ErrorCode::NetworkError,
165            message: ErrorCode::NetworkError.message(None).to_string(),
166        }),
167    }
168}
169
170pub async fn request<R: DeserializeOwned>(builder: RequestBuilder) -> Result<R, ErrorResponse> {
171    // Check internet connection before making the request
172    if !check_internet_connection().await {
173        error!("No internet connection available");
174        return Err(ErrorResponse::Error {
175            error_code: ErrorCode::NetworkError,
176            message: "No internet connection. Please check your network settings and try again."
177                .to_string(),
178        });
179    }
180
181    let response = builder.send().await;
182    let response = match response {
183        Ok(response) => response,
184        Err(e) => {
185            error!("Failed to get response: {:?}", e);
186            return Err(ErrorResponse::Error {
187                error_code: ErrorCode::NetworkError,
188                message: ErrorCode::NetworkError.message(None).to_string(),
189            });
190        }
191    };
192    let response = match response.status() {
193        reqwest::StatusCode::OK | reqwest::StatusCode::CREATED => response,
194        status => {
195            error!("Failed to get response: {:?}", status);
196            return parse_error_response(response).await;
197        }
198    };
199
200    let response_body = match response.text().await {
201        Ok(body) => body,
202        Err(e) => {
203            error!("Failed to get response body: {:?}", e);
204            return Err(ErrorResponse::Error {
205                error_code: ErrorCode::NetworkError,
206                message: ErrorCode::NetworkError.message(None).to_string(),
207            });
208        }
209    };
210
211    if LOG_RESPONSE_BODY {
212        println!();
213        println!("Parse >>>>");
214        println!("{:?}", serde_json::to_string_pretty(&response_body));
215        println!("Parse >>>>");
216        println!();
217    }
218
219    let response = match serde_json::from_str::<R>(&response_body) {
220        Ok(response) => response,
221        Err(e) => {
222            error!("Failed to parse response: {:?}", e);
223            return Err(ErrorResponse::Error {
224                error_code: ErrorCode::ParseError,
225                message: e.to_string(),
226            });
227        }
228    };
229
230    Ok(response)
231}