paat-core 0.1.0

core functions for communicating with praamid.ee internal API
Documentation
use crate::{
    datetime::naive_date_to_output_string,
    types::event::{Direction, EventMap, EventResponse, WaitForSpot},
    url::EVENTS_URL,
};
use anyhow::{anyhow, Result};
use chrono::NaiveDate;
use futures::{stream, Stream, StreamExt};
use reqwest::Client as ReqwestClient;
use std::time::Duration;
use strum::EnumProperty;
use tokio::time::sleep;

pub struct Client {
    client: ReqwestClient,
    pause_between_stream_items: Duration,
}

impl Client {
    pub fn new(pause_between_stream_items: Duration) -> Self {
        Self {
            client: reqwest::Client::new(),
            pause_between_stream_items,
        }
    }

    pub async fn fetch_events(
        &self,
        departure_date: &NaiveDate,
        direction: &Direction,
    ) -> Result<EventMap> {
        let body = self
            .client
            .get(EVENTS_URL)
            .query(&[
                (
                    "direction",
                    direction.get_str("Abbreviation").unwrap().to_string(),
                ),
                (
                    "departure-date",
                    naive_date_to_output_string(departure_date),
                ),
            ])
            .send()
            .await?
            .text()
            .await?;
        if let Ok(event_response) = serde_json::from_str::<EventResponse>(&body) {
            return Ok(event_response
                .items
                .into_iter()
                .map(|event| (event.uuid.clone(), event))
                .collect());
        }

        Err(anyhow!("Failed to fetch events"))
    }

    fn create_event_stream<'a>(
        &'a self,
        departure_date: &'a NaiveDate,
        direction: &'a Direction,
    ) -> impl Stream<Item = Result<EventMap>> + 'a {
        stream::iter(0..).then(move |i| async move {
            if i > 0 {
                sleep(self.pause_between_stream_items).await;
            }
            self.fetch_events(departure_date, direction).await
        })
    }

    pub fn create_wait_stream<'a>(
        &'a self,
        departure_date: &'a NaiveDate,
        direction: &'a Direction,
        event_uuid: &'a str,
    ) -> impl Stream<Item = Result<WaitForSpot>> + 'a {
        self.create_event_stream(departure_date, direction)
            .map(move |event_map_result| {
                let event_map = event_map_result?;
                if let Some(event) = event_map.get(event_uuid) {
                    if event.capacities.small_vehicles > 0 {
                        return Ok(WaitForSpot::Done(event.capacities.small_vehicles as usize));
                    }
                    return Ok(WaitForSpot::Waiting);
                }
                Err(anyhow!(
                    "Failed to find corresponding event with followinf uuid: {}",
                    event_uuid
                ))
            })
    }
}