summaryrefslogtreecommitdiff
path: root/src/onboard/zugportal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/onboard/zugportal.rs')
-rw-r--r--src/onboard/zugportal.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/onboard/zugportal.rs b/src/onboard/zugportal.rs
new file mode 100644
index 0000000..0ad6cfd
--- /dev/null
+++ b/src/onboard/zugportal.rs
@@ -0,0 +1,109 @@
+/// implementation of traits to query zugportal.de
+/// (available at least in the Munich S-Bahn, maybe other trains)
+use chrono::{DateTime, Utc};
+use serde::Deserialize;
+
+use crate::onboard;
+use crate::onboard::{OnBoardAPI, OnBoardInfo};
+use crate::{traits::*, travelynx::TrainRef};
+
+pub struct Zugportal {}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct Journey {
+ name: String, // the line's name, e.g. S 8
+ no: i64,
+ stops: Vec<Stop>
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct Stop {
+ station: Station,
+ status: String, // one of "Normal", ...?
+ track: Track,
+ messages: Vec<String>,
+ arrival_time: Option<DepartureTime>,
+ departure_time: Option<DepartureTime>
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct Station {
+ eva_no: String,
+ name: String
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct Track {
+ target: String,
+ prediction: String
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct DepartureTime {
+ target: DateTime<Utc>,
+ predicted: DateTime<Utc>,
+ time_type: String, // one of REAL, PREVIEW, ..?
+ diff: i64 // diff in minutes?
+ // NOTE: also sends predictedTimeInMs and targetTimeInMs; these might be unix times
+}
+
+impl IsStation for Stop {
+ fn name(&self) -> &str {
+ &self.station.name
+ }
+
+ fn scheduled_arrival(&self) -> Option<&chrono::DateTime<Utc>> {
+ self.arrival_time.as_ref().map(|t| &t.target)
+ }
+
+ fn real_arrival(&self) -> Option<&chrono::DateTime<Utc>> {
+ self.arrival_time.as_ref().map(|t| &t.predicted)
+ }
+
+ fn ds100(&self) -> &str {
+ "??"
+ }
+}
+
+impl std::fmt::Display for Stop {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.station.name)
+ }
+}
+
+impl OnBoardInfo for Journey {
+ fn guess_last_station(&self) -> Option<&dyn IsStation> {
+ todo!()
+ }
+
+ fn get_train_ref(&self) -> TrainRef {
+ TrainRef {
+ _type: self.name.clone(),
+ no: self.no.to_string().clone()
+ }
+ }
+
+ fn stops<'a>(
+ &'a self
+ ) -> Box<dyn std::iter::Iterator<Item = &'a dyn IsStation> + 'a> {
+ Box::new(self.stops.iter().map(|s| s as &dyn IsStation))
+ }
+}
+
+impl OnBoardAPI for Zugportal {
+ fn apiurl(&self) -> &'static str {
+ "https://zugportal.de/prd/zupo-travel-information/api/public/ri/journey"
+ }
+
+ fn request(
+ &self,
+ debug: bool
+ ) -> Result<Box<dyn OnBoardInfo>, serde_json::Error> {
+ onboard::request::<_, Journey>(self, debug)
+ }
+}