summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock766
-rw-r--r--Cargo.toml15
-rw-r--r--src/iceportal.rs67
-rw-r--r--src/lib.rs5
-rw-r--r--src/main.rs145
-rw-r--r--src/travelynx.rs64
-rw-r--r--src/types.rs208
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 <= &current_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())
+ )
+ }
+ }
+}