diff --git a/Cargo.lock b/Cargo.lock index 01fce5d..106f490 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,12 +89,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "autocfg" version = "1.4.0" @@ -173,6 +167,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.39" @@ -199,16 +199,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -325,21 +315,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -434,8 +409,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -469,25 +446,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "h2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.2.0", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "hashbrown" version = "0.15.2" @@ -593,7 +551,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", + "h2", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -616,7 +574,6 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.7", "http 1.2.0", "http-body 1.0.1", "httparse", @@ -642,22 +599,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.5.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", + "webpki-roots 0.26.11", ] [[package]] @@ -1006,23 +948,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1073,50 +998,6 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "openssl" -version = "0.10.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "overload" version = "0.1.1" @@ -1187,12 +1068,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - [[package]] name = "powerfmt" version = "0.2.0" @@ -1230,6 +1105,58 @@ dependencies = [ "yansi", ] +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.37" @@ -1350,38 +1277,37 @@ checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64", "bytes", - "encoding_rs", "futures-core", "futures-util", - "h2 0.4.7", "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", "hyper-rustls", - "hyper-tls", "hyper-util", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", - "tokio-native-tls", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.26.11", "windows-registry", ] @@ -1487,6 +1413,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustix" version = "0.38.42" @@ -1507,6 +1439,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -1527,6 +1460,9 @@ name = "rustls-pki-types" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" @@ -1551,15 +1487,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -1572,29 +1499,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" version = "1.0.215" @@ -1764,27 +1668,6 @@ dependencies = [ "syn", ] -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tempfile" version = "3.14.0" @@ -1798,6 +1681,26 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -1849,6 +1752,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.42.0" @@ -1877,16 +1795,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.1" @@ -2113,12 +2021,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -2216,6 +2118,34 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.1", +] + +[[package]] +name = "webpki-roots" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 9052643..c8dfc0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] chrono = { version = "0.4.39", features = ["serde"] } html-escape = "0.2.13" -reqwest = "0.12.9" +reqwest = { version = "0.12.9", default-features = false, features = ["rustls-tls"] } rocket = "0.5.1" serde = { version = "1.0.215", features = ["derive"] } serde_json = "1.0.133" diff --git a/src/api.rs b/src/api.rs index 37265c6..970c2ee 100644 --- a/src/api.rs +++ b/src/api.rs @@ -10,15 +10,13 @@ use serde::Deserialize; pub struct ApiClient { pub swu_stop_number: u32, pub swu_api_limit: u8, + pub stop_name: String, pub departures: Vec, pub directions: HashMap>>, pub directions_last_save: Option, } impl ApiClient { - pub fn new() -> Self { - Self::new_custom(1240) - } pub fn new_custom(swu_stop_number: u32) -> Self { Self::new_custom_with_limit(swu_stop_number, 30) } @@ -26,6 +24,7 @@ impl ApiClient { Self { swu_stop_number, swu_api_limit, + stop_name: String::new(), departures: vec![], directions: HashMap::new(), directions_last_save: None, @@ -33,7 +32,8 @@ impl ApiClient { } pub async fn api_get(&mut self) -> Result<(), String> { // get departures - let departures = self.api_get_departures().await?; + let (stop_name, departures) = self.api_get_departures().await?; + self.stop_name = stop_name; let mut should_save = false; @@ -120,7 +120,7 @@ impl ApiClient { Ok(()) } - async fn api_get_departures(&self) -> Result, String> { + async fn api_get_departures(&self) -> Result<(String, Vec), String> { match get(format!( "https://api.swu.de/mobility/v1/stop/passage/Departures?StopNumber={}&Limit={}", self.swu_stop_number, self.swu_api_limit @@ -129,7 +129,10 @@ impl ApiClient { { Ok(response) => match response.text().await { Ok(response) => match serde_json::from_str::(&response) { - Ok(response) => Ok(response.stop_passage.departure_data), + Ok(response) => Ok(( + response.stop_passage.stop_name, + response.stop_passage.departure_data, + )), Err(e) => Err(format!("{}\n{}", e, response)), }, Err(e) => Err(e.to_string()), @@ -346,6 +349,8 @@ struct ResDepartures { } #[derive(Deserialize)] struct ResStopPassage { + #[serde(rename = "StopName")] + pub stop_name: String, #[serde(rename = "DepartureData")] pub departure_data: Vec, } diff --git a/src/cache.rs b/src/cache.rs index cc216e0..91bf9fa 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,4 +1,4 @@ -use std::time::Duration; +use std::{collections::BTreeMap, sync::Arc, time::Duration}; use chrono::DateTime; use tokio::{sync::Mutex, time::Instant}; @@ -6,14 +6,18 @@ use tokio::{sync::Mutex, time::Instant}; use crate::api::{bahnhof_get_departures, ApiClient}; pub struct Cache { + pub list: String, pub index: String, pub nojs: String, - pub data: Mutex, - pub api_client: Mutex, - pub api_next_update: Mutex, + pub stops: Mutex>>>, pub bahnhof_html: Mutex, pub bahnhof_next_update: Mutex, } +pub struct StopCache { + pub data: Data, + pub api_client: ApiClient, + pub api_next_update: Instant, +} pub struct Data { pub seq: u8, pub departures: Vec, @@ -28,82 +32,49 @@ pub struct Departure { pub scheduled_time: Option>, pub direction: Option, } + impl Cache { - pub fn new(index: String, nojs: String, swu_stop_number: Option) -> Self { - let now = Instant::now(); - Self { - index, - nojs, - data: Mutex::new(Data { + pub async fn stop<'a>(&'a self, swu_stop_number: u32) -> Arc> { + let mut stops = self.stops.lock().await; + let stop = if let Some(stop) = stops.get(&swu_stop_number) { + Arc::clone(stop) + } else { + Arc::clone( + stops + .entry(swu_stop_number) + .or_insert(Arc::new(Mutex::new(StopCache::new(swu_stop_number).await))), + ) + }; + drop(stops); + stop + } +} + +impl StopCache { + pub async fn new(swu_stop_number: u32) -> Self { + let mut s = Self { + data: Data { seq: 0, departures: vec![], - }), - api_client: Mutex::new(if let Some(swu_stop_number) = swu_stop_number { - ApiClient::new_custom(swu_stop_number) - } else { - ApiClient::new() - }), - api_next_update: Mutex::new(now), - bahnhof_html: Mutex::new(String::new()), - bahnhof_next_update: Mutex::new(now), + }, + api_client: ApiClient::new_custom(swu_stop_number), + api_next_update: Instant::now(), + }; + if let Err(e) = s.api_client.directions_load().await { + eprintln!("No direction data loaded: {e}"); } + s } - pub async fn update_swu(&self) -> Duration { - let mut next_update = self.api_next_update.lock().await; - let now = Instant::now(); - if now >= *next_update { - let delay = Duration::from_secs(14); - let mut api = self.api_client.lock().await; - match api.api_get().await { - Ok(()) => { - // TODO: find changes - // increment sequence number thingy (ze counting boi) - let mut data = self.data.lock().await; - data.seq += 1; - if data.seq >= 10 { - data.seq = 0; - } - // store departures - let departures = api - .departures - .iter() - .map(|departure| { - let direction = departure - .route_name - .as_ref() - .and_then(|rn| { - departure.departure_direction_text.as_ref().and_then(|dt| { - api.directions - .get(rn) - .and_then(|v| v.get(dt).and_then(|v| v.as_ref())) - }) - }) - .filter(|(_, _, success)| *success > 2) - .map(|(_, dir, _)| *dir); - Departure { - route_name: departure.route_name.clone(), - departure_direction_text: departure - .departure_direction_text - .clone(), - vehicle_number: departure.vehicle_number, - departure_time: departure - .departure_time_actual - .as_ref() - .or(departure.departure_time_scheduled.as_ref()) - .cloned(), - scheduled_time: departure.departure_time_scheduled.clone(), - direction, - } - }) - .collect(); - data.departures = departures; - } - Err(e) => eprintln!("Couldn't get departures from swu: {e}"), - } - *next_update = Instant::now() + delay; - delay - } else { - *next_update - now +} +impl Cache { + pub fn new(list: String, index: String, nojs: String) -> Self { + Self { + list, + index, + nojs, + stops: Mutex::new(Default::default()), + bahnhof_html: Mutex::new(String::new()), + bahnhof_next_update: Mutex::new(Instant::now()), } } @@ -126,3 +97,63 @@ impl Cache { } } } + +impl StopCache { + pub async fn update_swu(&mut self) -> Duration { + let now = Instant::now(); + if now >= self.api_next_update { + let delay = Duration::from_secs(14); + match self.api_client.api_get().await { + Ok(()) => { + // TODO: find changes + // increment sequence number thingy (ze counting boi) + self.data.seq += 1; + if self.data.seq >= 10 { + self.data.seq = 0; + } + // store departures + let departures = self + .api_client + .departures + .iter() + .map(|departure| { + let direction = departure + .route_name + .as_ref() + .and_then(|rn| { + departure.departure_direction_text.as_ref().and_then(|dt| { + self.api_client + .directions + .get(rn) + .and_then(|v| v.get(dt).and_then(|v| v.as_ref())) + }) + }) + .filter(|(_, _, success)| *success > 2) + .map(|(_, dir, _)| *dir); + Departure { + route_name: departure.route_name.clone(), + departure_direction_text: departure + .departure_direction_text + .clone(), + vehicle_number: departure.vehicle_number, + departure_time: departure + .departure_time_actual + .as_ref() + .or(departure.departure_time_scheduled.as_ref()) + .cloned(), + scheduled_time: departure.departure_time_scheduled.clone(), + direction, + } + }) + .collect(); + self.data.departures = departures; + } + Err(e) => eprintln!("Couldn't get departures from swu: {e}"), + } + self.api_next_update = Instant::now() + delay; + delay + } else { + self.api_next_update - now + } + } +} diff --git a/src/index.html b/src/index.html index 6da9a05..ab39e83 100644 --- a/src/index.html +++ b/src/index.html @@ -45,7 +45,7 @@ const sleep = ms => new Promise(r => setTimeout(r, ms)); setInterval(doRepeatedFast, 500); -fetchUniAllRepeated(); +fetchUniAllRepeated(true); async function doRepeatedFast() { await rebuildDepartureElements(); } @@ -70,7 +70,8 @@ function getRouteColumn(route) { const newColumn = document.createElement("table"); const columnHeaderRow = document.createElement("tr"); const columnHeaderData = document.createElement("td"); - columnHeaderData.innerText = "Linie " + route; + columnHeaderData.innerHTML = "Linie "; + columnHeaderData.append(route); columnHeaderData.style.fontSize = "3em"; columnHeaderData.style.textDecoration = "underline gray"; columnHeaderRow.appendChild(columnHeaderData); @@ -124,12 +125,14 @@ var currentSeq = 0; var resUniAll = []; var secondsUntilNextUpdate = 0; -async function fetchUniAllRepeated() { +async function fetchUniAllRepeated(firstTime) { + let first = firstTime; while (true) { var doneFetching = false; while (!doneFetching) { try { - await fetchUniAll(); + await fetchUniAll(first); + first = false; doneFetching = true; } catch (e) { console.log(e); @@ -158,7 +161,7 @@ async function fetchUniAllRepeated() { } } -async function fetchUniAll() { +async function fetchUniAll(first) { const resUniAllText = await (await fetch("./uni/all")).text(); const prevResUniAll = resUniAll; resUniAll = []; @@ -172,6 +175,9 @@ async function fetchUniAll() { const furtherSplitLine = resUniAllLine.substring(1).split("#"); currentSeq = parseInt(furtherSplitLine[0]); secondsUntilNextUpdate = parseInt(furtherSplitLine[1]); + if (first && furtherSplitLine.length > 2 && furtherSplitLine[2].trim()) { + document.title = furtherSplitLine[2].trim() + " - " + document.title; + } } else if (resUniAllLine.startsWith("-")) { resUniThis.elem = document.createElement("td"); getTripRow(resUniThis.route, resUniThis.vehicle, resUniThis.scheduledTime).replaceChildren(resUniThis.elem); @@ -193,12 +199,15 @@ async function fetchUniAll() { resUniThis[resUniAllLine.substring(0, 1)] = resUniAllLine.substring(1); } } - for (const column of document.getElementById("routesTable").firstChild.children) { - if (column.childElementCount <= 1) { - column.remove(); - let columnWidthPercent = (99 / routesTable.childElementCount) + "vw"; - for (const column of routesTable.children) { - column.style.width = columnWidthPercent; + let columnsContainer = document.getElementById("routesTable").firstChild; + if (columnsContainer) { + for (const column of columnsContainer.children) { + if (column.childElementCount <= 1) { + column.remove(); + let columnWidthPercent = (99 / routesTable.childElementCount) + "vw"; + for (const column of routesTable.children) { + column.style.width = columnWidthPercent; + } } } } diff --git a/src/list.html b/src/list.html new file mode 100644 index 0000000..a3dc2b9 --- /dev/null +++ b/src/list.html @@ -0,0 +1,21 @@ + + + + + + +ulm öpnv abfahrten + + + + + + + diff --git a/src/main.rs b/src/main.rs index 751ba3c..2e171c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,21 +7,30 @@ use cache::Cache; use rocket::{get, response::content::RawHtml, routes, State}; #[get("/")] -fn index(cache: &State>) -> RawHtml<&str> { +fn list(cache: &State>) -> RawHtml<&str> { + RawHtml(&cache.list) +} + +#[get("/<_swu_stop_number>")] +fn index(cache: &State>, _swu_stop_number: u32) -> RawHtml<&str> { RawHtml(&cache.index) } -#[get("/favicon.ico")] -fn favicon() -> &'static [u8] { +#[get("/<_swu_stop_number>/favicon.ico")] +fn favicon(_swu_stop_number: u32) -> &'static [u8] { include_bytes!("favicon.ico") } -#[get("/uni/all")] -async fn uni_all(cache: &State>) -> RawHtml { - let seconds_until_next_update = cache.update_swu().await.as_secs() + 1; - let data = cache.data.lock().await; - let mut o = format!("#{}#{}", data.seq, seconds_until_next_update); - for departure in data.departures.iter() { +#[get("//uni/all")] +async fn uni_all(cache: &State>, swu_stop_number: u32) -> RawHtml { + let stop = cache.stop(swu_stop_number).await; + let mut stop = stop.lock().await; + let seconds_until_next_update = stop.update_swu().await.as_secs() + 1; + let mut o = format!( + "#{}#{}#{}", + stop.data.seq, seconds_until_next_update, stop.api_client.stop_name, + ); + for departure in stop.data.departures.iter() { if let Some(route) = &departure.route_name { o.push_str("\nR"); o.push_str(route); @@ -47,21 +56,23 @@ async fn uni_all(cache: &State>) -> RawHtml { o.push_str("\n-"); // v.route_name } + drop(stop); RawHtml(o) } -#[get("/bf/all")] -async fn bf_all(cache: &State>) -> String { +#[get("/<_swu_stop_number>/bf/all")] +async fn bf_all(cache: &State>, _swu_stop_number: u32) -> String { cache.update_bahn().await; cache.bahnhof_html.lock().await.clone() } -#[get("/nojs")] -async fn nojs(cache: &State>) -> RawHtml { +#[get("//nojs")] +async fn nojs(cache: &State>, swu_stop_number: u32) -> RawHtml { let mut html = cache.nojs.clone(); html.push_str("\n"); - cache.update_swu().await; - let data = cache.data.lock().await; + let stop = cache.stop(swu_stop_number).await; + let mut stop = stop.lock().await; + stop.update_swu().await; let mut routes = BTreeMap::>::new(); #[derive(PartialEq, Eq)] struct StrOrderedByLen<'a>(&'a str); @@ -78,7 +89,7 @@ async fn nojs(cache: &State>) -> RawHtml { .then_with(|| self.0.cmp(other.0)) } } - for departure in data.departures.iter() { + for departure in stop.data.departures.iter() { if let Some(route_name) = &departure.route_name { if let Some(route) = routes.get_mut(&StrOrderedByLen(route_name.as_str())) { route.push(departure); @@ -149,7 +160,7 @@ async fn nojs(cache: &State>) -> RawHtml { html.push_str("\n"); } } - drop(data); + drop(stop); html.push_str("\n"); html.push_str("\n"); RawHtml(html) @@ -158,23 +169,19 @@ async fn nojs(cache: &State>) -> RawHtml { #[rocket::main] async fn main() -> Result<(), rocket::Error> { let cache = Arc::new(Cache::new( + std::fs::read_to_string("list.html") + .ok() + .unwrap_or_else(|| include_str!("list.html").to_owned()), std::fs::read_to_string("index.html") .ok() .unwrap_or_else(|| include_str!("index.html").to_owned()), std::fs::read_to_string("nojs.html") .ok() .unwrap_or_else(|| include_str!("nojs.html").to_owned()), - std::env::args().nth(1).map(|v| { - v.parse() - .expect("argument must be an integer (Haltestelle als SWU Stop-Number)") - }), )); - if let Err(e) = cache.api_client.lock().await.directions_load().await { - eprintln!("No direction data loaded: {e}"); - } let rocket = rocket::build() .manage(Arc::clone(&cache)) - .mount("/", routes![index, nojs, favicon, uni_all, bf_all]) + .mount("/", routes![list, index, nojs, favicon, uni_all, bf_all]) .ignite() .await?; // should not be necessary anymore