Skip to main content

flyr/
fetch.rs

1use std::sync::Arc;
2use std::time::Duration;
3
4use wreq::Client;
5use wreq::cookie::Jar;
6use wreq_util::Emulation;
7
8use crate::error::{self, FlightError};
9
10const BASE_URL: &str = "https://www.google.com/travel/flights";
11
12#[derive(Clone)]
13pub struct FetchOptions {
14    pub proxy: Option<String>,
15    pub timeout: u64,
16}
17
18impl Default for FetchOptions {
19    fn default() -> Self {
20        Self {
21            proxy: None,
22            timeout: 30,
23        }
24    }
25}
26
27pub async fn fetch_html(
28    params: &[(String, String)],
29    options: &FetchOptions,
30) -> Result<String, FlightError> {
31    let jar = Arc::new(Jar::default());
32    let url: wreq::Uri = "https://www.google.com".parse().unwrap();
33    jar.add(
34        "SOCS=CAESEwgDEgk2MjA5NDM1NjAaAmVuIAEaBgiA_Le-Bg",
35        &url,
36    );
37    jar.add("CONSENT=PENDING+987", &url);
38
39    let mut builder = Client::builder()
40        .emulation(Emulation::Chrome137)
41        .cookie_provider(jar)
42        .timeout(Duration::from_secs(options.timeout));
43
44    if let Some(ref proxy) = options.proxy {
45        builder = builder.proxy(
46            wreq::Proxy::all(proxy).map_err(error::from_http_error)?,
47        );
48    }
49
50    let client = builder.build().map_err(error::from_http_error)?;
51
52    let response = client
53        .get(BASE_URL)
54        .query(params)
55        .send()
56        .await
57        .map_err(error::from_http_error)?;
58
59    let status = response.status().as_u16();
60    match status {
61        200 => {}
62        429 => return Err(FlightError::RateLimited),
63        403 | 503 => return Err(FlightError::Blocked(status)),
64        _ if status >= 400 => return Err(FlightError::HttpStatus(status)),
65        _ => {}
66    }
67
68    response.text().await.map_err(error::from_http_error)
69}