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}