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}