railway-provider-db-movas-0.3.0/.cargo_vcs_info.json0000644000000001670000000000100160460ustar { "git": { "sha1": "db4730b96174cae902758d2659864d39e047a4d0" }, "path_in_vcs": "railway-provider-db-movas" }railway-provider-db-movas-0.3.0/Cargo.lock0000644000000664600000000000100140310ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[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.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", "windows-sys 0.60.2", ] [[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.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" version = "1.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-link", ] [[package]] name = "chrono-tz" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" dependencies = [ "chrono", "phf", ] [[package]] name = "colorchoice" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[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.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", "regex", ] [[package]] name = "env_logger" version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", "jiff", "log", ] [[package]] name = "find-msvc-tools" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "form_urlencoded" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 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.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", "wasip2", ] [[package]] name = "iana-time-zone" version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "log", "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 = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_normalizer" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", "writeable", "yoke", "zerofrom", "zerotrie", "zerovec", ] [[package]] name = "idna" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" dependencies = [ "jiff-static", "log", "portable-atomic", "portable-atomic-util", "serde_core", ] [[package]] name = "jiff-static" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" dependencies = [ "proc-macro2", "quote", "syn", ] [[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.178" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libm" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "litemap" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "log" version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[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 = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" dependencies = [ "phf_shared", ] [[package]] name = "phf_shared" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" 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 = "portable-atomic" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" dependencies = [ "portable-atomic", ] [[package]] name = "potential_utf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] [[package]] name = "proc-macro2" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "railway-core" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93677f9367e5a53020ecaf8822230201cc9cdf4f4772def98a39c663e4fd08c8" dependencies = [ "async-trait", "chrono", "chrono-tz", "geojson", "log", "url", ] [[package]] name = "railway-provider-db-movas" version = "0.3.0" dependencies = [ "async-trait", "chrono", "chrono-tz", "env_logger", "railway-core", "serde", "serde_json", "tokio", "url", "uuid", ] [[package]] name = "regex" version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[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.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 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.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 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.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "tokio" version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ "pin-project-lite", "tokio-macros", ] [[package]] name = "tokio-macros" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "url" version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", ] [[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.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ "getrandom", "js-sys", "wasm-bindgen", ] [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[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.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-interface" version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] [[package]] name = "windows-targets" version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", "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.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerotrie" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", "zerofrom", ] [[package]] name = "zerovec" version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] railway-provider-db-movas-0.3.0/Cargo.toml0000644000000032100000000000100140340ustar # 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.3.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.10.4" [dependencies.rcore] version = "0.3" package = "railway-core" [dependencies.serde] version = "1.0" features = ["derive"] [dependencies.serde_json] version = "1.0" [dependencies.url] version = "2.5.7" [dependencies.uuid] version = "1.19.0" features = ["v4"] [dev-dependencies.env_logger] version = "0.11.8" [dev-dependencies.tokio] version = "1.48" features = [ "rt-multi-thread", "macros", ] railway-provider-db-movas-0.3.0/Cargo.toml.orig000064400000000000000000000017341046102023000175260ustar 00000000000000[package] name = "railway-provider-db-movas" version = "0.3.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.3" } serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" chrono = { version = "0.4" } chrono-tz = "0.10.4" url = "2.5.7" uuid = { version = "1.19.0", features = ["v4"] } async-trait = "0.1" [features] rt-multi-thread = [ "rcore/rt-multi-thread" ] polylines = [ "rcore/polylines" ] [dev-dependencies] tokio = { version = "1.48", features = [ "rt-multi-thread", "macros" ] } env_logger = "0.11.8" rcore = { package = "railway-core", path = "../railway-core", features = [ "reqwest-requester" ] } railway-provider-db-movas-0.3.0/README.md000064400000000000000000000005101046102023000161050ustar 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.3.0/src/error.rs000064400000000000000000000007011046102023000171160ustar 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.3.0/src/lib.rs000064400000000000000000000247721046102023000165510ustar 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; const LOCATION_MIME: &str = "application/x.db.vendo.mob.location.v3+json"; const VERBINDUNGSSUCHE_MIME: &str = "application/x.db.vendo.mob.verbindungssuche.v9+json"; #[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(VERBINDUNGSSUCHE_MIME, &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(LOCATION_MIME, &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) } 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(VERBINDUNGSSUCHE_MIME, &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() .flat_map(Option::::from) .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.3.0/src/serialize.rs000064400000000000000000000034051046102023000177600ustar 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.3.0/src/types.rs000064400000000000000000000377011046102023000171430ustar 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: Option, spaeter_context: Option, } #[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: value.frueher_context, later_ref: value.spaeter_context, journeys: value.verbindungen.into_iter().map(Into::into).collect(), } } } impl From for Journey { fn from(value: DBTrip) -> Self { Self { // The journey context after a certain point (in my testing "¶KCC¶") can change when searching the journey multiple times. // Cut off only the first, non-changing part. // Note that this in particular does not break reloading, which does not seem to use the second part. id: value .verbindung .kontext .split_once("¶KCC¶") .map(|s| s.0.to_owned()) .unwrap_or_else(|| value.verbindung.kontext), legs: value .verbindung .verbindungs_abschnitte .into_iter() .flat_map(Option::::from) .collect(), price: value.angebote.preise.map(|p| Price { amount: p.gesamt.ab.betrag, currency: p.gesamt.ab.waehrung, }), } } } impl From for Option { fn from(value: DBLeg) -> Self { // DB adds transitions at the same station between platforms as "walking". // In Railway, this would lead to ridiculous "walking" times and no time waiting. // As far as I can see, their API actually does not differentiate between walking and waiting anymore, we can therefore not nicely fix it. // Instead, interpret all legs that have the same start and end station as "waiting". if value.abgangs_ort.location_id == value.ankunfts_ort.location_id { return None; } Some(Leg { 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, } }