diff --git a/Cargo.lock b/Cargo.lock index f8c1d47..2de9242 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -61,6 +61,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -117,7 +132,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -132,6 +147,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" @@ -147,6 +168,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -171,6 +213,8 @@ version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -198,7 +242,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -263,6 +307,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -315,14 +368,23 @@ dependencies = [ "syn", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dynamic-preauth" version = "0.1.0" dependencies = [ "anyhow", "chrono", + "dotenv", "futures-util", "rand", + "regex", + "reqwest 0.11.27", "salvo", "serde", "serde_json", @@ -393,6 +455,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -523,6 +595,25 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +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" @@ -534,7 +625,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.2.0", "indexmap", "slab", "tokio", @@ -557,7 +648,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 1.2.0", "httpdate", "mime", "sha1", @@ -569,7 +660,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http", + "http 1.2.0", ] [[package]] @@ -587,6 +678,17 @@ dependencies = [ "digest", ] +[[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" @@ -598,6 +700,17 @@ dependencies = [ "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" @@ -605,7 +718,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.2.0", ] [[package]] @@ -616,8 +729,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http", - "http-body", + "http 1.2.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -633,6 +746,30 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "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.2" @@ -642,9 +779,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -654,6 +791,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.5" @@ -661,15 +812,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http", - "hyper", + "http 1.2.0", + "hyper 1.5.2", "hyper-util", "log", - "rustls", + "rustls 0.23.20", "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.1", "tower-service", ] @@ -681,7 +832,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.5.2", "hyper-util", "native-tls", "tokio", @@ -698,9 +849,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", - "http-body", - "hyper", + "http 1.2.0", + "http-body 1.0.1", + "hyper 1.5.2", "pin-project-lite", "socket2", "tokio", @@ -901,6 +1052,15 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.76" @@ -1026,7 +1186,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 1.2.0", "httparse", "memchr", "mime", @@ -1066,7 +1226,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", @@ -1143,7 +1303,7 @@ version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -1207,7 +1367,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1360,7 +1520,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags", + "bitflags 2.6.0", ] [[package]] @@ -1407,6 +1567,47 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-rustls 0.24.2", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + [[package]] name = "reqwest" version = "0.12.9" @@ -1418,12 +1619,12 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.5.2", + "hyper-rustls 0.27.5", "hyper-tls", "hyper-util", "ipnet", @@ -1434,12 +1635,12 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pemfile 2.2.0", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", - "system-configuration", + "system-configuration 0.6.1", "tokio", "tokio-native-tls", "tokio-util", @@ -1513,13 +1714,25 @@ version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.20" @@ -1530,7 +1743,7 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -1547,6 +1760,15 @@ dependencies = [ "security-framework 3.1.0", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -1562,6 +1784,16 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.102.8" @@ -1613,7 +1845,7 @@ dependencies = [ "base64 0.22.1", "bytes", "http-body-util", - "hyper-rustls", + "hyper-rustls 0.27.5", "hyper-util", "jsonwebtoken", "salvo_core", @@ -1632,11 +1864,11 @@ checksum = "ef1f0487e3987c47c2e26d71a9ec696282f0c79203b22f4b9d50afc33273df5f" dependencies = [ "fastrand", "futures-util", - "hyper", - "hyper-rustls", + "hyper 1.5.2", + "hyper-rustls 0.27.5", "hyper-util", "percent-encoding", - "reqwest", + "reqwest 0.12.9", "salvo_core", "tokio", "tracing", @@ -1681,17 +1913,20 @@ checksum = "447c7ab93300c57c76c95412cc469ef07943c698ef022dc08f743f92c05847a8" dependencies = [ "async-trait", "base64 0.22.1", + "brotli", "bytes", "cookie", + "encoding_rs", "enumflags2", + "flate2", "form_urlencoded", "futures-channel", "futures-util", "headers", - "http", + "http 1.2.0", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.5.2", + "hyper-rustls 0.27.5", "hyper-util", "indexmap", "mime", @@ -1704,18 +1939,21 @@ dependencies = [ "pin-project", "rand", "regex", - "rustls-pemfile", + "rustls-pemfile 2.2.0", "salvo_macros", "serde", "serde-xml-rs", "serde_json", + "serde_urlencoded", "sync_wrapper 1.0.2", "tempfile", "thiserror 2.0.9", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.1", "tokio-util", "tracing", + "url", + "zstd", ] [[package]] @@ -1728,7 +1966,7 @@ dependencies = [ "etag", "futures-util", "http-body-util", - "hyper", + "hyper 1.5.2", "pin-project", "salvo_core", "serde", @@ -1778,13 +2016,23 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags", + "bitflags 2.6.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -1797,7 +2045,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc" dependencies = [ - "bitflags", + "bitflags 2.6.0", "core-foundation 0.10.0", "core-foundation-sys", "libc", @@ -2005,15 +2253,36 @@ dependencies = [ "syn", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys 0.5.0", +] + [[package]] name = "system-configuration" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags", + "bitflags 2.6.0", "core-foundation 0.9.4", - "system-configuration-sys", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -2167,13 +2436,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls", + "rustls 0.23.20", "tokio", ] @@ -2557,6 +2836,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "winapi" version = "0.3.9" @@ -2594,7 +2879,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2605,7 +2890,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ "windows-result", "windows-strings", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2614,7 +2899,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2624,7 +2909,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -2633,7 +2927,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2642,7 +2936,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "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]] @@ -2651,28 +2960,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "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" @@ -2685,24 +3012,48 @@ 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" @@ -2718,6 +3069,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -2835,3 +3196,31 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 8831bcd..8260c56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,12 @@ edition = "2021" [dependencies] anyhow = "1.0.95" chrono = { version = "0.4.39", features = ["serde"] } +dotenv = "0.15" futures-util = "0.3.31" rand = "0.8.5" -salvo = { version = "0.74.3", features = ["affix-state", "catch-panic", "cors", "logging", "serve-static", "websocket"] } +regex = "1.10" +reqwest = { version = "0.11", features = ["json", "rustls-tls"], default-features = false } +salvo = { version = "0.74.3", features = ["affix-state", "catch-panic", "cors", "logging", "serve-static", "test", "websocket"] } serde = { version = "1.0.216", features = ["derive"] } serde_json = "1.0.134" tokio = { version = "1", features = ["macros"] } diff --git a/frontend/src/components/DownloadButton.tsx b/frontend/src/components/DownloadButton.tsx index 6f66b0b..7131134 100644 --- a/frontend/src/components/DownloadButton.tsx +++ b/frontend/src/components/DownloadButton.tsx @@ -130,7 +130,7 @@ export default function DownloadButton({ diff --git a/src/main.rs b/src/main.rs index 4bee38f..5858877 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,9 +19,10 @@ use tracing_subscriber::EnvFilter; use crate::models::State; -static STORE: LazyLock> = LazyLock::new(State::new); +static STORE: LazyLock> = LazyLock::new(|| Mutex::new(State::new())); mod models; +mod railway; mod utility; #[handler] @@ -110,7 +111,7 @@ async fn handle_socket(session_id: u32, websocket: WebSocket) { // Create the executable message first, borrow issues let executable_message = OutgoingMessage::Executables { executables: store.executable_json(), - build_log: store.build_log.clone(), + build_log: if store.build_logs.is_some() { Some("/build-logs".to_string()) } else { None }, }; let session = store @@ -185,6 +186,53 @@ async fn handle_socket(session_id: u32, websocket: WebSocket) { tokio::task::spawn(fut); } +#[handler] +pub async fn get_build_logs(req: &mut Request, res: &mut Response, _depot: &mut Depot) { + let store = STORE.lock().await; + + if let Some(build_logs) = &store.build_logs { + // Use pre-computed hash for ETag + let etag = format!("\"{:x}\"", build_logs.content_hash); + + // Check If-None-Match header + if let Some(if_none_match) = req.headers().get("If-None-Match") { + if if_none_match == &etag { + res.status_code(StatusCode::NOT_MODIFIED); + return; + } + } + + // Check If-Modified-Since header + if let Some(if_modified_since) = req.headers().get("If-Modified-Since") { + if let Ok(if_modified_since_str) = if_modified_since.to_str() { + if let Ok(if_modified_since_time) = + chrono::DateTime::parse_from_rfc2822(if_modified_since_str) + { + if build_logs.fetched_at <= if_modified_since_time { + res.status_code(StatusCode::NOT_MODIFIED); + return; + } + } + } + } + + res.headers_mut().insert("ETag", etag.parse().unwrap()); + res.headers_mut() + .insert("Content-Type", "text/plain; charset=utf-8".parse().unwrap()); + res.headers_mut() + .insert("Cache-Control", "public, max-age=300".parse().unwrap()); + res.headers_mut().insert( + "Last-Modified", + build_logs.fetched_at.to_rfc2822().parse().unwrap(), + ); + + res.render(&build_logs.content); + } else { + res.status_code(StatusCode::NOT_FOUND); + res.render("Build logs not available"); + } +} + #[handler] pub async fn download(req: &mut Request, res: &mut Response, depot: &mut Depot) { let download_id = req @@ -333,6 +381,9 @@ fn get_session_id(req: &Request, depot: &Depot) -> Option { #[tokio::main] async fn main() { + // Load environment variables from .env file + dotenv::dotenv().ok(); + let port = std::env::var("PORT").unwrap_or_else(|_| "5800".to_string()); let addr = format!("0.0.0.0:{}", port); tracing_subscriber::fmt() @@ -352,7 +403,7 @@ async fn main() { // Check if we are deployed on Railway let is_railway = env::var("RAILWAY_PROJECT_ID").is_ok(); if is_railway { - let build_logs = format!( + let build_logs_url = format!( "https://railway.com/project/{}/service/{}?environmentId={}&id={}#build", env::var("RAILWAY_PROJECT_ID").unwrap(), env::var("RAILWAY_SERVICE_ID").unwrap(), @@ -360,8 +411,26 @@ async fn main() { env::var("RAILWAY_DEPLOYMENT_ID").unwrap() ); - tracing::info!("Build logs available here: {}", build_logs); - store.build_log = Some(build_logs); + tracing::info!("Build logs available here: {}", build_logs_url); + store.build_log_url = Some(build_logs_url); + + // Try to fetch actual build logs using Railway API + if env::var("RAILWAY_TOKEN").is_ok() { + match crate::railway::fetch_build_logs().await { + Ok(build_logs) => { + tracing::info!( + "Successfully fetched build logs ({} bytes)", + build_logs.content.len() + ); + store.build_logs = Some(build_logs); + } + Err(e) => { + tracing::warn!("Failed to fetch build logs from Railway API: {}", e); + } + } + } else { + tracing::warn!("RAILWAY_TOKEN not set, skipping build log fetch"); + } } store.add_executable("Windows", "./demo.exe"); @@ -400,6 +469,8 @@ async fn main() { .hoop(CatchPanic::new()) // /notify does not need a session, nor should it have one .push(Router::with_path("notify").post(notify)) + // /build-logs does not need a session + .push(Router::with_path("build-logs").get(get_build_logs)) .push( Router::new() .hoop(session_middleware) diff --git a/src/models.rs b/src/models.rs index 92cf61c..2064eaf 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,10 +1,17 @@ use salvo::{http::cookie::Cookie, websocket::Message, Response}; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, path}; -use tokio::sync::{mpsc::UnboundedSender, Mutex}; +use tokio::sync::mpsc::UnboundedSender; use crate::utility::search; +#[derive(Debug, Clone)] +pub struct BuildLogs { + pub content: String, + pub fetched_at: chrono::DateTime, + pub content_hash: u64, +} + #[derive(Debug, Serialize, Clone)] pub struct Session { pub id: u32, @@ -98,26 +105,25 @@ pub struct SessionDownload { impl SessionDownload {} -#[derive(Clone, Debug)] -pub struct State<'a> { - // A map of executables, keyed by their type/platform - pub executables: HashMap<&'a str, Executable>, - // A map of sessions, keyed by their identifier (a random number) +#[derive(Default)] +pub struct State { pub sessions: HashMap, - // Provided on startup, the URL to the build log of the current deployment - pub build_log: Option, + pub executables: HashMap, + pub build_logs: Option, + pub build_log_url: Option, } -impl<'a> State<'a> { - pub fn new() -> Mutex { - Mutex::new(Self { - build_log: None, - executables: HashMap::new(), +impl State { + pub fn new() -> Self { + Self { sessions: HashMap::new(), - }) + executables: HashMap::new(), + build_logs: None, + build_log_url: None, + } } - pub fn add_executable(&mut self, exe_type: &'a str, exe_path: &str) { + pub fn add_executable(&mut self, exe_type: &str, exe_path: &str) { let data = std::fs::read(&exe_path).expect("Unable to read file"); let pattern = "a".repeat(1024); @@ -140,7 +146,7 @@ impl<'a> State<'a> { key_end: key_end, }; - self.executables.insert(exe_type, exe); + self.executables.insert(exe_type.to_string(), exe); } pub async fn new_session(&mut self, res: &mut Response) -> u32 { diff --git a/src/railway.rs b/src/railway.rs new file mode 100644 index 0000000..67f800b --- /dev/null +++ b/src/railway.rs @@ -0,0 +1,178 @@ +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use std::env; + +#[derive(Debug, Serialize)] +struct GraphQLRequest { + query: String, + variables: serde_json::Value, +} + +#[derive(Debug, Deserialize)] +struct GraphQLResponse { + data: Option, + errors: Option>, +} + +#[derive(Debug, Deserialize)] +struct GraphQLError { + message: String, +} + +#[derive(Debug, Deserialize)] +struct BuildLogEntry { + message: String, + severity: String, + timestamp: String, +} + +fn strip_ansi_codes(text: &str) -> String { + // Simple regex to remove ANSI escape sequences + let re = regex::Regex::new(r"\x1b\[[0-9;]*[a-zA-Z]").unwrap(); + re.replace_all(text, "").to_string() +} + +fn should_stop_at_message(message: &str) -> bool { + let clean_message = strip_ansi_codes(message); + + // Check for "Build time: X seconds" pattern (case insensitive) + let build_time_pattern = regex::Regex::new(r"(?i)Build\s+time:\s+\d+").unwrap(); + if build_time_pattern.is_match(&clean_message) { + return true; + } + + // Check for "Starting Container" (case insensitive) + let starting_container_pattern = regex::Regex::new(r"(?i)Starting\s+Container").unwrap(); + if starting_container_pattern.is_match(&clean_message) { + return true; + } + + false +} + +pub async fn fetch_build_logs() -> Result { + let token = env::var("RAILWAY_TOKEN")?; + let deployment_id = env::var("RAILWAY_DEPLOYMENT_ID")?; + + let query = r#" + query buildLogs($deploymentId: String!, $endDate: DateTime, $filter: String, $limit: Int, $startDate: DateTime) { + buildLogs( + deploymentId: $deploymentId + endDate: $endDate + filter: $filter + limit: $limit + startDate: $startDate + ) { + message + severity + timestamp + } + } + "#; + + let variables = serde_json::json!({ + "deploymentId": deployment_id, + "limit": 1000 + }); + + let request = GraphQLRequest { + query: query.to_string(), + variables, + }; + + let client = reqwest::Client::new(); + let response = client + .post("https://backboard.railway.app/graphql/v2") + .header("Authorization", format!("Bearer {}", token)) + .json(&request) + .send() + .await?; + + let response_text = response.text().await?; + let graphql_response: GraphQLResponse = serde_json::from_str(&response_text)?; + + if let Some(errors) = graphql_response.errors { + let error_messages: Vec = errors.iter().map(|e| e.message.clone()).collect(); + return Err(anyhow::anyhow!( + "GraphQL errors: {}", + error_messages.join(", ") + )); + } + + if let Some(data) = graphql_response.data { + if let Some(build_logs_value) = data.get("buildLogs") { + if let Ok(build_logs) = + serde_json::from_value::>(build_logs_value.clone()) + { + let mut filtered_logs = Vec::new(); + + for entry in build_logs { + // Check if we should stop at this message + if should_stop_at_message(&entry.message) { + // For "Build time" messages, include them + // For "Starting Container" messages, stop before them + let clean_message = strip_ansi_codes(&entry.message); + let starting_container_pattern = + regex::Regex::new(r"(?i)Starting\s+Container").unwrap(); + + if starting_container_pattern.is_match(&clean_message) { + // Stop before "Starting Container" message + break; + } else { + // Include "Build time" message and stop + let formatted_entry = format!( + "{} {} {}", + entry.timestamp, + entry.severity, + clean_message.trim() + ); + filtered_logs.push(formatted_entry); + break; + } + } + + // Include this log entry + let clean_message = strip_ansi_codes(&entry.message); + let formatted_entry = format!( + "{} {} {}", + entry.timestamp, + entry.severity, + clean_message.trim() + ); + filtered_logs.push(formatted_entry); + } + + // Add Railway URL header to the logs + let railway_url = format!( + "Railway Build Logs: https://railway.com/project/{}/service/{}?environmentId={}&id={}#build\n\n", + env::var("RAILWAY_PROJECT_ID").unwrap_or_default(), + env::var("RAILWAY_SERVICE_ID").unwrap_or_default(), + env::var("RAILWAY_ENVIRONMENT_ID").unwrap_or_default(), + deployment_id + ); + + let content = format!("{}{}", railway_url, filtered_logs.join("\n")); + let fetched_at = chrono::Utc::now(); + + // Generate hash for the content + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + let mut hasher = DefaultHasher::new(); + content.hash(&mut hasher); + let content_hash = hasher.finish(); + + return Ok(crate::models::BuildLogs { + content, + fetched_at, + content_hash, + }); + } + } + + Err(anyhow::anyhow!( + "Unexpected response structure from Railway API" + )) + } else { + Err(anyhow::anyhow!("No data received from Railway API")) + } +}