railway-provider-db-movas-0.2.0/.cargo_vcs_info.json0000644000000001670000000000100160450ustar { "git": { "sha1": "e328905c7c5270a1f94ac9edc7f50f664ac9ac19" }, "path_in_vcs": "railway-provider-db-movas" }railway-provider-db-movas-0.2.0/Cargo.lock0000644000000675230000000000100140310ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "addr2line" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anstream" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", "windows-sys", ] [[package]] name = "approx" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" dependencies = [ "num-traits", ] [[package]] name = "async-trait" version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", "windows-targets", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cc" version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "shlex", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-targets", ] [[package]] name = "chrono-tz" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" dependencies = [ "chrono", "chrono-tz-build", "phf", ] [[package]] name = "chrono-tz-build" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" dependencies = [ "parse-zoneinfo", "phf", "phf_codegen", ] [[package]] name = "colorchoice" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "env_filter" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", ] [[package]] name = "env_logger" version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", "env_filter", "humantime", "log", ] [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "geo-types" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bd1157f0f936bf0cd68dec91e8f7c311afe60295574d62b70d4861a1bfdf2d9" dependencies = [ "approx", "num-traits", "serde", ] [[package]] name = "geojson" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d728c1df1fbf328d74151efe6cb0586f79ee813346ea981add69bd22c9241b" dependencies = [ "geo-types", "log", "serde", "serde_json", "thiserror", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "icu_collections" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_locid_transform" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_locid_transform_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "utf16_iter", "utf8_iter", "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "displaydoc", "icu_collections", "icu_locid_transform", "icu_properties_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" [[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", "icu_provider_macros", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_provider_macros" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "idna" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libm" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "litemap" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "log" version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] [[package]] name = "object" version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "parse-zoneinfo" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" dependencies = [ "regex", ] [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_shared", ] [[package]] name = "phf_codegen" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", "phf_shared", ] [[package]] name = "phf_generator" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", "rand", ] [[package]] name = "phf_shared" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "proc-macro2" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "railway-core" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5225e8c1c72e6ab4268688fda9ff45446e60dbbcb8756ad05146f6db77903791" dependencies = [ "async-trait", "chrono", "chrono-tz", "geojson", "log", "url", ] [[package]] name = "railway-provider-db-movas" version = "0.2.0" dependencies = [ "async-trait", "chrono", "chrono-tz", "env_logger", "railway-core", "serde", "serde_json", "tokio", "url", "uuid", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustversion" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "siphasher" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "tokio" version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "pin-project-lite", "tokio-macros", ] [[package]] name = "tokio-macros" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "url" version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ "getrandom", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "write16" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "yoke" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", "syn", ] railway-provider-db-movas-0.2.0/Cargo.toml0000644000000032070000000000100140410ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "railway-provider-db-movas" version = "0.2.0" authors = ["Julian Schmidhuber "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Implementation of a DB Movas client in Rust" readme = "README.md" keywords = [ "railway-backend", "train", "public-transport", ] license = "AGPL-3.0-or-later OR EUPL-1.2" repository = "https://gitlab.com/schmiddi-on-mobile/railway-backend" [features] polylines = ["rcore/polylines"] rt-multi-thread = ["rcore/rt-multi-thread"] [lib] name = "railway_provider_db_movas" path = "src/lib.rs" [dependencies.async-trait] version = "0.1" [dependencies.chrono] version = "0.4" [dependencies.chrono-tz] version = "0.8.6" [dependencies.rcore] version = "0.2" package = "railway-core" [dependencies.serde] version = "1.0" features = ["derive"] [dependencies.serde_json] version = "1.0" [dependencies.url] version = "2.5.0" [dependencies.uuid] version = "1.12.0" features = ["v4"] [dev-dependencies.env_logger] version = "0.11.3" [dev-dependencies.tokio] version = "1.37" features = [ "rt-multi-thread", "macros", ] railway-provider-db-movas-0.2.0/Cargo.toml.orig000064400000000000000000000017331046102023000175240ustar 00000000000000[package] name = "railway-provider-db-movas" version = "0.2.0" edition = "2021" authors = ["Julian Schmidhuber "] description = "Implementation of a DB Movas client in Rust" repository = "https://gitlab.com/schmiddi-on-mobile/railway-backend" license = "AGPL-3.0-or-later OR EUPL-1.2" keywords = ["railway-backend", "train", "public-transport"] [dependencies] rcore = { package = "railway-core", path = "../railway-core", version = "0.2" } serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" chrono = { version = "0.4" } chrono-tz = "0.8.6" url = "2.5.0" uuid = { version = "1.12.0", features = ["v4"] } async-trait = "0.1" [features] rt-multi-thread = [ "rcore/rt-multi-thread" ] polylines = [ "rcore/polylines" ] [dev-dependencies] tokio = { version = "1.37", features = [ "rt-multi-thread", "macros" ] } env_logger = "0.11.3" rcore = { package = "railway-core", path = "../railway-core", features = [ "reqwest-requester" ] } railway-provider-db-movas-0.2.0/README.md000064400000000000000000000005101046102023000161040ustar 00000000000000# Railway DB Movas Provider Implementation of the Movas client for Railway. This crate is part of [railway-backend](https://gitlab.com/schmiddi-on-mobile/railway-backend). You can find a high-level documentation of railway-backend [here](https://gitlab.com/schmiddi-on-mobile/railway-backend/-/tree/main/docs?ref_type=heads). railway-provider-db-movas-0.2.0/src/error.rs000064400000000000000000000007011046102023000171150ustar 00000000000000use std::fmt::Display; #[derive(Debug)] pub enum Error { Json(serde_json::Error), RefreshJourneyNotFound, } impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match &self { Self::Json(e) => write!(f, "json error: {}", e), Self::RefreshJourneyNotFound => write!(f, "refresh journey not found"), } } } impl std::error::Error for Error {} railway-provider-db-movas-0.2.0/src/lib.rs000064400000000000000000000253751046102023000165500ustar 00000000000000#![doc = include_str!("../README.md")] mod error; mod serialize; mod types; use error::Error; use types::*; use async_trait::async_trait; use rcore::{ Journey, Location, Mode, ProductsSelection, Provider, Requester, RequesterBuilder, TariffClass, }; use serde_json::json; use url::Url; use uuid::Uuid; use std::collections::{HashMap, HashSet}; pub const API_URL: &str = "https://app.vendo.noncd.db.de/mob"; const TZ: chrono_tz::Tz = chrono_tz::Europe::Berlin; #[derive(Clone)] pub struct DbMovasClient { requester: R, url: Url, } impl DbMovasClient { pub fn new>(requester: RB) -> Self { Self { requester: requester.build(), url: Url::parse(API_URL).expect("Failed to parse API_URL"), } } } fn products_to_api_type(selection: ProductsSelection) -> Vec<&'static str> { HashSet::::from(selection) .into_iter() .flat_map(mode_to_api_type) .collect() } fn mode_to_api_type(mode: Mode) -> Vec<&'static str> { match mode { Mode::HighSpeedTrain => vec![ "HOCHGESCHWINDIGKEITSZUEGE", "INTERCITYUNDEUROCITYZUEGE", "INTERREGIOUNDSCHNELLZUEGE", ], Mode::RegionalTrain => vec!["NAHVERKEHRSONSTIGEZUEGE"], Mode::SuburbanTrain => vec!["SBAHNEN"], Mode::Subway => vec!["UBAHN"], Mode::Tram => vec!["STRASSENBAHN"], Mode::Bus => vec!["BUSSE"], Mode::Ferry => vec!["SCHIFFE"], Mode::Cablecar => vec![], Mode::OnDemand => vec!["ANRUFPFLICHTIGEVERKEHRE"], Mode::Unknown => vec![], } } fn headers_for_content_type<'a>( mime: &'static str, correlation: &'a str, ) -> HashMap<&'static str, &'a str> { [ ("X-Correlation-ID", correlation), ("Accept", mime), ("Content-Type", mime), ] .into() } fn correlation_id() -> String { Uuid::new_v4().to_string() + "_" + &Uuid::new_v4().to_string() } #[cfg_attr(feature = "rt-multi-thread", async_trait)] #[cfg_attr(not(feature = "rt-multi-thread"), async_trait(?Send))] impl Provider for DbMovasClient { type Error = Error; async fn journeys( &self, from: rcore::Place, to: rcore::Place, opts: rcore::JourneysOptions, ) -> Result::Error, Self::Error>> { // TODO: // - via // - results // - stopovers // - polylines // - tickets // - start_with_walking // - accessibility // - transfers // - transfer_time // - language // - loyalty_card // - passenger_age let place_to_id = |p| match p { rcore::Place::Station(s) => s.id, rcore::Place::Location(Location::Address { address, .. }) => address, // TODO: Error when not set rcore::Place::Location(Location::Point { id, name, .. }) => { id.or(name).unwrap_or_default() } }; let mut url = self.url.clone(); url.path_segments_mut() .expect("API URL cannot-be-a-base") .push("angebote") .push("fahrplan"); let time = opts .departure .or(opts.arrival) .map(|t| t.with_timezone(&TZ)) .unwrap_or(chrono::Local::now().with_timezone(&TZ)); let time_type = if opts.arrival.is_some() { "ANKUNFT" } else { "ABFAHRT" }; let context = opts.earlier_than.or(opts.later_than); let class = match opts.tariff_class { TariffClass::First => "KLASSE_1", TariffClass::Second => "KLASSE_2", }; let mut query = json!({ "autonomeReservierung": false, "einstiegsTypList": ["STANDARD"], "klasse": class, "reiseHin": { "wunsch": { "abgangsLocationId": place_to_id(from), "verkehrsmittel": products_to_api_type(opts.products), "zeitWunsch": { "reiseDatum": time.format("%Y-%m-%dT%H:%M:%S%:z").to_string(), "zeitPunktArt": time_type, }, "zielLocationId": place_to_id(to) }, }, "reisendenProfil": { "reisende": [ { "ermaessigungen": ["KEINE_ERMAESSIGUNG KLASSENLOS"], "reisendenTyp": "ERWACHSENER" } ] }, "reservierungsKontingenteVorhanden": false }); if let Some(context) = context { query["reiseHin"]["wunsch"]["context"] = context.into(); } if opts.bike_friendly { query["reiseHin"]["wunsch"]["fahrradmitnahme"] = true.into(); } let response = self .requester .post( &url, &serde_json::to_vec(&query).expect("Failed to serialize body"), headers_for_content_type( "application/x.db.vendo.mob.verbindungssuche.v8+json", &correlation_id(), ), ) .await .map_err(rcore::Error::Request)?; let response: DBTripsResponse = serde_json::from_slice(&response) .map_err(|e| rcore::Error::Provider(Error::Json(e)))?; Ok(response.into()) } async fn locations( &self, opts: rcore::LocationsOptions, ) -> Result::Error, Self::Error>> { // TODO // - results // - language let mut url = self.url.clone(); url.path_segments_mut() .expect("API URL cannot-be-a-base") .push("location") .push("search"); let query = json!({ "searchTerm": opts.query, "locationTypes": [ "ALL" ], "maxResults": opts.results, }); let response = self .requester .post( &url, &serde_json::to_vec(&query).expect("Failed to serialize body"), headers_for_content_type( "application/x.db.vendo.mob.location.v3+json", &correlation_id(), ), ) .await .map_err(rcore::Error::Request)?; let response: Vec = serde_json::from_slice(&response) .map_err(|e| rcore::Error::Provider(Error::Json(e)))?; Ok(response.into_iter().map(Into::into).collect()) } async fn station_board( &self, _place: rcore::Place, _kind: rcore::StationBoardKind, _opts: rcore::StationBoardOptions, ) -> Result::Error, Self::Error>> { Err(rcore::Error::NotImplemented) } // This method is not guaranteed to find the same journey. // TODO: Figure out how to refresh the journey based on the context // TODO: Currently broken I think. async fn refresh_journey( &self, journey: &Journey, _opts: rcore::RefreshJourneyOptions, ) -> Result::Error, Self::Error>> { let mut url = self.url.clone(); url.path_segments_mut() .expect("API URL cannot-be-a-base") .push("trip") .push("recon"); let query = json!({ "reconCtx": journey.id, }); let response = self .requester .post( &url, &serde_json::to_vec(&query).expect("Failed to serialize body"), headers_for_content_type( "application/x.db.vendo.mob.verbindungssuche.v8+json", &correlation_id(), ), ) .await .map_err(rcore::Error::Request)?; let response: DBConnection = serde_json::from_slice(&response) .map_err(|e| rcore::Error::Provider(Error::Json(e)))?; Ok(Journey { id: journey.id.clone(), legs: response .verbindungs_abschnitte .into_iter() .map(Into::into) .collect(), price: journey.price.clone(), }) } } #[cfg(test)] mod test { use rcore::{ JourneysOptions, Location, LocationsOptions, Place, ReqwestRequesterBuilder, Station, }; use super::*; pub async fn check_search>( search: S, expected: S, ) -> Result<(), Box> { let client = DbMovasClient::new(ReqwestRequesterBuilder::default()); let locations = client .locations(LocationsOptions { query: search.as_ref().to_string(), ..Default::default() }) .await?; let results = locations .into_iter() .flat_map(|p| match p { Place::Station(s) => s.name, Place::Location(Location::Address { address, .. }) => Some(address), Place::Location(Location::Point { name, .. }) => name, }) .collect::>(); assert!( results.iter().find(|s| s == &expected.as_ref()).is_some(), "expected {} to be contained in {:#?}", expected.as_ref(), results ); Ok(()) } pub async fn check_journey>( from: S, to: S, ) -> Result<(), Box> { let client = DbMovasClient::new(ReqwestRequesterBuilder::default()); let journeys = client .journeys( Place::Station(Station { id: from.as_ref().to_string(), ..Default::default() }), Place::Station(Station { id: to.as_ref().to_string(), ..Default::default() }), JourneysOptions::default(), ) .await?; assert!( !journeys.journeys.is_empty(), "expected journey from {} to {} to exist", from.as_ref(), to.as_ref() ); Ok(()) } #[tokio::test] async fn search_berlin() -> Result<(), Box> { check_search("Berl", "Berlin Hbf").await } #[tokio::test] async fn journey_tuebingen_augsburg() -> Result<(), Box> { check_journey("A=1@O=Tübingen Hbf@X=9055410@Y=48515807@U=80@L=8000141@B=1@p=1711395084@i=U×008029318@", "A=1@O=Augsburg Hbf@X=10885568@Y=48365444@U=80@L=8000013@B=1@p=1711395084@i=U×008002140@").await } } railway-provider-db-movas-0.2.0/src/serialize.rs000064400000000000000000000034051046102023000177570ustar 00000000000000// From . pub(crate) mod time { use chrono::{DateTime, FixedOffset}; use serde::{self, Deserialize, Deserializer, Serializer}; const FORMAT: &str = "%Y-%m-%dT%H:%M:%S%:z"; pub fn serialize(date: &DateTime, serializer: S) -> Result where S: Serializer, { let s = format!("{}", date.format(FORMAT)); serializer.serialize_str(&s) } pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; let dt = DateTime::::parse_from_str(&s, FORMAT) .map_err(serde::de::Error::custom)?; Ok(dt) } } pub(crate) mod optional_time { use chrono::{DateTime, FixedOffset}; use serde::{self, Deserialize, Deserializer, Serializer}; const FORMAT: &str = "%Y-%m-%dT%H:%M:%S%:z"; pub fn serialize( date: &Option>, serializer: S, ) -> Result where S: Serializer, { if let Some(date) = date { let s = format!("{}", date.format(FORMAT)); serializer.serialize_str(&s) } else { serializer.serialize_none() } } pub fn deserialize<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, { let s: Option = Option::deserialize(deserializer)?; if let Some(s) = s { let dt = DateTime::::parse_from_str(&s, FORMAT) .map_err(serde::de::Error::custom)?; Ok(Some(dt)) } else { Ok(None) } } } railway-provider-db-movas-0.2.0/src/types.rs000064400000000000000000000356571046102023000171520ustar 00000000000000use rcore::{ IntermediateLocation, Journey, JourneysResponse, Leg, Line, Location, Mode, Place, Price, Product, Remark, RemarkAssociation, RemarkType, Station, }; use serde::{Deserialize, Serialize}; use crate::serialize; use std::borrow::Cow; const TZ: chrono_tz::Tz = chrono_tz::Europe::Berlin; #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBLocationsResponse { name: String, location_id: String, coordinates: DBCoordinate, products: Vec, location_type: DBLocationType, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBCoordinate { latitude: f32, longitude: f32, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "UPPERCASE")] pub enum DBProduct { Hochgeschwindigkeitszuege, Intercityundeurocityzuege, Interregioundschnellzuege, Nahverkehrsonstigezuege, Sbahnen, Busse, Schiffe, Ubahn, Strassenbahn, Anrufpflichtigeverkehre, } impl From for Product { fn from(product: DBProduct) -> Self { match product { DBProduct::Hochgeschwindigkeitszuege => Product { mode: Mode::HighSpeedTrain, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Intercityundeurocityzuege => Product { mode: Mode::HighSpeedTrain, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Interregioundschnellzuege => Product { mode: Mode::HighSpeedTrain, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Nahverkehrsonstigezuege => Product { mode: Mode::RegionalTrain, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Sbahnen => Product { mode: Mode::Subway, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Busse => Product { mode: Mode::Bus, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Schiffe => Product { mode: Mode::Ferry, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Ubahn => Product { mode: Mode::Subway, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Strassenbahn => Product { mode: Mode::Tram, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, DBProduct::Anrufpflichtigeverkehre => Product { mode: Mode::OnDemand, name: Cow::Borrowed(""), short: Cow::Borrowed(""), }, } } } #[derive(Serialize, Deserialize, Debug, Clone)] pub enum DBLocationType { #[serde(rename = "ST")] Station, #[serde(rename = "POI")] Poi, #[serde(rename = "ADR")] Address, } impl From for Place { fn from(location: DBLocationsResponse) -> Self { match location.location_type { DBLocationType::Station => Place::Station(Station { id: location.location_id.clone(), name: Some(location.name.clone()), location: Some(Location::Point { id: Some(location.location_id), name: Some(location.name), poi: Some(false), latitude: location.coordinates.latitude, longitude: location.coordinates.longitude, }), products: location.products.into_iter().map(Into::into).collect(), }), DBLocationType::Poi => Place::Location(Location::Point { id: Some(location.location_id), name: Some(location.name), poi: Some(true), latitude: location.coordinates.latitude, longitude: location.coordinates.longitude, }), DBLocationType::Address => Place::Location(Location::Address { address: location.name, latitude: location.coordinates.latitude, longitude: location.coordinates.longitude, }), } } } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBTripsResponse { verbindungen: Vec, frueher_context: String, spaeter_context: String, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBTrip { verbindung: DBConnection, angebote: DBOffer, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBConnection { kontext: String, pub(crate) verbindungs_abschnitte: Vec, echtzeit_notizen: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBLoad { klasse: String, stufe: u8, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBLeg { typ: String, distanz: Option, administration_id: Option, kurztext: Option, mitteltext: Option, langtext: Option, zuglauf_id: Option, nummer: Option, halte: Vec, verkehrsmittel_nummer: Option, richtung: Option, produkt_gattung: Option, abgangs_ort: DBLocation, ankunfts_ort: DBLocation, #[serde(with = "serialize::time")] abgangs_datum: chrono::DateTime, #[serde(with = "serialize::time")] ankunfts_datum: chrono::DateTime, #[serde(with = "serialize::optional_time")] #[serde(default)] ez_abgangs_datum: Option>, #[serde(with = "serialize::optional_time")] #[serde(default)] ez_ankunfts_datum: Option>, echtzeit_notizen: Vec, attribut_notizen: Vec, him_notizen: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBStop { #[serde(with = "serialize::optional_time")] #[serde(default)] abgangs_datum: Option>, #[serde(with = "serialize::optional_time")] #[serde(default)] ankunfts_datum: Option>, #[serde(with = "serialize::optional_time")] #[serde(default)] ez_abgangs_datum: Option>, #[serde(with = "serialize::optional_time")] #[serde(default)] ez_ankunfts_datum: Option>, ort: DBLocation, gleis: Option, ez_gleis: Option, auslastungs_infos: Vec, echtzeit_notizen: Vec, attribut_notizen: Vec, him_notizen: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBLocation { name: String, location_id: String, position: DBCoordinate, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBOffer { preise: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBPrice { gesamt: DBTotalPrice, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBTotalPrice { ab: DBTotalPriceStart, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBTotalPriceStart { waehrung: String, betrag: f64, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DBNote { text: String, key: Option, } impl From for JourneysResponse { fn from(value: DBTripsResponse) -> Self { Self { earlier_ref: Some(value.frueher_context), later_ref: Some(value.spaeter_context), journeys: value.verbindungen.into_iter().map(Into::into).collect(), } } } impl From for Journey { fn from(value: DBTrip) -> Self { Self { id: value.verbindung.kontext, legs: value .verbindung .verbindungs_abschnitte .into_iter() .map(Into::into) .collect(), price: value.angebote.preise.map(|p| Price { amount: p.gesamt.ab.betrag, currency: p.gesamt.ab.waehrung, }), } } } impl From for Leg { fn from(value: DBLeg) -> Self { Self { origin: value.abgangs_ort.into(), destination: value.ankunfts_ort.into(), departure: Some( value .ez_abgangs_datum .unwrap_or(value.abgangs_datum) .with_timezone(&TZ), ), planned_departure: Some(value.abgangs_datum.with_timezone(&TZ)), arrival: Some( value .ez_ankunfts_datum .unwrap_or(value.ankunfts_datum) .with_timezone(&TZ), ), planned_arrival: Some(value.ankunfts_datum.with_timezone(&TZ)), reachable: true, // TODO trip_id: value.zuglauf_id, line: if value.typ == "FAHRZEUG" { Some(Line { name: value.mitteltext, fahrt_nr: value.nummer.map(|n| n.to_string()), mode: Mode::Unknown, product: Product::unknown(), operator: None, product_name: value.kurztext, }) } else { None }, direction: value.richtung, arrival_platform: value .halte .last() .and_then(|h| h.ez_gleis.as_ref().or(h.gleis.as_ref()).cloned()), planned_arrival_platform: value.halte.last().and_then(|h| h.gleis.clone()), departure_platform: value .halte .first() .and_then(|h| h.ez_gleis.as_ref().or(h.gleis.as_ref()).cloned()), planned_departure_platform: value.halte.first().and_then(|h| h.gleis.clone()), frequency: None, // TODO cancelled: value .halte .first() .iter() .chain(value.halte.last().iter()) .flat_map(|h| &h.echtzeit_notizen) .any(|n| &n.text == "Halt entfällt" || n.text == "Stop cancelled"), load_factor: match value .halte .iter() .flat_map(|h| &h.auslastungs_infos) .map(|a| a.stufe) .max() { // TODO: Check if correct. Some(1) => Some(rcore::LoadFactor::LowToMedium), Some(2) => Some(rcore::LoadFactor::LowToMedium), Some(3) => Some(rcore::LoadFactor::High), _ => None, }, intermediate_locations: value.halte.into_iter().map(Into::into).collect(), remarks: value .echtzeit_notizen .into_iter() .chain(value.attribut_notizen) .chain(value.him_notizen) .map(Into::into) .collect(), walking: value.typ == "FUSSWEG", transfer: false, // TODO distance: value.distanz, #[cfg(feature = "polylines")] polyline: None, } } } impl From for Place { fn from(value: DBLocation) -> Self { // TODO: Parse type based on locationId Place::Station(Station { id: value.location_id.clone(), name: Some(value.name.clone()), location: Some(Location::Point { id: Some(value.location_id), name: Some(value.name), poi: Some(false), latitude: value.position.latitude, longitude: value.position.longitude, }), products: vec![], }) } } impl From for IntermediateLocation { fn from(value: DBStop) -> Self { IntermediateLocation::Stop(rcore::Stop { place: value.ort.into(), departure: value .ez_abgangs_datum .or(value.abgangs_datum) .map(|d| d.with_timezone(&TZ)), planned_departure: value.abgangs_datum.map(|d| d.with_timezone(&TZ)), arrival: value .ez_ankunfts_datum .or(value.ankunfts_datum) .map(|d| d.with_timezone(&TZ)), planned_arrival: value.ankunfts_datum.map(|d| d.with_timezone(&TZ)), arrival_platform: value.ez_gleis.as_ref().or(value.gleis.as_ref()).cloned(), planned_arrival_platform: value.gleis.clone(), departure_platform: value.ez_gleis.as_ref().or(value.gleis.as_ref()).cloned(), planned_departure_platform: value.gleis.clone(), cancelled: value .echtzeit_notizen .iter() .any(|n| &n.text == "Halt entfällt" || &n.text == "Stop cancelled"), remarks: value .echtzeit_notizen .into_iter() .chain(value.attribut_notizen) .chain(value.him_notizen) .map(Into::into) .collect(), }) } } impl From for Remark { fn from(value: DBNote) -> Self { Remark { text: value.text, r#type: if value.key.is_none() { RemarkType::Status } else { RemarkType::Hint }, association: value .key .as_ref() .map(remark_association_from_key) .unwrap_or(RemarkAssociation::None), summary: None, trip_id: None, code: value.key.unwrap_or_default(), } } } fn remark_association_from_key>(key: S) -> RemarkAssociation { match key.as_ref() { "FB" => RemarkAssociation::Bike, // Fahrradmitnahme begrenzt möglich "EA" => RemarkAssociation::Accessibility, // Behindertengerechte Ausstattung "ER" => RemarkAssociation::Accessibility, // Rampe im Zug "EH" => RemarkAssociation::Accessibility, // Fahrzeuggebundene Einstiegshilfe vorhanden "LS" => RemarkAssociation::Power, // Laptop-Steckdosen "KL" => RemarkAssociation::AirConditioning, // Klimaanlage "WV" => RemarkAssociation::WiFi, // WLAN verfügbar _ => RemarkAssociation::Unknown, } }