use std::io::BufRead; use hafas_rest::{Hafas, JourneysQuery, JourneysResult, Leg, LoyaltyCard, Station, StationsQuery}; use rrw::RestConfig; const CARD: Option = None; #[tokio::main] async fn main() -> Result<(), Box> { env_logger::init(); let stdin = std::io::stdin(); let mut lines = stdin.lock().lines(); let hafas = Hafas::new(RestConfig::new("https://v5.db.transport.rest")); println!("Departure: "); let departure_str = lines.next().expect("Failed to read line")?; let departure = get_station_by_search(&hafas, &departure_str).await?; println!("Found station: {} (id: {})", departure.name, departure.id); println!(""); println!("Arrival: "); let arrival_str = lines.next().expect("Failed to read line")?; let arrival = get_station_by_search(&hafas, &arrival_str).await?; println!("Found station: {} (id: {})", arrival.name, arrival.id); println!(""); let journeys = hafas .journey(&JourneysQuery { from: Some(departure.id.clone()), to: Some(arrival.id.clone()), stopovers: Some(true), loyalty_card: CARD, ..Default::default() }) .await?; print_journeys(&journeys); println!("Inspect Closer (or 'earlier' or 'later')"); let inspect_line = lines.next().expect("Failed to read line")?; if inspect_line == "earlier" { let earlier_ref = &journeys.earlier_ref; let earlier = hafas .journey(&JourneysQuery { from: Some(departure.id.clone()), to: Some(arrival.id.clone()), earlier_than: Some(earlier_ref.clone()), stopovers: Some(true), ..Default::default() }) .await?; print_journeys(&earlier); return Ok(()); } if inspect_line == "later" { let later_ref = &journeys.later_ref; let later = hafas .journey(&JourneysQuery { from: Some(departure.id.clone()), to: Some(arrival.id.clone()), later_than: Some(later_ref.clone()), stopovers: Some(true), ..Default::default() }) .await?; print_journeys(&later); return Ok(()); } let inspect_idx = inspect_line .parse::() .expect("Failed to parst integer"); println!(""); if inspect_idx >= journeys.journeys.len() { println!("Index out of scope"); return Err(Box::new(NoSuchElement {}) as Box); } let inspect = &journeys.journeys[inspect_idx]; if let Some(price) = &inspect.price { println!("Price: {} {}", price.amount, price.currency); } print_legs(&inspect.legs); Ok(()) } async fn get_station_by_search>( hafas: &Hafas, query: S, ) -> Result> { let stations = hafas .stations(&StationsQuery { query: query.as_ref().to_string(), ..Default::default() }) .await?; if stations.len() == 0 { println!("No station found for {}.", query.as_ref()); return Err(Box::new(NoSuchElement {})); } let mut stations_vec = stations.into_values().collect::>(); stations_vec.sort_by(|s1, s2| s1.weight.partial_cmp(&s2.weight).unwrap()); Ok(stations_vec[0].clone()) } fn print_journeys(journeys: &JourneysResult) { for (pos, journey) in journeys.journeys.iter().enumerate() { println!("Available Journey: [{}]", pos); let source = journey.legs.first().expect("Every journey must have a leg"); let destination = journey.legs.last().expect("Every journey must have a leg"); println!( "Departure(Planned): {}, Departure: {}", source .planned_departure .map(|d| d.to_string()) .unwrap_or("?".to_string()), source .departure .map(|d| d.to_string()) .unwrap_or("?".to_string()), ); println!( "Arrival(Planned): {}, Arrival: {}", destination .planned_arrival .map(|d| d.to_string()) .unwrap_or("?".to_string()), destination .arrival .map(|d| d.to_string()) .unwrap_or("?".to_string()), ); println!( "Types of transport: {:?}", journey .legs .iter() .map(|leg| leg .line .as_ref() .expect("Line to be set up") .product_name .clone()) .collect::>() ); println!(""); } } fn print_legs(legs: &Vec) { for (idx, leg) in legs.iter().enumerate() { println!("Leg {} (id: {})", idx, leg.id()); println!( "Origin: {}, Destination: {}", leg.origin.name, leg.destination.name ); println!( "Departure(Planned): {}, Departure: {}, Platform(Planned): {}, Platform: {}", leg.planned_departure .map(|d| d.to_string()) .unwrap_or("?".to_string()), leg.departure .map(|d| d.to_string()) .unwrap_or("?".to_string()), leg.planned_departure_platform.clone().unwrap_or_default(), leg.departure_platform.clone().unwrap_or_default(), ); println!( "Arrival(Planned): {}, Arrival: {}, Platform(Planned): {}, Platform: {}", leg.planned_arrival .map(|d| d.to_string()) .unwrap_or("?".to_string()), leg.arrival .map(|d| d.to_string()) .unwrap_or("?".to_string()), leg.planned_arrival_platform.clone().unwrap_or_default(), leg.arrival_platform.clone().unwrap_or_default(), ); if let Some(stopovers) = &leg.stopovers { println!(""); println!("Stopovers:"); for (idx, stopover) in stopovers.iter().enumerate() { println!("{}: {}", idx, stopover.stop.name); } } if let Some(remarks) = &leg.remarks { println!(""); println!("Remarks:"); for (idx, remark) in remarks.iter().enumerate() { println!("{}: {}", idx, remark.text); } } println!(""); } } #[derive(Debug)] struct NoSuchElement {} impl std::fmt::Display for NoSuchElement { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "No such element") } } impl std::error::Error for NoSuchElement {}