wl_realtime_ogd/
models.rs

1use chrono::{DateTime, FixedOffset};
2use serde::{Deserialize, Deserializer, Serialize};
3use std::{error::Error, fmt::Display};
4
5use crate::{
6    helpers::join_vec,
7    serde_deserializers::{date_format, optional_date_format},
8};
9
10const WL_ENDPOINT: &str = "https://www.wienerlinien.at/ogd_realtime";
11
12pub trait BuildRequestUrl {
13    fn build_request_url(&self) -> String;
14}
15
16#[derive(Debug, Clone, PartialEq)]
17pub struct MonitorRequest {
18    pub stop_id: Vec<u32>,
19    pub diva: Option<u32>,
20    pub activate_traffic_info: Vec<ExtTrafficInfoEnum>,
21    pub a_area: bool,
22}
23
24impl MonitorRequest {
25    pub fn new() -> Self {
26        MonitorRequest {
27            activate_traffic_info: vec![],
28            stop_id: vec![],
29            diva: None,
30            a_area: false,
31        }
32    }
33
34    pub async fn run(&self) -> Result<MonitorResponse, Box<dyn Error>> {
35        let url = WL_ENDPOINT.to_owned() + &self.build_request_url();
36        let response = reqwest::get(url).await?.json::<MonitorResponse>().await?;
37        Ok(response)
38    }
39}
40
41impl Default for MonitorRequest {
42    fn default() -> Self {
43        MonitorRequest::new()
44    }
45}
46
47impl BuildRequestUrl for MonitorRequest {
48    fn build_request_url(&self) -> String {
49        let mut url = String::from("/monitor?");
50        let mut url_segments: Vec<String> = vec![];
51        if !self.stop_id.is_empty() {
52            let mut stops = join_vec("stopId=", &self.stop_id);
53            url_segments.append(&mut stops);
54        }
55        if self.diva.is_some() {
56            url_segments.push(format!("diva={}", self.diva.unwrap()));
57        }
58        if !self.activate_traffic_info.is_empty() {
59            let mut traffic_info = join_vec("activateTrafficInfo=", &self.activate_traffic_info);
60            url_segments.append(&mut traffic_info);
61        }
62        if self.a_area {
63            url_segments.push(String::from("aArea=1"));
64        }
65
66        url.push_str(&url_segments.join("&"));
67        url
68    }
69}
70
71#[derive(Debug, Clone, PartialEq)]
72pub struct TrafficInfoListRequest {
73    pub related_line: Vec<String>,
74    pub related_stop: Vec<u32>,
75    pub name: Vec<TrafficInfoEnum>,
76}
77
78impl TrafficInfoListRequest {
79    pub fn new() -> Self {
80        TrafficInfoListRequest {
81            related_line: vec![],
82            related_stop: vec![],
83            name: vec![],
84        }
85    }
86
87    pub async fn run(&self) -> Result<TrafficInfoListResponse, Box<dyn Error>> {
88        let url = WL_ENDPOINT.to_owned() + &self.build_request_url();
89        let response = reqwest::get(url)
90            .await?
91            .json::<TrafficInfoListResponse>()
92            .await?;
93        Ok(response)
94    }
95}
96
97impl Default for TrafficInfoListRequest {
98    fn default() -> Self {
99        TrafficInfoListRequest::new()
100    }
101}
102
103impl BuildRequestUrl for TrafficInfoListRequest {
104    fn build_request_url(&self) -> String {
105        let mut url = String::from("/trafficInfoList?");
106        let mut url_segments: Vec<String> = vec![];
107        if !self.related_line.is_empty() {
108            let mut lines = join_vec("relatedLine=", &self.related_line);
109            url_segments.append(&mut lines);
110        }
111        if !self.related_stop.is_empty() {
112            let mut stops = join_vec("relatedStop=", &self.related_stop);
113            url_segments.append(&mut stops);
114        }
115        if !self.name.is_empty() {
116            let mut names = join_vec("name=", &self.name);
117            url_segments.append(&mut names);
118        }
119
120        url.push_str(&url_segments.join("&"));
121        url
122    }
123}
124
125#[derive(Serialize, Debug, Clone, PartialEq)]
126pub enum TrafficInfoEnum {
127    StoerungLang,
128    StoerungKurz,
129    AufzugsInfo,
130    FahrtreppenInfo,
131}
132
133impl Display for TrafficInfoEnum {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        let str: &str = match self {
136            TrafficInfoEnum::StoerungLang => "stoerunglang",
137            TrafficInfoEnum::StoerungKurz => "stoerungkurz",
138            TrafficInfoEnum::AufzugsInfo => "aufzugsinfo",
139            TrafficInfoEnum::FahrtreppenInfo => "fahrtreppeninfo",
140        };
141        write!(f, "{}", str)
142    }
143}
144
145#[derive(Serialize, Debug, Clone, PartialEq)]
146pub enum ExtTrafficInfoEnum {
147    TrafficInfo(TrafficInfoEnum),
148    Information,
149}
150
151impl Display for ExtTrafficInfoEnum {
152    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153        match self {
154            ExtTrafficInfoEnum::Information => write!(f, "information"),
155            ExtTrafficInfoEnum::TrafficInfo(other) => other.fmt(f),
156        }
157    }
158}
159
160#[derive(Debug, Clone, PartialEq)]
161pub enum MessageCode {
162    OK = 1,
163    DbOffline = 311,
164    StopDoesNotExist = 312,
165    RequestLimitExceeded = 316,
166    GetParamInvalid = 320,
167    GetParamMissing = 321,
168    NoDataFound = 322,
169}
170
171impl<'de> Deserialize<'de> for MessageCode {
172    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
173    where
174        D: Deserializer<'de>,
175    {
176        let code: u32 = Deserialize::deserialize(deserializer)?;
177
178        match code {
179            1 => Ok(MessageCode::OK),
180            311 => Ok(MessageCode::DbOffline),
181            312 => Ok(MessageCode::StopDoesNotExist),
182            316 => Ok(MessageCode::RequestLimitExceeded),
183            320 => Ok(MessageCode::GetParamInvalid),
184            321 => Ok(MessageCode::GetParamMissing),
185            322 => Ok(MessageCode::NoDataFound),
186            _ => Err(serde::de::Error::custom(format!(
187                "Unknown message code: {}",
188                code
189            ))),
190        }
191    }
192}
193
194#[derive(Debug, Deserialize, Clone, PartialEq)]
195pub struct Message {
196    pub value: String,
197    #[serde(rename = "messageCode")]
198    pub message_code: MessageCode,
199    #[serde(rename = "serverTime", with = "date_format")]
200    pub server_time: DateTime<FixedOffset>,
201}
202
203#[derive(Debug, Deserialize, Clone, PartialEq)]
204pub struct Response {
205    pub message: Message,
206}
207
208#[derive(Debug, Deserialize, Clone, PartialEq)]
209pub struct Geometry {
210    #[serde(rename = "type")]
211    pub geometry_type: String,
212    pub coordinates: Vec<f64>,
213}
214
215#[derive(Debug, Deserialize, Clone, PartialEq)]
216pub struct Attributes {
217    pub rbl: i32,
218}
219
220#[derive(Debug, Deserialize, Clone, PartialEq)]
221pub struct Properties {
222    pub name: String,
223    pub title: String,
224    pub municipality: String,
225    #[serde(rename = "municipalityId")]
226    pub municipality_id: i32,
227    #[serde(rename = "type")]
228    pub stop_type: String,
229    #[serde(rename = "coordName")]
230    pub coord_name: String,
231    pub attributes: Attributes,
232}
233
234#[derive(Debug, Deserialize, Clone, PartialEq)]
235pub struct LocationStop {
236    #[serde(rename = "type")]
237    pub location_type: String,
238    pub geometry: Geometry,
239    pub properties: Properties,
240}
241
242#[derive(Debug, Deserialize, Clone, PartialEq)]
243pub struct DepartureTime {
244    #[serde(rename = "timePlanned", with = "date_format")]
245    pub time_planned: DateTime<FixedOffset>,
246    #[serde(rename = "timeReal", default, with = "optional_date_format")]
247    pub time_real: Option<DateTime<FixedOffset>>,
248    pub countdown: i32,
249}
250
251#[derive(Debug, Deserialize, Clone, PartialEq)]
252pub struct Vehicle {
253    pub name: String,
254    pub towards: String,
255    pub direction: String,
256    #[serde(rename = "richtungsId")]
257    pub richtungs_id: String,
258    #[serde(rename = "barrierFree")]
259    pub barrier_free: bool,
260    #[serde(rename = "realtimeSupported")]
261    pub realtime_supported: bool,
262    pub trafficjam: bool,
263    #[serde(rename = "type")]
264    pub vehicle_type: String,
265}
266
267#[derive(Debug, Deserialize, Clone, PartialEq)]
268pub struct Departure {
269    #[serde(rename = "departureTime")]
270    pub departure_time: DepartureTime,
271    pub vehicle: Option<Vehicle>,
272}
273
274#[derive(Debug, Deserialize, Clone, PartialEq)]
275pub struct Departures {
276    pub departure: Vec<Departure>,
277}
278
279#[derive(Debug, Deserialize, Clone, PartialEq)]
280pub struct Line {
281    pub name: String,
282    pub towards: String,
283    pub direction: String,
284    #[serde(rename = "richtungsId")]
285    pub richtungs_id: String,
286    #[serde(rename = "barrierFree")]
287    pub barrier_free: bool,
288    #[serde(rename = "realtimeSupported")]
289    pub realtime_supported: bool,
290    pub trafficjam: bool,
291    pub departures: Departures,
292    #[serde(rename = "type")]
293    pub line_type: String,
294    #[serde(rename = "lineId")]
295    pub line_id: Option<i32>,
296}
297
298#[derive(Debug, Deserialize, Clone, PartialEq)]
299pub struct Monitor {
300    #[serde(rename = "locationStop")]
301    pub location_stop: LocationStop,
302    pub lines: Vec<Line>,
303    #[serde(rename = "refTrafficInfoNames")]
304    pub ref_traffic_info_names: Option<Vec<String>>,
305}
306
307#[derive(Debug, Deserialize, Clone, PartialEq)]
308pub struct Time {
309    #[serde(default, with = "optional_date_format")]
310    pub start: Option<DateTime<FixedOffset>>,
311    #[serde(default, with = "optional_date_format")]
312    pub end: Option<DateTime<FixedOffset>>,
313    #[serde(default, with = "optional_date_format")]
314    pub resume: Option<DateTime<FixedOffset>>,
315}
316
317#[derive(Debug, Deserialize, Clone, PartialEq)]
318pub struct AttributesTrafficInfo {
319    pub status: Option<String>,
320    pub station: Option<String>,
321    pub location: Option<String>,
322    pub reason: Option<String>,
323    pub towards: Option<String>,
324    #[serde(rename = "relatedLines")]
325    pub related_lines: Option<Vec<String>>,
326    #[serde(rename = "relatedStops")]
327    pub related_stops: Option<Vec<u32>>,
328}
329
330#[derive(Debug, Deserialize, Clone, PartialEq)]
331pub struct TrafficInfo {
332    #[serde(rename = "refTrafficInfoCategoryId")]
333    pub ref_traffic_info_category_id: i32,
334    pub name: String,
335    pub priority: Option<String>,
336    pub owner: Option<String>,
337    pub title: String,
338    pub description: String,
339    pub time: Option<Time>,
340    pub attributes: Option<AttributesTrafficInfo>,
341    #[serde(rename = "relatedLines")]
342    pub related_lines: Option<Vec<String>>,
343    #[serde(rename = "relatedStops")]
344    pub related_stops: Option<Vec<i32>>,
345}
346
347#[derive(Debug, Deserialize, Clone, PartialEq)]
348pub struct TrafficInfoCategory {
349    pub id: i32,
350    #[serde(rename = "refTrafficInfoCategoryGroupId")]
351    pub ref_traffic_info_category_group_id: i32,
352    pub name: String,
353    #[serde(rename = "trafficInfoNameList")]
354    pub traffic_info_name_list: String,
355    pub title: String,
356}
357
358#[derive(Debug, Deserialize, Clone, PartialEq)]
359pub struct TrafficInfoCategoryGroup {
360    pub id: i32,
361    pub name: String,
362}
363
364#[derive(Debug, Deserialize, Clone, PartialEq)]
365pub struct MonitorResponseData {
366    pub monitors: Vec<Monitor>,
367    #[serde(rename = "trafficInfos")]
368    pub traffic_infos: Option<Vec<TrafficInfo>>,
369    #[serde(rename = "trafficInfoCategories")]
370    pub traffic_info_categories: Option<Vec<TrafficInfoCategory>>,
371    #[serde(rename = "trafficInfoCategoryGroups")]
372    pub traffic_info_category_groups: Option<Vec<TrafficInfoCategoryGroup>>,
373}
374
375#[derive(Debug, Deserialize, Clone, PartialEq)]
376pub struct MonitorResponse {
377    pub message: Message,
378    pub data: MonitorResponseData,
379}
380
381#[derive(Debug, Deserialize, Clone, PartialEq)]
382pub struct TrafficInfoListResponseData {
383    #[serde(rename = "trafficInfos")]
384    pub traffic_infos: Option<Vec<TrafficInfo>>,
385    #[serde(rename = "trafficInfoCategories")]
386    pub traffic_info_categories: Option<Vec<TrafficInfoCategory>>,
387    #[serde(rename = "trafficInfoCategoryGroups")]
388    pub traffic_info_category_groups: Option<Vec<TrafficInfoCategoryGroup>>,
389}
390
391#[derive(Debug, Deserialize, Clone, PartialEq)]
392pub struct TrafficInfoListResponse {
393    pub message: Message,
394    pub data: TrafficInfoListResponseData,
395}