use std::collections::HashMap;
use crate::{
error::Result,
types::{gtfs::Entity, ATResponse, Header},
BASE_API_URL,
};
use reqwest::{Client, Method};
pub struct Realtime<'a> {
client: Client,
api_key: &'a str,
}
impl<'a> Realtime<'a> {
pub fn new(api_key: &'a str) -> Self {
Self {
client: Client::new(),
api_key,
}
}
pub async fn fetch_combined<'b>(
&self,
trip_ids: Option<&Vec<&'b str>>,
vehicle_ids: Option<&Vec<&'b str>>,
) -> Result<(Header, Vec<Entity>)> {
let url = format!("{}/public/realtime", BASE_API_URL);
let mut params = vec![];
if let Some(trips) = trip_ids {
params.push(("tripid", trips.join(",")));
}
if let Some(vehicles) = vehicle_ids {
params.push(("vehicleid", vehicles.join(",")));
}
let resp = self
.request(Method::GET, Self::build_query(url, ¶ms))
.send()
.await?
.json::<ATResponse>()
.await?;
let mut merged = vec![];
let entities: HashMap<_, _> = resp
.response
.entity
.into_iter()
.map(|e| (e.id.clone(), e))
.collect();
fn merge(ent: &Entity, hm: &HashMap<String, Entity>) -> Option<Entity> {
let trip_id = ent.vehicle.as_ref()?.trip.as_ref()?.trip_id.as_ref()?;
let tu_ent = hm.get(trip_id)?;
let mut entity = ent.clone();
if let Some(trip_update) = tu_ent.trip_update.as_ref() {
entity.trip_update = Some(trip_update.clone());
}
Some(entity)
}
for (_, ent) in entities.iter() {
if let Some(ent) = merge(ent, &entities) {
merged.push(ent);
}
}
Ok((resp.response.header, merged))
}
fn request(&self, method: Method, url: String) -> reqwest::RequestBuilder {
self.client
.request(method, url)
.header("Ocp-Apim-Subscription-Key", self.api_key)
}
fn build_query(mut url: String, params: &[(&str, String)]) -> String {
let mut queries = vec![];
for (k, v) in params {
queries.push(format!("{}={}", k, v));
}
if !queries.is_empty() {
let queries = format!("?{}", queries.join("&"));
url += queries.as_str();
}
url
}
}