paat_core/
client.rs

1use crate::{
2    datetime::naive_date_to_output_string,
3    types::event::{Direction, EventMap, EventResponse, WaitForSpot},
4    url::EVENTS_URL,
5};
6use anyhow::{anyhow, Result};
7use chrono::NaiveDate;
8use futures::{stream, Stream, StreamExt};
9use reqwest::Client as ReqwestClient;
10use std::time::Duration;
11use strum::EnumProperty;
12use tokio::time::sleep;
13
14pub struct Client {
15    client: ReqwestClient,
16    pause_between_stream_items: Duration,
17}
18
19impl Client {
20    pub fn new(pause_between_stream_items: Duration) -> Self {
21        Self {
22            client: reqwest::Client::new(),
23            pause_between_stream_items,
24        }
25    }
26
27    pub async fn fetch_events(
28        &self,
29        departure_date: &NaiveDate,
30        direction: &Direction,
31    ) -> Result<EventMap> {
32        let body = self
33            .client
34            .get(EVENTS_URL)
35            .query(&[
36                (
37                    "direction",
38                    direction.get_str("Abbreviation").unwrap().to_string(),
39                ),
40                (
41                    "departure-date",
42                    naive_date_to_output_string(departure_date),
43                ),
44            ])
45            .send()
46            .await?
47            .text()
48            .await?;
49        if let Ok(event_response) = serde_json::from_str::<EventResponse>(&body) {
50            return Ok(event_response
51                .items
52                .into_iter()
53                .map(|event| (event.uuid.clone(), event))
54                .collect());
55        }
56
57        Err(anyhow!("Failed to fetch events"))
58    }
59
60    fn create_event_stream<'a>(
61        &'a self,
62        departure_date: &'a NaiveDate,
63        direction: &'a Direction,
64    ) -> impl Stream<Item = Result<EventMap>> + 'a {
65        stream::iter(0..).then(move |i| async move {
66            if i > 0 {
67                sleep(self.pause_between_stream_items).await;
68            }
69            self.fetch_events(departure_date, direction).await
70        })
71    }
72
73    pub fn create_wait_stream<'a>(
74        &'a self,
75        departure_date: &'a NaiveDate,
76        direction: &'a Direction,
77        event_uuid: &'a str,
78    ) -> impl Stream<Item = Result<WaitForSpot>> + 'a {
79        self.create_event_stream(departure_date, direction)
80            .map(move |event_map_result| {
81                let event_map = event_map_result?;
82                if let Some(event) = event_map.get(event_uuid) {
83                    if event.capacities.small_vehicles > 0 {
84                        return Ok(WaitForSpot::Done(event.capacities.small_vehicles as usize));
85                    }
86                    return Ok(WaitForSpot::Waiting);
87                }
88                Err(anyhow!(
89                    "Failed to find corresponding event with followinf uuid: {}",
90                    event_uuid
91                ))
92            })
93    }
94}