From 5b7518ea061fe3e97c7a940adeb53949d94a89d2 Mon Sep 17 00:00:00 2001 From: tanneberger Date: Mon, 14 Oct 2024 06:01:16 +0200 Subject: [PATCH] adding test gtfs support --- Cargo.lock | 144 +++++++++++++++++++++++++++--------- Cargo.toml | 3 + src/main.rs | 6 +- src/routes/gtfs.rs | 179 +++++++++++++++++++++++++++++++++++++++++++++ src/routes/mod.rs | 1 + 5 files changed, 298 insertions(+), 35 deletions(-) create mode 100644 src/routes/gtfs.rs diff --git a/Cargo.lock b/Cargo.lock index a011ddf..ec866b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,7 +103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -298,7 +298,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -489,7 +489,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -500,7 +500,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -745,7 +745,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -929,7 +929,7 @@ dependencies = [ "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -938,7 +938,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" dependencies = [ - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -1124,7 +1124,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -1194,6 +1194,18 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "gtfs-realtime" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3112306a5404a41db6c25aa1779812040193bd1450f3b9c30808674d6240dab" +dependencies = [ + "prost 0.13.3", + "prost-build 0.13.3", + "prost-derive 0.13.3", + "serde", +] + [[package]] name = "h2" version = "0.3.22" @@ -1536,6 +1548,7 @@ dependencies = [ "derive_more", "env_logger", "futures", + "gtfs-realtime", "log", "rand", "redis", @@ -1728,7 +1741,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -1834,7 +1847,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -1898,6 +1911,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prettyplease" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +dependencies = [ + "proc-macro2", + "syn 2.0.79", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1924,9 +1947,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -1952,7 +1975,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.10.1", +] + +[[package]] +name = "prost" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" +dependencies = [ + "bytes", + "prost-derive 0.13.3", ] [[package]] @@ -1970,13 +2003,34 @@ dependencies = [ "log", "multimap", "petgraph", - "prost", - "prost-types", + "prost 0.10.4", + "prost-types 0.10.1", "regex", "tempfile", "which", ] +[[package]] +name = "prost-build" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" +dependencies = [ + "bytes", + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease 0.2.22", + "prost 0.13.3", + "prost-types 0.13.3", + "regex", + "syn 2.0.79", + "tempfile", +] + [[package]] name = "prost-derive" version = "0.10.1" @@ -1990,6 +2044,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "prost-types" version = "0.10.1" @@ -1997,14 +2064,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" dependencies = [ "bytes", - "prost", + "prost 0.10.4", +] + +[[package]] +name = "prost-types" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" +dependencies = [ + "prost 0.13.3", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2222,7 +2298,7 @@ dependencies = [ "quote", "rust-embed-utils", "shellexpand", - "syn 2.0.39", + "syn 2.0.79", "walkdir", ] @@ -2396,7 +2472,7 @@ checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -2545,9 +2621,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -2620,7 +2696,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -2678,7 +2754,7 @@ dependencies = [ "num-derive", "num-traits", "pbkdf2", - "prost", + "prost 0.10.4", "rand", "regex", "reqwest", @@ -2729,7 +2805,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -2787,8 +2863,8 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost", - "prost-derive", + "prost 0.10.4", + "prost-derive 0.10.1", "tokio", "tokio-stream", "tokio-util", @@ -2805,9 +2881,9 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9263bf4c9bfaae7317c1c2faf7f18491d2fe476f70c414b73bf5d445b00ffa1" dependencies = [ - "prettyplease", + "prettyplease 0.1.25", "proc-macro2", - "prost-build", + "prost-build 0.10.4", "quote", "syn 1.0.109", ] @@ -2883,7 +2959,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] @@ -3002,7 +3078,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.39", + "syn 2.0.79", "uuid", ] @@ -3090,7 +3166,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -3124,7 +3200,7 @@ checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3290,7 +3366,7 @@ checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.79", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index efe18a3..5781573 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,9 @@ env_logger = "0" log = "0" rand = "0" +# gtfs +gtfs-realtime = "0.1.0" + utoipa = { version = "3", features = ["actix_extras", "uuid"] } utoipa-swagger-ui = { version = "3", features = ["actix-web"] } regex = "1" diff --git a/src/main.rs b/src/main.rs index 5e26237..31d2b22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,11 @@ async fn main() -> std::io::Result<()> { .wrap(prometheus.clone()) .wrap(Logger::default()) .app_data(web::Data::new(redis_connectionpool.clone())) - .service(web::scope("/v1").service(routes::vehicles::vehicles_list)) + .service( + web::scope("/v1") + .service(routes::vehicles::vehicles_list) + .service(routes::gtfs::gtfs_live_data), + ) .service( SwaggerUi::new("/swagger-ui/{_:.*}") .url("/api-doc/openapi.json", routes::ApiDoc::openapi()), diff --git a/src/routes/gtfs.rs b/src/routes/gtfs.rs new file mode 100644 index 0000000..d0ba222 --- /dev/null +++ b/src/routes/gtfs.rs @@ -0,0 +1,179 @@ +use crate::routes::ServerError; + +use tlms::locations::waypoint::Waypoint; + +use actix_web::{get, web, HttpRequest}; +use log::error; +use redis::{Client, Commands}; +use serde::Serialize; +use std::time::SystemTime; +use std::time::UNIX_EPOCH; + +use gtfs_realtime::{FeedEntity, FeedMessage}; + +#[derive(Debug, Clone, Serialize)] +pub struct LizardResults { + pub vehicle_positions: FeedMessage, + pub trip_updates: FeedMessage, +} + +/// will return a list of all vehicles inside this region with their last seen position +#[utoipa::path( + get, + path = "/v1/gtfs/{region}/", + params( + ("region" = i64, Path, description = "Identitier of the region") + ), + responses( + (status = 200, description = "gtfs information for the specified region"), + (status = 500, description = "postgres pool error"), + ), +)] +#[get("/gtfs/{region}")] +pub async fn gtfs_live_data( + _req: HttpRequest, + path: web::Path<(i64,)>, + redis_pool: web::Data, +) -> Result, ServerError> { + let mut redis_connection = match redis_pool.get_connection() { + Ok(value) => value, + Err(e) => { + error!("cannot fetch redis connection {:?}", e); + return Err(ServerError::InternalError); + } + }; + + let waypoint_string: String = match redis_connection.get(format!("r{}", path.0)) { + Ok(value) => value, + Err(e) => { + error!("cannot find region with this key {:?}", e); + return Err(ServerError::BadClientData); + } + }; + + let waypoints: Vec = match serde_json::from_str(&waypoint_string) { + Ok(value) => value, + Err(e) => { + error!( + "cannot deserialize value from redis with error {:?} and value {}", + e, &waypoint_string + ); + return Err(ServerError::InternalError); + } + }; + + let feed_entities = waypoints.into_iter().map(|waypoint| { + let vehicle_number = waypoint.line * 1000 + waypoint.run; + + let position_entity = FeedEntity { + id: vehicle_number.to_string(), + stop: None, + trip_modifications: None, + is_deleted: None, + trip_update: None, + vehicle: Some(gtfs_realtime::VehiclePosition { + trip: Some(gtfs_realtime::TripDescriptor { + modified_trip: None, + trip_id: Some(vehicle_number.to_string()), + route_id: Some(waypoint.line.to_string()), + direction_id: None, + start_time: None, + start_date: None, + schedule_relationship: None, + }), + vehicle: None, + position: Some(gtfs_realtime::Position { + latitude: waypoint.lat as f32, + longitude: waypoint.lon as f32, + bearing: None, + odometer: None, + speed: None, + }), + current_status: None, + current_stop_sequence: None, + stop_id: None, + timestamp: Some( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(), + ), + congestion_level: None, + occupancy_percentage: None, + occupancy_status: None, + multi_carriage_details: vec![], + }), + alert: None, + shape: None, + }; + + let trip_entity: FeedEntity = FeedEntity { + id: vehicle_number.to_string(), + vehicle: None, + alert: None, + shape: None, + stop: None, + trip_modifications: None, + is_deleted: None, + trip_update: Some(gtfs_realtime::TripUpdate { + trip: gtfs_realtime::TripDescriptor { + modified_trip: None, + trip_id: Some(vehicle_number.to_string()), + route_id: Some(waypoint.line.to_string()), + direction_id: None, + start_time: None, + start_date: None, + schedule_relationship: None, + }, + vehicle: Some(gtfs_realtime::VehicleDescriptor { + id: Some(vehicle_number.to_string()), + label: None, + license_plate: None, + wheelchair_accessible: None, + }), + stop_time_update: Vec::new(), + timestamp: Some( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(), + ), + delay: waypoint.delayed.map(|x| x as i32), + trip_properties: None, + }), + }; + + (position_entity, trip_entity) + }); + + let (vehicle_positions, trip_updates) = feed_entities.unzip(); + + Ok(web::Json(LizardResults { + vehicle_positions: gtfs_realtime::FeedMessage { + entity: vehicle_positions, + header: gtfs_realtime::FeedHeader { + timestamp: Some( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(), + ), + gtfs_realtime_version: String::from("2.0"), + incrementality: None, + }, + }, + trip_updates: gtfs_realtime::FeedMessage { + entity: trip_updates, + header: gtfs_realtime::FeedHeader { + timestamp: Some( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(), + ), + gtfs_realtime_version: String::from("2.0"), + incrementality: None, + }, + }, + })) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 5b4b71c..f9c6ec3 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,3 +1,4 @@ +pub mod gtfs; pub mod vehicles; use actix_web::{