feat: fetch builds logs for Railway on startup

This commit is contained in:
2025-08-20 17:31:02 -05:00
parent 8431290ea7
commit d20f298da5
6 changed files with 732 additions and 85 deletions

513
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "addr2line" name = "addr2line"
@@ -61,6 +61,21 @@ dependencies = [
"memchr", "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]] [[package]]
name = "android-tzdata" name = "android-tzdata"
version = "0.1.1" version = "0.1.1"
@@ -117,7 +132,7 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
"object", "object",
"rustc-demangle", "rustc-demangle",
"windows-targets", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@@ -132,6 +147,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.6.0" version = "2.6.0"
@@ -147,6 +168,27 @@ dependencies = [
"generic-array", "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]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.16.0" version = "3.16.0"
@@ -171,6 +213,8 @@ version = "1.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
dependencies = [ dependencies = [
"jobserver",
"libc",
"shlex", "shlex",
] ]
@@ -198,7 +242,7 @@ dependencies = [
"num-traits", "num-traits",
"serde", "serde",
"wasm-bindgen", "wasm-bindgen",
"windows-targets", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@@ -263,6 +307,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.6" version = "0.1.6"
@@ -315,14 +368,23 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]] [[package]]
name = "dynamic-preauth" name = "dynamic-preauth"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
"dotenv",
"futures-util", "futures-util",
"rand", "rand",
"regex",
"reqwest 0.11.27",
"salvo", "salvo",
"serde", "serde",
"serde_json", "serde_json",
@@ -393,6 +455,16 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 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]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -523,6 +595,25 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 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]] [[package]]
name = "h2" name = "h2"
version = "0.4.7" version = "0.4.7"
@@ -534,7 +625,7 @@ dependencies = [
"fnv", "fnv",
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"http", "http 1.2.0",
"indexmap", "indexmap",
"slab", "slab",
"tokio", "tokio",
@@ -557,7 +648,7 @@ dependencies = [
"base64 0.21.7", "base64 0.21.7",
"bytes", "bytes",
"headers-core", "headers-core",
"http", "http 1.2.0",
"httpdate", "httpdate",
"mime", "mime",
"sha1", "sha1",
@@ -569,7 +660,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
dependencies = [ dependencies = [
"http", "http 1.2.0",
] ]
[[package]] [[package]]
@@ -587,6 +678,17 @@ dependencies = [
"digest", "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]] [[package]]
name = "http" name = "http"
version = "1.2.0" version = "1.2.0"
@@ -598,6 +700,17 @@ dependencies = [
"itoa", "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]] [[package]]
name = "http-body" name = "http-body"
version = "1.0.1" version = "1.0.1"
@@ -605,7 +718,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http 1.2.0",
] ]
[[package]] [[package]]
@@ -616,8 +729,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-util", "futures-util",
"http", "http 1.2.0",
"http-body", "http-body 1.0.1",
"pin-project-lite", "pin-project-lite",
] ]
@@ -633,6 +746,30 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 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]] [[package]]
name = "hyper" name = "hyper"
version = "1.5.2" version = "1.5.2"
@@ -642,9 +779,9 @@ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"h2", "h2 0.4.7",
"http", "http 1.2.0",
"http-body", "http-body 1.0.1",
"httparse", "httparse",
"httpdate", "httpdate",
"itoa", "itoa",
@@ -654,6 +791,20 @@ dependencies = [
"want", "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]] [[package]]
name = "hyper-rustls" name = "hyper-rustls"
version = "0.27.5" version = "0.27.5"
@@ -661,15 +812,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"http", "http 1.2.0",
"hyper", "hyper 1.5.2",
"hyper-util", "hyper-util",
"log", "log",
"rustls", "rustls 0.23.20",
"rustls-native-certs", "rustls-native-certs",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls 0.26.1",
"tower-service", "tower-service",
] ]
@@ -681,7 +832,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [ dependencies = [
"bytes", "bytes",
"http-body-util", "http-body-util",
"hyper", "hyper 1.5.2",
"hyper-util", "hyper-util",
"native-tls", "native-tls",
"tokio", "tokio",
@@ -698,9 +849,9 @@ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"http", "http 1.2.0",
"http-body", "http-body 1.0.1",
"hyper", "hyper 1.5.2",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio", "tokio",
@@ -901,6 +1052,15 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.76" version = "0.3.76"
@@ -1026,7 +1186,7 @@ dependencies = [
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-util", "futures-util",
"http", "http 1.2.0",
"httparse", "httparse",
"memchr", "memchr",
"mime", "mime",
@@ -1066,7 +1226,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"cfg-if", "cfg-if",
"cfg_aliases", "cfg_aliases",
"libc", "libc",
@@ -1143,7 +1303,7 @@ version = "0.10.68"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"cfg-if", "cfg-if",
"foreign-types", "foreign-types",
"libc", "libc",
@@ -1207,7 +1367,7 @@ dependencies = [
"libc", "libc",
"redox_syscall", "redox_syscall",
"smallvec", "smallvec",
"windows-targets", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@@ -1360,7 +1520,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
] ]
[[package]] [[package]]
@@ -1407,6 +1567,47 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 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]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.12.9" version = "0.12.9"
@@ -1418,12 +1619,12 @@ dependencies = [
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2 0.4.7",
"http", "http 1.2.0",
"http-body", "http-body 1.0.1",
"http-body-util", "http-body-util",
"hyper", "hyper 1.5.2",
"hyper-rustls", "hyper-rustls 0.27.5",
"hyper-tls", "hyper-tls",
"hyper-util", "hyper-util",
"ipnet", "ipnet",
@@ -1434,12 +1635,12 @@ dependencies = [
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"rustls-pemfile", "rustls-pemfile 2.2.0",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"sync_wrapper 1.0.2", "sync_wrapper 1.0.2",
"system-configuration", "system-configuration 0.6.1",
"tokio", "tokio",
"tokio-native-tls", "tokio-native-tls",
"tokio-util", "tokio-util",
@@ -1513,13 +1714,25 @@ version = "0.38.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys 0.59.0", "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]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.20" version = "0.23.20"
@@ -1530,7 +1743,7 @@ dependencies = [
"once_cell", "once_cell",
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
"rustls-webpki", "rustls-webpki 0.102.8",
"subtle", "subtle",
"zeroize", "zeroize",
] ]
@@ -1547,6 +1760,15 @@ dependencies = [
"security-framework 3.1.0", "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]] [[package]]
name = "rustls-pemfile" name = "rustls-pemfile"
version = "2.2.0" version = "2.2.0"
@@ -1562,6 +1784,16 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" 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]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.102.8" version = "0.102.8"
@@ -1613,7 +1845,7 @@ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
"http-body-util", "http-body-util",
"hyper-rustls", "hyper-rustls 0.27.5",
"hyper-util", "hyper-util",
"jsonwebtoken", "jsonwebtoken",
"salvo_core", "salvo_core",
@@ -1632,11 +1864,11 @@ checksum = "ef1f0487e3987c47c2e26d71a9ec696282f0c79203b22f4b9d50afc33273df5f"
dependencies = [ dependencies = [
"fastrand", "fastrand",
"futures-util", "futures-util",
"hyper", "hyper 1.5.2",
"hyper-rustls", "hyper-rustls 0.27.5",
"hyper-util", "hyper-util",
"percent-encoding", "percent-encoding",
"reqwest", "reqwest 0.12.9",
"salvo_core", "salvo_core",
"tokio", "tokio",
"tracing", "tracing",
@@ -1681,17 +1913,20 @@ checksum = "447c7ab93300c57c76c95412cc469ef07943c698ef022dc08f743f92c05847a8"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64 0.22.1", "base64 0.22.1",
"brotli",
"bytes", "bytes",
"cookie", "cookie",
"encoding_rs",
"enumflags2", "enumflags2",
"flate2",
"form_urlencoded", "form_urlencoded",
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"headers", "headers",
"http", "http 1.2.0",
"http-body-util", "http-body-util",
"hyper", "hyper 1.5.2",
"hyper-rustls", "hyper-rustls 0.27.5",
"hyper-util", "hyper-util",
"indexmap", "indexmap",
"mime", "mime",
@@ -1704,18 +1939,21 @@ dependencies = [
"pin-project", "pin-project",
"rand", "rand",
"regex", "regex",
"rustls-pemfile", "rustls-pemfile 2.2.0",
"salvo_macros", "salvo_macros",
"serde", "serde",
"serde-xml-rs", "serde-xml-rs",
"serde_json", "serde_json",
"serde_urlencoded",
"sync_wrapper 1.0.2", "sync_wrapper 1.0.2",
"tempfile", "tempfile",
"thiserror 2.0.9", "thiserror 2.0.9",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls 0.26.1",
"tokio-util", "tokio-util",
"tracing", "tracing",
"url",
"zstd",
] ]
[[package]] [[package]]
@@ -1728,7 +1966,7 @@ dependencies = [
"etag", "etag",
"futures-util", "futures-util",
"http-body-util", "http-body-util",
"hyper", "hyper 1.5.2",
"pin-project", "pin-project",
"salvo_core", "salvo_core",
"serde", "serde",
@@ -1778,13 +2016,23 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 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]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.11.1" version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"core-foundation 0.9.4", "core-foundation 0.9.4",
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@@ -1797,7 +2045,7 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc" checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"core-foundation 0.10.0", "core-foundation 0.10.0",
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@@ -2005,15 +2253,36 @@ dependencies = [
"syn", "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]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.6.1" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [ dependencies = [
"bitflags", "bitflags 2.6.0",
"core-foundation 0.9.4", "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]] [[package]]
@@ -2167,13 +2436,23 @@ dependencies = [
"tokio", "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]] [[package]]
name = "tokio-rustls" name = "tokio-rustls"
version = "0.26.1" version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
dependencies = [ dependencies = [
"rustls", "rustls 0.23.20",
"tokio", "tokio",
] ]
@@ -2557,6 +2836,12 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "webpki-roots"
version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -2594,7 +2879,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@@ -2605,7 +2890,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
dependencies = [ dependencies = [
"windows-result", "windows-result",
"windows-strings", "windows-strings",
"windows-targets", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@@ -2614,7 +2899,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@@ -2624,7 +2909,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [ dependencies = [
"windows-result", "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]] [[package]]
@@ -2633,7 +2927,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@@ -2642,7 +2936,22 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [ 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]] [[package]]
@@ -2651,28 +2960,46 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.52.6",
"windows_i686_gnu", "windows_i686_gnu 0.52.6",
"windows_i686_gnullvm", "windows_i686_gnullvm",
"windows_i686_msvc", "windows_i686_msvc 0.52.6",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc", "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]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.6" version = "0.52.6"
@@ -2685,24 +3012,48 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 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]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 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]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 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]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
@@ -2718,6 +3069,16 @@ dependencies = [
"memchr", "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]] [[package]]
name = "write16" name = "write16"
version = "1.0.0" version = "1.0.0"
@@ -2835,3 +3196,31 @@ dependencies = [
"quote", "quote",
"syn", "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",
]

View File

@@ -6,9 +6,12 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.95" anyhow = "1.0.95"
chrono = { version = "0.4.39", features = ["serde"] } chrono = { version = "0.4.39", features = ["serde"] }
dotenv = "0.15"
futures-util = "0.3.31" futures-util = "0.3.31"
rand = "0.8.5" 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 = { version = "1.0.216", features = ["derive"] }
serde_json = "1.0.134" serde_json = "1.0.134"
tokio = { version = "1", features = ["macros"] } tokio = { version = "1", features = ["macros"] }

View File

@@ -130,7 +130,7 @@ export default function DownloadButton({
<MenuItem> <MenuItem>
<a <a
className="group flex w-full items-center gap-2 rounded-lg py-1.5 px-2 data-[focus]:bg-white/10" className="group flex w-full items-center gap-2 rounded-lg py-1.5 px-2 data-[focus]:bg-white/10"
href={buildLog} href={buildLog.startsWith('/') ? withBackend(buildLog) : buildLog}
target="_blank" target="_blank"
> >
<BeakerIcon className="size-4 fill-white/40" /> <BeakerIcon className="size-4 fill-white/40" />

View File

@@ -19,9 +19,10 @@ use tracing_subscriber::EnvFilter;
use crate::models::State; use crate::models::State;
static STORE: LazyLock<Mutex<State>> = LazyLock::new(State::new); static STORE: LazyLock<Mutex<State>> = LazyLock::new(|| Mutex::new(State::new()));
mod models; mod models;
mod railway;
mod utility; mod utility;
#[handler] #[handler]
@@ -110,7 +111,7 @@ async fn handle_socket(session_id: u32, websocket: WebSocket) {
// Create the executable message first, borrow issues // Create the executable message first, borrow issues
let executable_message = OutgoingMessage::Executables { let executable_message = OutgoingMessage::Executables {
executables: store.executable_json(), 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 let session = store
@@ -185,6 +186,53 @@ async fn handle_socket(session_id: u32, websocket: WebSocket) {
tokio::task::spawn(fut); 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] #[handler]
pub async fn download(req: &mut Request, res: &mut Response, depot: &mut Depot) { pub async fn download(req: &mut Request, res: &mut Response, depot: &mut Depot) {
let download_id = req let download_id = req
@@ -333,6 +381,9 @@ fn get_session_id(req: &Request, depot: &Depot) -> Option<u32> {
#[tokio::main] #[tokio::main]
async fn 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 port = std::env::var("PORT").unwrap_or_else(|_| "5800".to_string());
let addr = format!("0.0.0.0:{}", port); let addr = format!("0.0.0.0:{}", port);
tracing_subscriber::fmt() tracing_subscriber::fmt()
@@ -352,7 +403,7 @@ async fn main() {
// Check if we are deployed on Railway // Check if we are deployed on Railway
let is_railway = env::var("RAILWAY_PROJECT_ID").is_ok(); let is_railway = env::var("RAILWAY_PROJECT_ID").is_ok();
if is_railway { if is_railway {
let build_logs = format!( let build_logs_url = format!(
"https://railway.com/project/{}/service/{}?environmentId={}&id={}#build", "https://railway.com/project/{}/service/{}?environmentId={}&id={}#build",
env::var("RAILWAY_PROJECT_ID").unwrap(), env::var("RAILWAY_PROJECT_ID").unwrap(),
env::var("RAILWAY_SERVICE_ID").unwrap(), env::var("RAILWAY_SERVICE_ID").unwrap(),
@@ -360,8 +411,26 @@ async fn main() {
env::var("RAILWAY_DEPLOYMENT_ID").unwrap() env::var("RAILWAY_DEPLOYMENT_ID").unwrap()
); );
tracing::info!("Build logs available here: {}", build_logs); tracing::info!("Build logs available here: {}", build_logs_url);
store.build_log = Some(build_logs); 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"); store.add_executable("Windows", "./demo.exe");
@@ -400,6 +469,8 @@ async fn main() {
.hoop(CatchPanic::new()) .hoop(CatchPanic::new())
// /notify does not need a session, nor should it have one // /notify does not need a session, nor should it have one
.push(Router::with_path("notify").post(notify)) .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( .push(
Router::new() Router::new()
.hoop(session_middleware) .hoop(session_middleware)

View File

@@ -1,10 +1,17 @@
use salvo::{http::cookie::Cookie, websocket::Message, Response}; use salvo::{http::cookie::Cookie, websocket::Message, Response};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashMap, path}; use std::{collections::HashMap, path};
use tokio::sync::{mpsc::UnboundedSender, Mutex}; use tokio::sync::mpsc::UnboundedSender;
use crate::utility::search; use crate::utility::search;
#[derive(Debug, Clone)]
pub struct BuildLogs {
pub content: String,
pub fetched_at: chrono::DateTime<chrono::Utc>,
pub content_hash: u64,
}
#[derive(Debug, Serialize, Clone)] #[derive(Debug, Serialize, Clone)]
pub struct Session { pub struct Session {
pub id: u32, pub id: u32,
@@ -98,26 +105,25 @@ pub struct SessionDownload {
impl SessionDownload {} impl SessionDownload {}
#[derive(Clone, Debug)] #[derive(Default)]
pub struct State<'a> { pub struct State {
// 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)
pub sessions: HashMap<u32, Session>, pub sessions: HashMap<u32, Session>,
// Provided on startup, the URL to the build log of the current deployment pub executables: HashMap<String, Executable>,
pub build_log: Option<String>, pub build_logs: Option<BuildLogs>,
pub build_log_url: Option<String>,
} }
impl<'a> State<'a> { impl State {
pub fn new() -> Mutex<Self> { pub fn new() -> Self {
Mutex::new(Self { Self {
build_log: None,
executables: HashMap::new(),
sessions: HashMap::new(), 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 data = std::fs::read(&exe_path).expect("Unable to read file");
let pattern = "a".repeat(1024); let pattern = "a".repeat(1024);
@@ -140,7 +146,7 @@ impl<'a> State<'a> {
key_end: key_end, 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 { pub async fn new_session(&mut self, res: &mut Response) -> u32 {

178
src/railway.rs Normal file
View File

@@ -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<serde_json::Value>,
errors: Option<Vec<GraphQLError>>,
}
#[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<crate::models::BuildLogs> {
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<String> = 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::<Vec<BuildLogEntry>>(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"))
}
}