From 3d3754b1162bc821e958728a7309941f8ac2b4d4 Mon Sep 17 00:00:00 2001 From: Mark <> Date: Sun, 2 Mar 2025 03:27:51 +0100 Subject: [PATCH] init --- .gitignore | 1 + Cargo.lock | 2550 +++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 13 + src/api.rs | 357 +++++++ src/cache.rs | 128 +++ src/favicon.ico | Bin 0 -> 32974 bytes src/index.html | 221 ++++ src/main.rs | 190 ++++ src/nojs.html | 53 + 9 files changed, 3513 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/api.rs create mode 100644 src/cache.rs create mode 100644 src/favicon.ico create mode 100644 src/index.html create mode 100644 src/main.rs create mode 100644 src/nojs.html 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..01fce5d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2550 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "atomic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "binascii" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytemuck" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "cc" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "devise" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d90b0c4c777a2cad215e3c7be59ac7c15adf45cf76317009b7d096d46f651d" +dependencies = [ + "devise_codegen", + "devise_core", +] + +[[package]] +name = "devise_codegen" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71b28680d8be17a570a2334922518be6adc3f58ecc880cbb404eaeb8624fd867" +dependencies = [ + "devise_core", + "quote", +] + +[[package]] +name = "devise_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" +dependencies = [ + "bitflags", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + +[[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 = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "figment" +version = "0.10.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" +dependencies = [ + "atomic 0.6.0", + "pear", + "serde", + "toml", + "uncased", + "version_check", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.2.0", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.2.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.2.0", + "hyper 1.5.1", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.5.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "hyper 1.5.1", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "inlinable_string" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "js-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.168" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 1.2.0", + "httparse", + "memchr", + "mime", + "spin", + "tokio", + "tokio-util", + "version_check", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pear" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" +dependencies = [ + "inlinable_string", + "pear_codegen", + "yansi", +] + +[[package]] +name = "pear_codegen" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.1", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rocket" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a516907296a31df7dc04310e7043b61d71954d703b603cc6867a026d7e72d73f" +dependencies = [ + "async-stream", + "async-trait", + "atomic 0.5.3", + "binascii", + "bytes", + "either", + "figment", + "futures", + "indexmap", + "log", + "memchr", + "multer", + "num_cpus", + "parking_lot", + "pin-project-lite", + "rand", + "ref-cast", + "rocket_codegen", + "rocket_http", + "serde", + "state", + "tempfile", + "time", + "tokio", + "tokio-stream", + "tokio-util", + "ubyte", + "version_check", + "yansi", +] + +[[package]] +name = "rocket_codegen" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46" +dependencies = [ + "devise", + "glob", + "indexmap", + "proc-macro2", + "quote", + "rocket_http", + "syn", + "unicode-xid", + "version_check", +] + +[[package]] +name = "rocket_http" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e274915a20ee3065f611c044bd63c40757396b6dbc057d6046aec27f14f882b9" +dependencies = [ + "cookie", + "either", + "futures", + "http 0.2.12", + "hyper 0.14.31", + "indexmap", + "log", + "memchr", + "pear", + "percent-encoding", + "pin-project-lite", + "ref-cast", + "serde", + "smallvec", + "stable-pattern", + "state", + "time", + "tokio", + "uncased", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable-pattern" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" +dependencies = [ + "memchr", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "state" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" +dependencies = [ + "loom", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ubyte" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" +dependencies = [ + "serde", +] + +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "serde", + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unisuedzeiger" +version = "0.1.0" +dependencies = [ + "chrono", + "html-escape", + "reqwest", + "rocket", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9052643 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "unisuedzeiger" +version = "0.1.0" +edition = "2021" + +[dependencies] +chrono = { version = "0.4.39", features = ["serde"] } +html-escape = "0.2.13" +reqwest = "0.12.9" +rocket = "0.5.1" +serde = { version = "1.0.215", features = ["derive"] } +serde_json = "1.0.133" +tokio = { version = "1.42.0", features = ["sync"] } diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 0000000..ead0ecb --- /dev/null +++ b/src/api.rs @@ -0,0 +1,357 @@ +use std::{ + collections::HashMap, + time::{Duration, Instant}, +}; + +use chrono::DateTime; +use reqwest::get; +use serde::Deserialize; + +pub struct ApiClient { + pub swu_stop_number: u32, + pub swu_api_limit: u8, + pub departures: Vec, + pub directions: HashMap>>, + pub directions_last_save: Option, +} + +impl ApiClient { + pub fn new() -> Self { + Self::new_custom(1240) + } + pub fn new_custom(swu_stop_number: u32) -> Self { + Self::new_custom_with_limit(swu_stop_number, 30) + } + pub fn new_custom_with_limit(swu_stop_number: u32, swu_api_limit: u8) -> Self { + Self { + swu_stop_number, + swu_api_limit, + departures: vec![], + directions: HashMap::new(), + directions_last_save: None, + } + } + pub async fn api_get(&mut self) -> Result<(), String> { + // get departures + let departures = self.api_get_departures().await?; + + let mut should_save = false; + + // fetch trip data (-> direction) for vehicles which have departed and cache it for next vehicles + for departure in self.departures.iter() { + if let Some(route_name) = &departure.route_name { + if let Some(departure_direction_text) = &departure.departure_direction_text { + if let Some(vehicle_number) = departure.vehicle_number { + if departures.iter().all(|dep| { + dep.route_name.as_ref().is_none_or(|v| v != route_name) + || dep.vehicle_number.is_none_or(|v| v != vehicle_number) + || dep + .departure_direction_text + .as_ref() + .is_none_or(|v| v != departure_direction_text) + }) { + // vehicle has just departed, check direction via api + let dir_value = self + .directions + .entry(route_name.clone()) + .or_insert_with(HashMap::new) + .entry(departure_direction_text.clone()) + .or_insert(None); + if dir_value.is_none_or(|(when, _, success_rate)| { + when.elapsed().as_secs() + >= (success_rate * 15).saturating_sub(5) as u64 + }) { + match Self::api_get_trip(vehicle_number).await { + Ok(res) => { + if res.route_number == departure.route_number + && res + .departure_direction_text + .as_ref() + .is_some_and(|ddt| ddt == departure_direction_text) + { + if let Some(dir) = res.direction { + if let Some((when, prev, success_rate)) = dir_value + { + *when = Instant::now(); + should_save = true; + if dir == *prev { + *success_rate = + success_rate.saturating_add(1).min(60); + eprintln!("[CACHE/dirs] {route_name} -> {departure_direction_text} => d{dir} (confirmed, success now {})", *success_rate); + } else { + if *success_rate <= 2 { + eprintln!("[CACHE/dirs] {route_name} -> {departure_direction_text} => d{dir} (changed from {})", *prev); + *prev = dir; + *success_rate = 1; + } else { + *success_rate /= 2; + eprintln!("[CACHE/dirs] {route_name} -> {departure_direction_text} => d{dir} (contradicted, success now {})", *success_rate); + } + } + } else { + eprintln!("[CACHE/dirs] {route_name} -> {departure_direction_text} => d{dir} (new info)"); + *dir_value = Some((Instant::now(), dir, 1)); + } + } + } else { + // ignore cuz is wrong route or wrong direction + } + } + Err(e) => eprintln!("{e}"), + } + } + } + } + } + } + } + + if should_save + && self + .directions_last_save + .is_none_or(|t| t.elapsed() > Duration::from_secs(60 * 60)) + { + if let Err(e) = self.directions_save().await { + eprintln!("Couldn't save directions data: {e}"); + } + } + + self.departures = departures; + Ok(()) + } + + async fn api_get_departures(&self) -> Result, String> { + match get(format!( + "https://api.swu.de/mobility/v1/stop/passage/Departures?StopNumber={}&Limit={}", + self.swu_stop_number, self.swu_api_limit + )) + .await + { + Ok(response) => match response.text().await { + Ok(response) => match serde_json::from_str::(&response) { + Ok(response) => Ok(response.stop_passage.departure_data), + Err(e) => Err(format!("{}\n{}", e, response)), + }, + Err(e) => Err(e.to_string()), + }, + Err(e) => Err(e.to_string()), + } + } + + async fn api_get_trip(vehicle_number: u32) -> Result { + match get(format!( + "https://api.swu.de/mobility/v1/vehicle/trip/Trip?VehicleNumber={vehicle_number}" + )) + .await + { + Ok(response) => match response.text().await { + Ok(response) => match serde_json::from_str::(&response) { + Ok(trip) => Ok(trip.vehicle_trip.trip_data.journey_data), + Err(e) => Err(format!("{}\n{}", e, response)), + }, + Err(e) => Err(e.to_string()), + }, + Err(e) => return Err(e.to_string()), + } + } +} + +pub async fn bahnhof_get_departures() -> Result { + match get( + "https://www.bahnhof.de/api/boards/departures?evaNumbers=8000170&filterTransports=HIGH_SPEED_TRAIN&filterTransports=INTERCITY_TRAIN&filterTransports=INTER_REGIONAL_TRAIN&filterTransports=REGIONAL_TRAIN&filterTransports=CITY_TRAIN&filterTransports=UNKNOWN&duration=120&locale=de", + ) + .await + { + Ok(response) => match response.text().await { + Ok(response) => match serde_json::from_str::(&response) { + Ok(response) => { + let mut o = format!("
\n"); + for departure in response.entries.into_iter().flat_map(|v| v.into_iter()) { + if let Some(line_name) = &departure.line_name { + o.push_str(if departure.canceled { + r#"
"# + } else { + r#"
"# + }); + o.push_str(""); + html_escape::encode_safe_to_string(line_name, &mut o); + o.push_str(""); + if let Some(departure_time) = + departure.time_delayed.or(departure.time_schedule) + { + o.push_str(" "); + o.push_str( + &departure_time.naive_local().format("%H:%M").to_string(), + ); + } + if let Some(destination) = + departure.destination.as_ref().and_then(|v| v.name.as_ref()) + { + o.push_str("
"); + html_escape::encode_safe_to_string(destination, &mut o); + } + o.push_str("
\n"); + } + } + o.push_str("
"); + Ok(o) + } + Err(e) => Err(format!("{e}\n{response}")), + }, + Err(e) => Err(e.to_string()), + }, + Err(e) => Err(e.to_string()), + } +} + +impl ApiClient { + pub async fn directions_save(&mut self) -> Result<(), String> { + let file_name = format!("unisuedzeiger_directions_{}.txt", self.swu_stop_number); + let mut out = String::new(); + for (line, directions) in &self.directions { + out.push_str(&format!("[{line}]\n")); + for (direction_text, value) in directions { + if let Some((_, direction_number, success_rate)) = value { + out.push_str(&format!( + "> {direction_text}={direction_number}/{success_rate}\n" + )); + } + } + } + tokio::fs::write(&file_name, out) + .await + .map_err(|e| format!("Couldn't save file {file_name}: {e}"))?; + self.directions_last_save = Some(Instant::now()); + Ok(()) + } + pub async fn directions_load(&mut self) -> Result<(), String> { + let prev_directions = std::mem::replace(&mut self.directions, HashMap::new()); + match self.directions_load_impl().await { + Ok(v) => { + dbg!(&self.directions); + Ok(v) + } + Err(e) => { + self.directions = prev_directions; + Err(e) + } + } + } + pub async fn directions_load_impl(&mut self) -> Result<(), String> { + let now = Instant::now(); + self.directions_last_save = Some(now); + let file_name = format!("unisuedzeiger_directions_{}.txt", self.swu_stop_number); + let text = tokio::fs::read_to_string(&file_name) + .await + .map_err(|e| format!("Couldn't read file {file_name}: {e}"))?; + let mut line_name = String::new(); + for line in text.lines() { + if line.starts_with('[') && line.ends_with(']') { + line_name = line[1..line.len() - 1].to_owned(); + if !self.directions.contains_key(&line_name) { + self.directions.insert(line_name.to_owned(), HashMap::new()); + } + } else if line.starts_with("> ") { + if let Some((direction_text, data_text)) = line[2..].rsplit_once('=') { + if let Some((direction_number, success_rate)) = data_text.split_once('/') { + if let (Some(direction_number), Some(success_rate)) = + (direction_number.parse().ok(), success_rate.parse().ok()) + { + let line_map = self.directions.get_mut(&line_name).unwrap(); + if line_map + .insert( + direction_text.to_owned(), + Some((now, direction_number, success_rate)), + ) + .is_some() + { + return Err(format!( + "Duplicate direction texts for line {line_name}: {direction_text}" + )); + } + } + } + } + } + } + Ok(()) + } +} + +#[derive(Deserialize)] +struct ResDepartures { + #[serde(rename = "StopPassage")] + pub stop_passage: ResStopPassage, +} +#[derive(Deserialize)] +struct ResStopPassage { + #[serde(rename = "DepartureData")] + pub departure_data: Vec, +} +#[derive(Debug, Deserialize)] +pub struct Departure { + #[serde(default, rename = "RouteName")] + pub route_name: Option, + #[serde(default, rename = "RouteNumber")] + pub route_number: Option, + #[serde(default, rename = "DepartureDirectionText")] + pub departure_direction_text: Option, + #[serde(default, rename = "VehicleNumber")] + pub vehicle_number: Option, + // #[serde(default, rename = "DepartureCountdown")] + // pub departure_countdown: Option, + #[serde(default, rename = "DepartureTimeActual")] + pub departure_time_actual: Option>, + #[serde(default, rename = "DepartureTimeScheduled")] + pub departure_time_scheduled: Option>, +} + +#[derive(Deserialize)] +struct ResTrip { + #[serde(rename = "VehicleTrip")] + pub vehicle_trip: ResVehicleTrip, +} +#[derive(Deserialize)] +struct ResVehicleTrip { + #[serde(rename = "TripData")] + trip_data: ResTripData, +} +#[derive(Deserialize)] +struct ResTripData { + #[serde(rename = "JourneyData")] + journey_data: JourneyData, +} +#[derive(Deserialize)] +pub struct JourneyData { + #[serde(default, rename = "RouteNumber")] + pub route_number: Option, + #[serde(default, rename = "DepartureDirectionText")] + pub departure_direction_text: Option, + #[serde(default, rename = "Direction")] + pub direction: Option, +} + +#[derive(Deserialize)] +struct BahnhofResDepartures { + entries: Vec>, +} +#[derive(Deserialize)] +struct BahnhofResDeparture { + #[serde(default, rename = "timeSchedule")] + time_schedule: Option>, + #[serde(default, rename = "timeDelayed")] + time_delayed: Option>, + #[serde(default, rename = "canceled")] + canceled: bool, + // #[serde(default, rename = "platform")] + // platform: Option, + #[serde(default, rename = "lineName")] + line_name: Option, + #[serde(default, rename = "destination")] + destination: Option, +} +#[derive(Deserialize)] +struct BahnhofResDepartureDestination { + #[serde(default, rename = "name")] + name: Option, +} diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 0000000..cc216e0 --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,128 @@ +use std::time::Duration; + +use chrono::DateTime; +use tokio::{sync::Mutex, time::Instant}; + +use crate::api::{bahnhof_get_departures, ApiClient}; + +pub struct Cache { + pub index: String, + pub nojs: String, + pub data: Mutex, + pub api_client: Mutex, + pub api_next_update: Mutex, + pub bahnhof_html: Mutex, + pub bahnhof_next_update: Mutex, +} +pub struct Data { + pub seq: u8, + pub departures: Vec, + // pub changes: [Vec; 10], +} +#[derive(Debug)] +pub struct Departure { + pub route_name: Option, + pub departure_direction_text: Option, + pub vehicle_number: Option, + pub departure_time: Option>, + pub scheduled_time: Option>, + pub direction: Option, +} +impl Cache { + pub fn new(index: String, nojs: String, swu_stop_number: Option) -> Self { + let now = Instant::now(); + Self { + index, + nojs, + data: Mutex::new(Data { + seq: 0, + departures: vec![], + }), + api_client: Mutex::new(if let Some(swu_stop_number) = swu_stop_number { + ApiClient::new_custom(swu_stop_number) + } else { + ApiClient::new() + }), + api_next_update: Mutex::new(now), + bahnhof_html: Mutex::new(String::new()), + bahnhof_next_update: Mutex::new(now), + } + } + pub async fn update_swu(&self) -> Duration { + let mut next_update = self.api_next_update.lock().await; + let now = Instant::now(); + if now >= *next_update { + let delay = Duration::from_secs(14); + let mut api = self.api_client.lock().await; + match api.api_get().await { + Ok(()) => { + // TODO: find changes + // increment sequence number thingy (ze counting boi) + let mut data = self.data.lock().await; + data.seq += 1; + if data.seq >= 10 { + data.seq = 0; + } + // store departures + let departures = api + .departures + .iter() + .map(|departure| { + let direction = departure + .route_name + .as_ref() + .and_then(|rn| { + departure.departure_direction_text.as_ref().and_then(|dt| { + api.directions + .get(rn) + .and_then(|v| v.get(dt).and_then(|v| v.as_ref())) + }) + }) + .filter(|(_, _, success)| *success > 2) + .map(|(_, dir, _)| *dir); + Departure { + route_name: departure.route_name.clone(), + departure_direction_text: departure + .departure_direction_text + .clone(), + vehicle_number: departure.vehicle_number, + departure_time: departure + .departure_time_actual + .as_ref() + .or(departure.departure_time_scheduled.as_ref()) + .cloned(), + scheduled_time: departure.departure_time_scheduled.clone(), + direction, + } + }) + .collect(); + data.departures = departures; + } + Err(e) => eprintln!("Couldn't get departures from swu: {e}"), + } + *next_update = Instant::now() + delay; + delay + } else { + *next_update - now + } + } + + pub async fn update_bahn(&self) -> Duration { + let mut next_update = self.bahnhof_next_update.lock().await; + let now = Instant::now(); + if now >= *next_update { + let delay = Duration::from_secs(59); + // bahnhof api request + match bahnhof_get_departures().await { + Ok(v) => { + *self.bahnhof_html.lock().await = v; + } + Err(e) => eprintln!("Couldn't get departures from bahnhof: {e}"), + } + *next_update = Instant::now() + delay; + delay + } else { + *next_update - now + } + } +} diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3dfb5e8b1482f6e0c2381b8b0fe1ddf32309a103 GIT binary patch literal 32974 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 Va{az(4n6 + + + + + +ulm öpnv abfahrten + + + +
no javascript? use the nojs version
+

+
+
+ + + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..751ba3c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,190 @@ +mod api; +mod cache; + +use std::{collections::BTreeMap, sync::Arc, time::Duration}; + +use cache::Cache; +use rocket::{get, response::content::RawHtml, routes, State}; + +#[get("/")] +fn index(cache: &State>) -> RawHtml<&str> { + RawHtml(&cache.index) +} + +#[get("/favicon.ico")] +fn favicon() -> &'static [u8] { + include_bytes!("favicon.ico") +} + +#[get("/uni/all")] +async fn uni_all(cache: &State>) -> RawHtml { + let seconds_until_next_update = cache.update_swu().await.as_secs() + 1; + let data = cache.data.lock().await; + let mut o = format!("#{}#{}", data.seq, seconds_until_next_update); + for departure in data.departures.iter() { + if let Some(route) = &departure.route_name { + o.push_str("\nR"); + o.push_str(route); + } + if let Some(dir) = &departure.departure_direction_text { + o.push_str("\nD"); + o.push_str(dir); + } + if let Some(dir) = departure.direction { + o.push_str(&format!("\nd{dir}")); + } + if let Some(vehicle) = departure.vehicle_number { + o.push_str(&format!("\nv{vehicle}")); + } + if let Some(time) = &departure.departure_time { + o.push_str("\nt"); + o.push_str(&format!("{time}")); + } + if let Some(time) = &departure.scheduled_time { + o.push_str("\ns"); + o.push_str(&format!("{time}")); + } + o.push_str("\n-"); + // v.route_name + } + RawHtml(o) +} + +#[get("/bf/all")] +async fn bf_all(cache: &State>) -> String { + cache.update_bahn().await; + cache.bahnhof_html.lock().await.clone() +} + +#[get("/nojs")] +async fn nojs(cache: &State>) -> RawHtml { + let mut html = cache.nojs.clone(); + html.push_str("\n"); + cache.update_swu().await; + let data = cache.data.lock().await; + let mut routes = BTreeMap::>::new(); + #[derive(PartialEq, Eq)] + struct StrOrderedByLen<'a>(&'a str); + impl<'a> std::cmp::PartialOrd for StrOrderedByLen<'a> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + impl<'a> std::cmp::Ord for StrOrderedByLen<'a> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0 + .len() + .cmp(&other.0.len()) + .then_with(|| self.0.cmp(other.0)) + } + } + for departure in data.departures.iter() { + if let Some(route_name) = &departure.route_name { + if let Some(route) = routes.get_mut(&StrOrderedByLen(route_name.as_str())) { + route.push(departure); + } else { + routes.insert(StrOrderedByLen(route_name.as_str()), vec![departure]); + } + } + } + let now = chrono::Local::now().naive_local() + Duration::from_secs(10); + for (route_name, departures) in routes { + html.push_str("

Linie "); + html_escape::encode_safe_to_string(&route_name.0, &mut html); + html.push_str("

\n"); + for departure in departures { + html.push_str(r#"
"#); + html_escape::encode_safe_to_string( + departure + .departure_direction_text + .as_ref() + .map(|v| v.as_str()) + .unwrap_or("[?direction?]"), + &mut html, + ); + html.push_str(r#" in now { + let remaining_time = time.signed_duration_since(now); + let mins = remaining_time.num_minutes(); + let secs = remaining_time.num_seconds() % 60; + let soon = match (mins, secs) { + (0, _) | (1, 0) => "1min", + (1, _) | (2, 0) => "2min", + (2..=4, _) | (5, 0) => "5min", + (5..=9, _) | (10, 0) => "10min", + (10..=14, _) | (15, 0) => "15min", + (15.., _) => "future", + (..=-1, _) => "now", + }; + if mins > 0 { + (soon, format!("{}m{}s ({})", mins, secs, time.time())) + } else { + ( + soon, + format!("{}s ({})", remaining_time.num_seconds(), time.time()), + ) + } + } else { + ("now", format!("now ({})", time.time())) + } + }); + html.push_str(time.as_ref().map(|v| v.0).unwrap_or("unknown")); + html.push_str(r#"">"#); + html_escape::encode_safe_to_string( + time.map(|v| v.1).unwrap_or("[?time?]".to_owned()), + &mut html, + ); + html.push_str("
\n"); + } + } + drop(data); + html.push_str("\n"); + html.push_str("\n"); + RawHtml(html) +} + +#[rocket::main] +async fn main() -> Result<(), rocket::Error> { + let cache = Arc::new(Cache::new( + std::fs::read_to_string("index.html") + .ok() + .unwrap_or_else(|| include_str!("index.html").to_owned()), + std::fs::read_to_string("nojs.html") + .ok() + .unwrap_or_else(|| include_str!("nojs.html").to_owned()), + std::env::args().nth(1).map(|v| { + v.parse() + .expect("argument must be an integer (Haltestelle als SWU Stop-Number)") + }), + )); + if let Err(e) = cache.api_client.lock().await.directions_load().await { + eprintln!("No direction data loaded: {e}"); + } + let rocket = rocket::build() + .manage(Arc::clone(&cache)) + .mount("/", routes![index, nojs, favicon, uni_all, bf_all]) + .ignite() + .await?; + // should not be necessary anymore + // let _direction_updater_task = tokio::task::spawn(async move { + // let start = Instant::now(); + // while start.elapsed().as_secs() < 120 * 60 { + // tokio::time::sleep(Duration::from_secs(15)).await; + // tokio::time::sleep(cache.update_swu().await).await; + // } + // }); + rocket.launch().await?; + Ok(()) +} diff --git a/src/nojs.html b/src/nojs.html new file mode 100644 index 0000000..e98c1b6 --- /dev/null +++ b/src/nojs.html @@ -0,0 +1,53 @@ + + + + + + + +ulm öpnv abfahrten + +