Skip to main content

eduboardapi/services/
client.rs

1use crate::config::{AppConfig, BASE_URL, RESULT_ENDPOINT};
2use crate::exceptions::{AppError, AppResult};
3use reqwest::cookie::Jar;
4use reqwest::header::{ACCEPT, ACCEPT_LANGUAGE, HeaderMap, HeaderValue, USER_AGENT};
5use reqwest::{Client, Url};
6use std::sync::Arc;
7use std::time::Duration;
8
9pub struct HttpClient {
10    config: AppConfig,
11    default_headers: HeaderMap,
12}
13
14impl HttpClient {
15    pub fn new(config: AppConfig) -> Self {
16        let mut default_headers = HeaderMap::new();
17        default_headers.insert(
18            ACCEPT,
19            HeaderValue::from_static("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"),
20        );
21        default_headers.insert(ACCEPT_LANGUAGE, HeaderValue::from_static("en-US,en;q=0.9"));
22        default_headers.insert(
23            USER_AGENT,
24            HeaderValue::from_static("Mozilla/5.0 (X11; Linux x86_64) EduBoardAPI/1.1"),
25        );
26
27        Self { config, default_headers }
28    }
29
30    fn build_session_client(&self) -> AppResult<Client> {
31        let cookie_jar = Jar::default();
32        Client::builder()
33            .cookie_provider(Arc::new(cookie_jar))
34            .default_headers(self.default_headers.clone())
35            .connect_timeout(Duration::from_secs(5))
36            .timeout(Duration::from_secs(self.config.timeout_seconds))
37            .pool_idle_timeout(Duration::from_secs(30))
38            .tcp_keepalive(Duration::from_secs(30))
39            .build()
40            .map_err(|e| AppError::Network(e.to_string()))
41    }
42
43    pub async fn get_homepage(&self) -> AppResult<(Client, String)> {
44        let client = self.build_session_client()?;
45        let url = Url::parse(BASE_URL).expect("Invalid BASE_URL");
46        let resp = client
47            .get(url)
48            .send()
49            .await
50            .map_err(|e| AppError::Network(e.to_string()))?;
51        let body = resp
52            .text()
53            .await
54            .map_err(|e| AppError::Network(e.to_string()))?;
55        Ok((client, body))
56    }
57
58    pub async fn submit_result_form<T: serde::Serialize>(&self, client: &Client, form_data: &T) -> AppResult<String> {
59        let url =
60            Url::parse(&format!("{BASE_URL}/{RESULT_ENDPOINT}")).expect("Invalid RESULT_ENDPOINT");
61        let resp = client
62            .post(url)
63            .form(form_data)
64            .send()
65            .await
66            .map_err(|e| AppError::Network(e.to_string()))?;
67        resp.text()
68            .await
69            .map_err(|e| AppError::Network(e.to_string()))
70    }
71}