diff options
Diffstat (limited to '')
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.lock | 766 | ||||
-rw-r--r-- | Cargo.toml | 15 | ||||
-rw-r--r-- | src/iceportal.rs | 67 | ||||
-rw-r--r-- | src/lib.rs | 5 | ||||
-rw-r--r-- | src/main.rs | 145 | ||||
-rw-r--r-- | src/travelynx.rs | 64 | ||||
-rw-r--r-- | src/types.rs | 208 |
8 files changed, 1271 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..389e3b5 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,766 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + +[[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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" + +[[package]] +name = "clap" +version = "3.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2afefa54b5c7dd40918dc1e09f213a171ab5937aadccab45e804780b238f9f43" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fd2078197a22f338bd4fbf7d6387eb6f0d6a3c69e6cbc09f5c93e97321fd92a" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "core-foundation" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "crc32fast" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "encoding_rs" +version = "0.8.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustls" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d09d3c15d814eda1d6a836f2f2b56a6abc1446c8a34351cb3180d3db92ffe4ce" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e90dd10c41c6bfc633da6e0c659bd25d31e0791e5974ac42970267d59eba87f7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cf9235533494ea2ddcdb794665461814781c53f19d87b76e571a1c35acbad2b" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dcde03d87d4c973c04be249e7d8f0b35db1c848c487bd43032808e59dd8328d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "traveltext" +version = "0.1.0" +dependencies = [ + "chrono", + "clap", + "colored", + "itertools", + "serde", + "serde_json", + "ureq", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "ureq" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5" +dependencies = [ + "base64", + "chunked_transfer", + "encoding_rs", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "serde", + "serde_json", + "url", + "webpki", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a1c58ce --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "traveltext" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ureq = { version = "*", features = ["json", "charset", "native-certs"] } +clap = { version = "3.0.12", features = [ "derive" ] } +serde = { version = "1.0.135", features = [ "derive" ] } +serde_json = "1.0.78" +colored = "2.0.0" +chrono = "0.4.19" +itertools = "0.10.2" diff --git a/src/iceportal.rs b/src/iceportal.rs new file mode 100644 index 0000000..1b36556 --- /dev/null +++ b/src/iceportal.rs @@ -0,0 +1,67 @@ +use serde::Deserialize; +use serde_json::Value; + +use crate::travelynx::TrainRef; + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct TripInfo { + trip: Trip, + connection: Option<Value>, + selected_route: Option<Value>, + active: Option<Value> +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct Trip { + train_type: String, + vzn: String, // train number + // some position info here + actual_position: u64, // distance along track, presumably + stops: Vec<Stop> +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct Stop { + info: StopInfo, + station: Station +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StopInfo { + distance_from_start: u64, + position_status: String // one of "departed", "future", ... ? +} + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct Station { + eva_nr: String, + name: String +} + + +impl TripInfo { + + pub fn guess_last_station (&self) -> Option<String> { + let current_pos = self.trip.actual_position; + self.trip + .stops + .iter() + .rev() + .map(|stop| (stop.info.distance_from_start, stop)) + .filter(|(dist,_)| dist <= ¤t_pos) + .next() + .map(|(_,stop)| stop.station.name.clone()) + } + + pub fn get_train_ref (&self) -> TrainRef { + TrainRef { + _type: self.trip.train_type.clone(), + no: self.trip.vzn.clone() + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a528cec --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ + + +pub mod types; +pub mod travelynx; +pub mod iceportal; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..12c67a8 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,145 @@ +use clap::{Parser, Subcommand}; + +use colored::*; + +use traveltext::types::*; +use traveltext::{travelynx::*, iceportal::*}; + + +#[allow(non_upper_case_globals)] +const token: &str = "1387-d942ee22-1d34-4dc2-89b6-5e7ef229fb5e"; +#[allow(non_upper_case_globals)] +const baseurl: &str = "https://travelynx.de"; + + + +#[derive(Parser)] +struct Cli { + #[clap(subcommand)] + command: Command, +} + +#[derive(Subcommand)] +enum Command { + /// Get current travelynx status + Status, + /// Check in to a train using travelynx + Checkin { + from: String, + to: String, + // TODO: make this optional and guess which train if not given + #[clap(flatten)] + train: TrainRef + }, + /// If iceportal.de is available, ask it which train we're in and + /// check in + Autocheckin, + /// Undo the last checkin (if any). + Undo, + /// Query iceportal.de (for testing) + ICEPortal +} + + + +fn main() -> Result<(), ureq::Error> { + let cli = Cli::parse(); + + let traveltext = format!( + "{}{}el{}{}", + "tr".cyan(), + "av".bright_magenta(), + "te".bright_magenta(), + "xt".cyan() + ); + + match cli.command { + Command::Status => { + let body: Status = ureq::get(&format!("{}/api/v1/status/{}", baseurl, token)) + .call() + // TODO: this prints the token! + .unwrap_or_else(|err| exit_err(&err.to_string())) + .into_json() + .unwrap_or_else(|err| exit_err(&err.to_string())); + + println!("{}: {}", traveltext, body); + } + Command::Checkin {from, to, train} => { + let request = Action::CheckIn { + train, + from_station: from, + to_station: Some(to), + comment: None, + token: format!("{}", token) + }; + + // println!("{}", serde_json::to_string(&request).unwrap()); + + let resp: Response = ureq::post(&format!("{}/api/v1/travel", baseurl)) + .send_json(request) + .unwrap_or_else(|err| exit_err(&err.to_string())) + .into_json() + .unwrap_or_else(|err| exit_err(&err.to_string())); + + // eprintln!("{:?}", resp); + println!("{}: {}", traveltext, resp); + }, + Command::Undo => { + let resp: Response = ureq::post(&format!("{}/api/v1/travel", baseurl)) + .send_json(Action::Undo {token: token.to_owned()}) + .unwrap_or_else(|err| exit_err(&err.to_string())) + .into_json() + .unwrap_or_else(|err| exit_err(&err.to_string())); + + println!("{}: {}", traveltext, resp); + }, + Command::Autocheckin => { + let iceportal: TripInfo = ureq::get("https://iceportal.de/api1/rs/tripInfo/trip") + .call()? + .into_json() + .unwrap_or_else(|err| exit_err(&err.to_string())); + let last_stop = iceportal.guess_last_station().unwrap(); + let train = iceportal.get_train_ref(); + println!( + "{}: guessing you got onto {} {} in {}, checking in …", + traveltext, + train._type, + train.no, + last_stop + ); + let request = Action::CheckIn { + train, + from_station: last_stop, + to_station: None, + comment: None, + token: format!("{}", token) + }; + + // println!("{}", serde_json::to_string(&request).unwrap()); + + let resp: Response = ureq::post(&format!("{}/api/v1/travel", baseurl)) + .send_json(request) + .unwrap_or_else(|err| exit_err(&err.to_string())) + .into_json() + .unwrap_or_else(|err| exit_err(&err.to_string())); + + // eprintln!("{:?}", resp); + println!("{}: {}", traveltext, resp); + + }, + Command::ICEPortal => { + let resp: TripInfo = ureq::get("https://iceportal.de/api1/rs/tripInfo/trip") + .call()? + .into_json() + .unwrap_or_else(|err| exit_err(&err.to_string())); + println!("{:?}", resp); + println!("guessing last stop was: {:?}", resp.guess_last_station()); + } + } + Ok(()) +} + +fn exit_err(msg: &str) -> ! { + eprintln!("{}", msg); + std::process::exit(1) +} diff --git a/src/travelynx.rs b/src/travelynx.rs new file mode 100644 index 0000000..0188f32 --- /dev/null +++ b/src/travelynx.rs @@ -0,0 +1,64 @@ +use clap::Args; +use serde::{Serialize, Deserialize}; +use colored::*; + +use crate::types::Status; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Travel { + token: String, + #[serde(flatten)] + action: Action, +} + +#[derive(Serialize, Debug)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "action")] +pub enum Action { + #[serde(rename = "checkin")] + #[serde(rename_all = "camelCase")] + CheckIn { + token: String, + train: TrainRef, + from_station: String, + #[serde(skip_serializing_if = "Option::is_none")] + to_station: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + comment: Option<String>, + }, + #[serde(rename = "checkout")] + CheckOut { + to_station: String, + force: bool, + #[serde(skip_serializing_if = "Option::is_none")] + comment: Option<String>, + }, + Undo {token: String}, +} + +#[derive(Args, Serialize, Debug)] +pub struct TrainRef { + #[clap(name = "TRAIN TYPE")] + #[serde(rename = "type")] + pub _type: String, + #[clap(name = "NUMBER")] + pub no: String, +} + +#[derive(Deserialize, Debug)] +pub struct Response { + success: Option<bool>, + deprecated: bool, + status: Status, + error: Option<String> +} + +impl std::fmt::Display for Response { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.error { + Some(msg) => write!(f, "{}", msg.red()), + None => write!(f, "{}\n\n{}", "Success!".green(), self.status) + } + } +} diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..3dcb6db --- /dev/null +++ b/src/types.rs @@ -0,0 +1,208 @@ +use serde::{Deserialize, Deserializer}; + +use chrono::NaiveDateTime; +use colored::*; +use itertools::Itertools; + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Station { + name: String, + ds100: String, + uic: u64, + latitude: f64, + longitude: f64, + #[serde(deserialize_with = "naive_read_unixtime")] + scheduled_time: NaiveDateTime, + #[serde(deserialize_with = "naive_read_unixtime")] + real_time: NaiveDateTime, +} + + +pub fn parse_optional_station<'de, D>(d: D) -> Result<Option<Station>, D::Error> +where + D: Deserializer<'de>, +{ + let val = <serde_json::Value>::deserialize(d)?; + match serde_json::from_value(val) { + Ok(station) => Ok(Some(station)), + Err(_) => Ok(None) + } +} + + +fn naive_read_unixtime<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> +where + D: Deserializer<'de>, +{ + let ts = <i64>::deserialize(d)?; + Ok(NaiveDateTime::from_timestamp(ts, 0)) +} +fn option_naive_read_unixtime<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> +where + D: Deserializer<'de>, +{ + match <i64>::deserialize(d) { + Ok(ts) => + Ok(Some(NaiveDateTime::from_timestamp(ts, 0))), + Err(_) => Ok(None) + } +} + + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Stop { + name: String, + #[serde(deserialize_with = "option_naive_read_unixtime")] + scheduled_arrival: Option<NaiveDateTime>, + #[serde(deserialize_with = "option_naive_read_unixtime")] + real_arrival: Option<NaiveDateTime>, + #[serde(deserialize_with = "option_naive_read_unixtime")] + scheduled_departure: Option<NaiveDateTime>, + #[serde(deserialize_with = "option_naive_read_unixtime")] + real_departure: Option<NaiveDateTime>, +} + +trait IsStation { + fn name (&self) -> &str; + fn scheduled_arrival (&self) -> Option<&NaiveDateTime>; + fn real_arrival (&self) -> Option<&NaiveDateTime>; + fn ds100 (&self) -> &str; + + fn to_fancy_string (&self) -> String { + format!( + "{} {} – {} ({})", + self.real_arrival().map(|t| t.time().to_string()).unwrap_or("??:??:??".to_string()).blue(), + { + let delay = match (self.real_arrival(), self.scheduled_arrival()) { + (Some(a), Some(s)) => (a.time() - s.time()).num_minutes(), + _ => 0 + }; + let text = format!("({:+})", delay); + if delay > 0 { + text.red() + } else { + text.green() + } + }, + self.ds100().red(), + self.name() + ) + } +} + +impl IsStation for Station { + fn name (&self) -> &str { + &self.name + } + fn scheduled_arrival (&self) -> Option<&NaiveDateTime> { + Some(&self.scheduled_time) + } + fn real_arrival (&self) -> Option<&NaiveDateTime> { + Some(&self.real_time) + } + + fn ds100 (&self) -> &str { + &self.ds100 + } +} + +impl IsStation for Stop { + fn name (&self) -> &str { + &self.name + } + fn scheduled_arrival (&self) -> Option<&NaiveDateTime> { + self.scheduled_arrival.as_ref() + } + fn real_arrival (&self) -> Option<&NaiveDateTime> { + self.real_arrival.as_ref() + } + + fn ds100 (&self) -> &str { + "[??]" + } +} + + + + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Train { + #[serde(rename = "type")] + _type: String, + line: Option<String>, + no: String, + id: String, +} + + + +#[derive(Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Status { + deprecated: bool, + checked_in: bool, + from_station: Station, + #[serde(deserialize_with = "parse_optional_station")] + to_station: Option<Station>, + intermediate_stops: Vec<Stop>, + train: Option<Train>, + action_time: u64, +} + +#[allow(dead_code)] +pub struct Ds100 { + inner: String, +} + +struct Trip<'a> (&'a Vec<Stop>); + +impl std::fmt::Display for Train { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {}", self._type, self.no) + } +} + +#[allow(unstable_name_collisions)] +impl std::fmt::Display for Trip<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.0.len() == 0 { + write!(f, "(none)") + } else { + self.0.iter() + .map(|stop| stop.to_fancy_string()) + .intersperse(" ↓".to_string()) + .for_each(|l| writeln!(f, " {}", l).unwrap()); + Ok(()) + } + } +} + + +impl std::fmt::Display for Status { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.checked_in { + false => write!( + f, + "not checked in. \n\n\ + last trip: \n {}\n ↓\n {}", + self.from_station.to_fancy_string(), + self.to_station.as_ref().unwrap().to_fancy_string() + ), + true => write!( + f, + "checked in to: {}.\n\n\ + stops:\n {}\n ↓\n{} ↓\n {}", + self.train.as_ref().map(|t| t.to_string()).unwrap_or("".to_string()).green(), + self.from_station.to_fancy_string(), + Trip(&self.intermediate_stops), + self.to_station + .as_ref() + .map(|s| s.to_fancy_string()) + .unwrap_or_else(|| "🚄 Fahrt ins Blaue".blue().to_string()) + ) + } + } +} |