summaryrefslogtreecommitdiff
path: root/src/onboard/iceportal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/onboard/iceportal.rs')
-rw-r--r--src/onboard/iceportal.rs126
1 files changed, 126 insertions, 0 deletions
diff --git a/src/onboard/iceportal.rs b/src/onboard/iceportal.rs
new file mode 100644
index 0000000..04ec291
--- /dev/null
+++ b/src/onboard/iceportal.rs
@@ -0,0 +1,126 @@
+/// implementation of traits to query the iceportal.de
+/// (available in high speed trains in DE)
+use chrono::{DateTime, Utc};
+use serde::Deserialize;
+use serde_json::Value;
+
+use crate::onboard;
+use crate::onboard::{OnBoardAPI, OnBoardInfo};
+use crate::{serde::*, traits::*, travelynx::TrainRef};
+
+pub struct Iceportal {}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct TripInfo {
+ trip: Trip,
+ connection: Option<Value>,
+ selected_route: Option<Value>,
+ active: Option<Value>
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct Trip {
+ train_type: String,
+ vzn: String, // train number
+ // some position info here
+ actual_position: u64, // distance along track, presumably
+ stops: Vec<Stop>
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct Stop {
+ info: StopInfo,
+ station: Station,
+ timetable: Timetable
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct StopInfo {
+ distance_from_start: u64,
+ position_status: String // one of "departed", "future", ... ?
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct Station {
+ eva_nr: String,
+ name: String
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct Timetable {
+ #[serde(deserialize_with = "option_naive_read_unixtime_db")]
+ scheduled_arrival_time: Option<DateTime<Utc>>,
+ #[serde(deserialize_with = "option_naive_read_unixtime_db")]
+ actual_arrival_time: Option<DateTime<Utc>>
+}
+
+impl IsStation for Stop {
+ fn name(&self) -> &str {
+ &self.station.name
+ }
+
+ fn scheduled_arrival(&self) -> Option<&chrono::DateTime<Utc>> {
+ self.timetable.scheduled_arrival_time.as_ref()
+ }
+
+ fn real_arrival(&self) -> Option<&chrono::DateTime<Utc>> {
+ self.timetable.scheduled_arrival_time.as_ref()
+ }
+
+ fn ds100(&self) -> &str {
+ "??"
+ }
+}
+
+impl OnBoardInfo for TripInfo {
+ fn guess_last_station(&self) -> Option<&dyn IsStation> {
+ let current_pos = self.trip.actual_position;
+ self
+ .trip
+ .stops
+ .iter()
+ .rev()
+ .map(|stop| (stop.info.distance_from_start, stop))
+ .filter(|(dist, _)| dist <= &current_pos)
+ .next()
+ .map(|(_, stop)| stop as &dyn IsStation)
+ }
+
+ fn get_train_ref(&self) -> TrainRef {
+ TrainRef {
+ _type: self.trip.train_type.clone(),
+ no: self.trip.vzn.clone()
+ }
+ }
+
+ fn stops<'a>(
+ &'a self
+ ) -> Box<dyn std::iter::Iterator<Item = &'a dyn IsStation> + 'a> {
+ Box::new(self.trip.stops.iter().map(|s| s as &dyn IsStation))
+ }
+}
+
+impl std::fmt::Display for Stop {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.station.name)
+ }
+}
+
+impl OnBoardAPI for Iceportal {
+ fn apiurl(&self) -> &'static str {
+ "https://iceportal.de/api1/rs/tripInfo/trip"
+ }
+
+ fn request(
+ &self,
+ debug: bool
+ ) -> Result<Box<dyn OnBoardInfo>, serde_json::Error> {
+ onboard::request::<_, TripInfo>(self, debug)
+ }
+}