Add Prometheus metrics support and update Rust to edition 2024 and version 1.85.0
Some checks failed
Push Dev / docker (push) Has been cancelled

This commit is contained in:
Shiroyasha 2025-02-26 01:14:01 +03:00
parent bac1203df8
commit 45aa79da6d
Signed by: shiroyashik
GPG key ID: E4953D3940D7860A
14 changed files with 306 additions and 128 deletions

192
Cargo.lock generated
View file

@ -60,9 +60,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.95" version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4"
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
@ -248,9 +248,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.13" version = "1.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@ -591,9 +591,9 @@ dependencies = [
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]] [[package]]
name = "errno" name = "errno"
@ -650,7 +650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide 0.8.4", "miniz_oxide 0.8.5",
] ]
[[package]] [[package]]
@ -783,9 +783,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.4.7" version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2"
dependencies = [ dependencies = [
"atomic-waker", "atomic-waker",
"bytes", "bytes",
@ -852,6 +852,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]] [[package]]
name = "hmac" name = "hmac"
version = "0.12.1" version = "0.12.1"
@ -1200,9 +1206,9 @@ dependencies = [
[[package]] [[package]]
name = "inout" name = "inout"
version = "0.1.3" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [ dependencies = [
"generic-array", "generic-array",
] ]
@ -1317,9 +1323,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.25" version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
[[package]] [[package]]
name = "lzma-rs" name = "lzma-rs"
@ -1369,9 +1375,9 @@ dependencies = [
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.4" 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 = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
dependencies = [ dependencies = [
"adler2", "adler2",
] ]
@ -1390,9 +1396,9 @@ dependencies = [
[[package]] [[package]]
name = "native-tls" name = "native-tls"
version = "0.2.13" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
@ -1495,9 +1501,9 @@ checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.70" version = "0.10.71"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
dependencies = [ dependencies = [
"bitflags 2.8.0", "bitflags 2.8.0",
"cfg-if", "cfg-if",
@ -1527,9 +1533,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.105" version = "0.9.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1663,6 +1669,52 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "procfs"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4"
dependencies = [
"bitflags 2.8.0",
"hex",
"lazy_static",
"procfs-core",
"rustix",
]
[[package]]
name = "procfs-core"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
dependencies = [
"bitflags 2.8.0",
"hex",
]
[[package]]
name = "prometheus"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1"
dependencies = [
"cfg-if",
"fnv",
"lazy_static",
"libc",
"memchr",
"parking_lot",
"procfs",
"protobuf",
"thiserror 1.0.69",
]
[[package]]
name = "protobuf"
version = "2.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.38" version = "1.0.38"
@ -1690,8 +1742,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [ dependencies = [
"rand_chacha 0.9.0", "rand_chacha 0.9.0",
"rand_core 0.9.0", "rand_core 0.9.1",
"zerocopy 0.8.17", "zerocopy 0.8.20",
] ]
[[package]] [[package]]
@ -1711,7 +1763,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [ dependencies = [
"ppv-lite86", "ppv-lite86",
"rand_core 0.9.0", "rand_core 0.9.1",
] ]
[[package]] [[package]]
@ -1725,19 +1777,19 @@ dependencies = [
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.9.0" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3"
dependencies = [ dependencies = [
"getrandom 0.3.1", "getrandom 0.3.1",
"zerocopy 0.8.17", "zerocopy 0.8.20",
] ]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.8" version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f"
dependencies = [ dependencies = [
"bitflags 2.8.0", "bitflags 2.8.0",
] ]
@ -1844,15 +1896,14 @@ dependencies = [
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.17.8" version = "0.17.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" checksum = "d34b5020fcdea098ef7d95e9f89ec15952123a4a039badd09fabebe9e963e839"
dependencies = [ dependencies = [
"cc", "cc",
"cfg-if", "cfg-if",
"getrandom 0.2.15", "getrandom 0.2.15",
"libc", "libc",
"spin",
"untrusted", "untrusted",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@ -1973,8 +2024,8 @@ dependencies = [
"dotenvy", "dotenvy",
"faster-hex", "faster-hex",
"indexmap 2.7.1", "indexmap 2.7.1",
"lazy_static",
"notify", "notify",
"prometheus",
"rand 0.9.0", "rand 0.9.0",
"reqwest", "reqwest",
"ring", "ring",
@ -2025,18 +2076,18 @@ checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.217" version = "1.0.218"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.217" version = "1.0.218"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2054,9 +2105,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.138" version = "1.0.139"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -2159,9 +2210,9 @@ dependencies = [
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.13.2" version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]] [[package]]
name = "socket2" name = "socket2"
@ -2173,12 +2224,6 @@ dependencies = [
"windows-sys 0.52.0", "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]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"
@ -2272,9 +2317,9 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.16.0" version = "3.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
@ -2441,9 +2486,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-tungstenite" name = "tokio-tungstenite"
version = "0.26.1" version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4bf6fecd69fcdede0ec680aaf474cdab988f9de6bc73d3758f0160e3b7025a" checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
@ -2644,17 +2689,16 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]] [[package]]
name = "tungstenite" name = "tungstenite"
version = "0.26.1" version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413083a99c579593656008130e29255e54dcaae495be556cc26888f211648c24" checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13"
dependencies = [ dependencies = [
"byteorder",
"bytes", "bytes",
"data-encoding", "data-encoding",
"http", "http",
"httparse", "httparse",
"log", "log",
"rand 0.8.5", "rand 0.9.0",
"sha1", "sha1",
"thiserror 2.0.11", "thiserror 2.0.11",
"utf-8", "utf-8",
@ -2662,15 +2706,15 @@ dependencies = [
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.17.0" version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.16" version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
@ -2709,9 +2753,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.13.1" version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" checksum = "93d59ca99a559661b96bf898d8fce28ed87935fd2bea9f05983c1464dd6c71b1"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -3015,9 +3059,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.7.2" version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -3079,11 +3123,11 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.8.17" version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" checksum = "dde3bb8c68a8f3f1ed4ac9221aad6b10cece3e60a8e2ea54a6a2dec806d0084c"
dependencies = [ dependencies = [
"zerocopy-derive 0.8.17", "zerocopy-derive 0.8.20",
] ]
[[package]] [[package]]
@ -3099,9 +3143,9 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.8.17" version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" checksum = "eea57037071898bf96a6da35fd626f4f27e9cee3ead2a6c703cf09d472b2e700"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3216,27 +3260,27 @@ dependencies = [
[[package]] [[package]]
name = "zstd" name = "zstd"
version = "0.13.2" version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [ dependencies = [
"zstd-safe", "zstd-safe",
] ]
[[package]] [[package]]
name = "zstd-safe" name = "zstd-safe"
version = "7.2.1" version = "7.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722"
dependencies = [ dependencies = [
"zstd-sys", "zstd-sys",
] ]
[[package]] [[package]]
name = "zstd-sys" name = "zstd-sys"
version = "2.0.13+zstd.1.5.6" version = "2.0.14+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5"
dependencies = [ dependencies = [
"cc", "cc",
"pkg-config", "pkg-config",

View file

@ -2,7 +2,7 @@
name = "sculptor" name = "sculptor"
authors = ["Shiroyashik <shiroyashik@shsr.ru>"] authors = ["Shiroyashik <shiroyashik@shsr.ru>"]
version = "0.4.1-dev" version = "0.4.1-dev"
edition = "2021" edition = "2024"
publish = false publish = false
[dependencies] [dependencies]
@ -31,7 +31,6 @@ semver = "1.0"
walkdir = "2.5" walkdir = "2.5"
indexmap = { version = "2.6", features = ["serde"] } indexmap = { version = "2.6", features = ["serde"] }
zip = "2.2" zip = "2.2"
lazy_static = "1.5"
notify = "8.0" notify = "8.0"
# Crypto # Crypto
@ -42,6 +41,7 @@ rand = "0.9"
axum = { version = "0.8", features = ["ws", "macros", "http2"] } axum = { version = "0.8", features = ["ws", "macros", "http2"] }
tower-http = { version = "0.6", features = ["trace"] } tower-http = { version = "0.6", features = ["trace"] }
tokio = { version = "1.41", features = ["full"] } tokio = { version = "1.41", features = ["full"] }
prometheus = { version = "0.13.4", features = ["process"] }
[dev-dependencies] [dev-dependencies]
cross = "0.2.5" cross = "0.2.5"

View file

@ -4,8 +4,12 @@ listen = "0.0.0.0:6665"
## Don't touch if you don't know what you're doing ## Don't touch if you don't know what you're doing
# token = "<random symbols>" # token = "<random symbols>"
## Enable Prometheus metrics
# metricsEnabled = true
## Path to minecraft server folder ## Path to minecraft server folder
## Sculptor try to use ban list from it ## Sculptor try to use ban list from it
## on Windows use double slash: "C:\\Servers\\1.20.1"
# mcFolder = "~/minecraft_server" # mcFolder = "~/minecraft_server"
## Can't work without at least one provider! ## Can't work without at least one provider!

View file

@ -1,6 +1,6 @@
## Chef ## Chef
# FROM clux/muslrust:stable AS chef # FROM clux/muslrust:stable AS chef
FROM rust:1.84-alpine3.21 AS chef FROM rust:1.85-alpine3.21 AS chef
USER root USER root
RUN apk add --no-cache musl-dev libressl-dev RUN apk add --no-cache musl-dev libressl-dev
RUN cargo install cargo-chef RUN cargo install cargo-chef

View file

@ -1,7 +1,7 @@
use axum::{debug_handler, extract::{Query, State}, response::{IntoResponse, Response}, routing::get, Router}; use axum::{extract::{Query, State}, http::HeaderMap, response::{IntoResponse, Response}, routing::get, Router};
use reqwest::StatusCode; use reqwest::{header::USER_AGENT, StatusCode};
use ring::digest::{self, digest}; use ring::digest::{self, digest};
use tracing::{error, info}; use tracing::{error, info, instrument};
use crate::{auth::{has_joined, Userinfo}, utils::rand, AppState}; use crate::{auth::{has_joined, Userinfo}, utils::rand, AppState};
use super::types::auth::*; use super::types::auth::*;
@ -12,7 +12,6 @@ pub fn router() -> Router<AppState> {
.route("/verify", get(verify)) .route("/verify", get(verify))
} }
#[debug_handler]
async fn id( async fn id(
// First stage of authentication // First stage of authentication
Query(query): Query<Id>, Query(query): Query<Id>,
@ -25,10 +24,11 @@ async fn id(
server_id server_id
} }
#[debug_handler] #[instrument(skip_all)]
async fn verify( async fn verify(
// Second stage of authentication // Second stage of authentication
Query(query): Query<Verify>, Query(query): Query<Verify>,
header: HeaderMap,
State(state): State<AppState>, State(state): State<AppState>,
) -> Response { ) -> Response {
let server_id = query.id.clone(); let server_id = query.id.clone();
@ -47,17 +47,23 @@ async fn verify(
if let Some((uuid, auth_provider)) = userinfo { if let Some((uuid, auth_provider)) = userinfo {
let umanager = state.user_manager; let umanager = state.user_manager;
if umanager.is_banned(&uuid) { if umanager.is_banned(&uuid) {
info!("[Authentication] {nickname} tried to log in, but was banned"); info!("{nickname} tried to log in, but was banned");
return (StatusCode::BAD_REQUEST, "You're banned!".to_string()).into_response(); return (StatusCode::BAD_REQUEST, "You're banned!".to_string()).into_response();
} }
info!("[Authentication] {nickname} logged in using {}", auth_provider.name); let mut userinfo = Userinfo {
let userinfo = Userinfo {
nickname, nickname,
uuid, uuid,
token: Some(server_id.clone()), token: Some(server_id.clone()),
auth_provider, auth_provider,
..Default::default() ..Default::default()
}; };
if let Some(agent) = header.get(USER_AGENT) {
if let Ok(agent) = agent.to_str() {
userinfo.version = agent.to_string();
}
}
info!("{} logged in using {} with {}", userinfo.nickname, userinfo.auth_provider.name, userinfo.version);
match umanager.insert(uuid, server_id.clone(), userinfo.clone()) { match umanager.insert(uuid, server_id.clone(), userinfo.clone()) {
Ok(_) => {}, Ok(_) => {},
Err(_) => { Err(_) => {
@ -70,7 +76,7 @@ async fn verify(
} }
(StatusCode::OK, server_id.to_string()).into_response() (StatusCode::OK, server_id.to_string()).into_response()
} else { } else {
info!("[Authentication] failed to verify {nickname}"); info!("failed to verify {nickname}");
(StatusCode::BAD_REQUEST, "failed to verify".to_string()).into_response() (StatusCode::BAD_REQUEST, "failed to verify".to_string()).into_response()
} }
} }

View file

@ -15,6 +15,7 @@ pub async fn initial(
ws.on_upgrade(|socket| handle_socket(socket, state)) ws.on_upgrade(|socket| handle_socket(socket, state))
} }
#[instrument(skip_all)]
async fn handle_socket(mut ws: WebSocket, state: AppState) { async fn handle_socket(mut ws: WebSocket, state: AppState) {
// Trying authenticate & get user data or dropping connection // Trying authenticate & get user data or dropping connection
match authenticate(&mut ws, &state).await { match authenticate(&mut ws, &state).await {
@ -44,7 +45,7 @@ async fn handle_socket(mut ws: WebSocket, state: AppState) {
// Starting main worker // Starting main worker
if let Err(kind) = main_worker(&mut session, &mut ws, &state).await { if let Err(kind) = main_worker(&mut session, &mut ws, &state).await {
tracing::error!("[WebSocket] Main worker halted due to {}.", kind) tracing::info!(error = %kind, nickname = %session.user.nickname, "Main worker exited");
} }
for (_, handle) in session.sub_workers_aborthandles { for (_, handle) in session.sub_workers_aborthandles {
@ -56,7 +57,7 @@ async fn handle_socket(mut ws: WebSocket, state: AppState) {
state.user_manager.remove(&user.uuid); state.user_manager.remove(&user.uuid);
}, },
Err(kind) => { Err(kind) => {
tracing::info!("[WebSocket] Can't authenticate: {}", kind); tracing::info!(error = %kind, "Can't authenticate");
} }
} }
@ -64,7 +65,7 @@ async fn handle_socket(mut ws: WebSocket, state: AppState) {
if let Err(kind) = ws.send(Message::Close(None)).await { tracing::trace!("[WebSocket] Closing fault: {}", kind) } if let Err(kind) = ws.send(Message::Close(None)).await { tracing::trace!("[WebSocket] Closing fault: {}", kind) }
} }
#[instrument(skip_all, fields(nickname = %session.user.nickname))] #[instrument(skip_all, parent = None, fields(nickname = %session.user.nickname))]
async fn main_worker(session: &mut WSSession, ws: &mut WebSocket, state: &AppState) -> anyhow::Result<()> { async fn main_worker(session: &mut WSSession, ws: &mut WebSocket, state: &AppState) -> anyhow::Result<()> {
tracing::debug!("WebSocket control for {} is transferred to the main worker", session.user.nickname); tracing::debug!("WebSocket control for {} is transferred to the main worker", session.user.nickname);
loop { loop {

View file

@ -89,6 +89,16 @@ impl From<C2SMessage> for Vec<u8> {
a a
} }
} }
impl C2SMessage {
pub fn name(&self) -> &'static str {
match self {
C2SMessage::Token(_) => "c2s>token",
C2SMessage::Ping(_, _, _) => "c2s>ping",
C2SMessage::Sub(_) => "c2s>sub",
C2SMessage::Unsub(_) => "c2s>unsub",
}
}
}
// impl<'a> C2SMessage<'a> { // impl<'a> C2SMessage<'a> {
// pub fn to_array(&self) -> Box<[u8]> { // pub fn to_array(&self) -> Box<[u8]> {

View file

@ -3,6 +3,8 @@ mod s2c;
mod errors; mod errors;
mod session; mod session;
use std::time::Instant;
pub use session::*; pub use session::*;
pub use errors::*; pub use errors::*;
pub use c2s::*; pub use c2s::*;
@ -10,6 +12,8 @@ pub use s2c::*;
use axum::extract::ws::{Message, WebSocket}; use axum::extract::ws::{Message, WebSocket};
use crate::{PINGS, PINGS_ERROR};
pub trait RecvAndDecode { pub trait RecvAndDecode {
async fn recv_and_decode(&mut self) -> Result<C2SMessage, RADError>; async fn recv_and_decode(&mut self) -> Result<C2SMessage, RADError>;
} }
@ -21,9 +25,17 @@ impl RecvAndDecode for WebSocket {
if let Message::Close(frame) = msg { if let Message::Close(frame) = msg {
return Err(RADError::Close(frame.map(|f| format!("code: {}, reason: {}", f.code, f.reason)))); return Err(RADError::Close(frame.map(|f| format!("code: {}, reason: {}", f.code, f.reason))));
} }
let start = Instant::now();
let data = msg.into_data(); let data = msg.into_data();
C2SMessage::try_from(data.as_ref()) let msg = C2SMessage::try_from(data.as_ref())
.map_err(|e| RADError::DecodeError(e, faster_hex::hex_string(&data))) .map_err(|e| { PINGS_ERROR.inc(); RADError::DecodeError(e, faster_hex::hex_string(&data)) });
let latency = start.elapsed().as_secs_f64();
PINGS
.with_label_values(&[msg.as_ref().map(|m| m.name()).unwrap_or("error")])
.observe(latency);
msg
} }
} }

View file

@ -85,6 +85,18 @@ impl From<S2CMessage> for Vec<u8> {
} }
} }
} }
impl S2CMessage {
pub fn name(&self) -> &'static str {
match self {
S2CMessage::Auth => "s2c>auth",
S2CMessage::Ping(_, _, _, _) => "s2c>ping",
S2CMessage::Event(_) => "s2c>event",
S2CMessage::Toast(_, _, _) => "s2c>toast",
S2CMessage::Chat(_) => "s2c>chat",
S2CMessage::Notice(_) => "s2c>notice",
}
}
}
// impl<'a> S2CMessage<'a> { // impl<'a> S2CMessage<'a> {
// pub fn to_array(&self) -> Box<[u8]> { // pub fn to_array(&self) -> Box<[u8]> {

View file

@ -2,10 +2,11 @@ use axum::{
extract::{Path, State}, extract::{Path, State},
Json Json
}; };
use dashmap::DashMap;
use tracing::{debug, info}; use tracing::{debug, info};
use uuid::Uuid; use uuid::Uuid;
use crate::{api::errors::internal_and_log, auth::{Token, Userinfo}, ApiResult, AppState}; use crate::{auth::{Token, Userinfo}, ApiResult, AppState};
pub(super) async fn create_user( pub(super) async fn create_user(
Token(token): Token, Token(token): Token,
@ -50,17 +51,17 @@ pub(super) async fn unban(
pub(super) async fn list( pub(super) async fn list(
Token(token): Token, Token(token): Token,
State(state): State<AppState>, State(state): State<AppState>,
) -> ApiResult<String> { ) -> ApiResult<Json<DashMap<Uuid, Userinfo>>> {
state.config.read().await.clone().verify_token(&token)?; state.config.read().await.clone().verify_token(&token)?;
serde_json::to_string_pretty(&state.user_manager.get_all_registered()).map_err(|err| { internal_and_log(err) }) Ok(Json(state.user_manager.get_all_registered()))
} }
pub(super) async fn list_sessions( pub(super) async fn list_sessions(
Token(token): Token, Token(token): Token,
State(state): State<AppState>, State(state): State<AppState>,
) -> ApiResult<String> { ) -> ApiResult<Json<DashMap<String, Uuid>>> {
state.config.read().await.clone().verify_token(&token)?; state.config.read().await.clone().verify_token(&token)?;
serde_json::to_string_pretty(&state.user_manager.get_all_authenticated()).map_err(|err| { internal_and_log(err) }) Ok(Json(state.user_manager.get_all_authenticated()))
} }

View file

@ -182,6 +182,12 @@ pub struct UManager {
registered: Arc<DashMap<Uuid, Userinfo>>, registered: Arc<DashMap<Uuid, Userinfo>>,
} }
impl Default for UManager {
fn default() -> Self {
Self::new()
}
}
impl UManager { impl UManager {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -229,6 +235,7 @@ impl UManager {
if userinfo.rank != Userinfo::default().rank { exist.rank = userinfo.rank }; if userinfo.rank != Userinfo::default().rank { exist.rank = userinfo.rank };
if userinfo.token.is_some() { exist.token = userinfo.token }; if userinfo.token.is_some() { exist.token = userinfo.token };
if userinfo.version != Userinfo::default().version { exist.version = userinfo.version }; if userinfo.version != Userinfo::default().version { exist.version = userinfo.version };
exist.last_used = userinfo.last_used;
}).or_insert(usercopy); }).or_insert(usercopy);
} }
pub fn get( pub fn get(
@ -274,7 +281,6 @@ impl UManager {
} }
// End of User manager // End of User manager
#[axum::debug_handler]
#[instrument(skip_all)] #[instrument(skip_all)]
pub async fn check_auth( pub async fn check_auth(
token: Option<Token>, token: Option<Token>,

View file

@ -6,10 +6,9 @@ use axum::{
use dashmap::DashMap; use dashmap::DashMap;
use tracing_panic::panic_hook; use tracing_panic::panic_hook;
use tracing_subscriber::{fmt::{self, time::ChronoLocal}, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; use tracing_subscriber::{fmt::{self, time::ChronoLocal}, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
use std::{path::PathBuf, sync::Arc, env::var}; use std::{env::var, path::PathBuf, sync::{Arc, LazyLock}};
use tokio::{fs, sync::RwLock, time::Instant}; use tokio::{fs, sync::RwLock, time::Instant};
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
use lazy_static::lazy_static;
// Consts // Consts
mod consts; mod consts;
@ -18,12 +17,13 @@ pub use consts::*;
// Errors // Errors
pub use api::errors::{ApiResult, ApiError}; pub use api::errors::{ApiResult, ApiError};
// Metrics
mod metrics;
pub use metrics::*;
// API // API
mod api; mod api;
use api::{ use api::figura::{ws, info as api_info, profile as api_profile, auth as api_auth, assets as api_assets};
figura::{ws, info as api_info, profile as api_profile, auth as api_auth, assets as api_assets},
// v1::{},
};
// Auth // Auth
mod auth; mod auth;
@ -37,23 +37,21 @@ use state::{Config, AppState};
mod utils; mod utils;
use utils::*; use utils::*;
lazy_static! { pub static LOGGER_VAR: LazyLock<String> = LazyLock::new(|| {
pub static ref LOGGER_VAR: String = { var(LOGGER_ENV).unwrap_or(String::from("info"))
var(LOGGER_ENV).unwrap_or(String::from("info")) });
}; pub static CONFIG_VAR: LazyLock<String> = LazyLock::new(|| {
pub static ref CONFIG_VAR: String = { var(CONFIG_ENV).unwrap_or(String::from("Config.toml"))
var(CONFIG_ENV).unwrap_or(String::from("Config.toml")) });
}; pub static LOGS_VAR: LazyLock<String> = LazyLock::new(|| {
pub static ref LOGS_VAR: String = { var(LOGS_ENV).unwrap_or(String::from("logs"))
var(LOGS_ENV).unwrap_or(String::from("logs")) });
}; pub static ASSETS_VAR: LazyLock<String> = LazyLock::new(|| {
pub static ref ASSETS_VAR: String = { var(ASSETS_ENV).unwrap_or(String::from("data/assets"))
var(ASSETS_ENV).unwrap_or(String::from("data/assets")) });
}; pub static AVATARS_VAR: LazyLock<String> = LazyLock::new(|| {
pub static ref AVATARS_VAR: String = { var(AVATARS_ENV).unwrap_or(String::from("data/avatars"))
var(AVATARS_ENV).unwrap_or(String::from("data/avatars")) });
};
}
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
@ -128,11 +126,11 @@ async fn app() -> Result<bool> {
} }
// Config // Config
let config = Arc::new(RwLock::new(Config::parse(CONFIG_VAR.clone().into()))); let config = Config::parse(CONFIG_VAR.clone().into());
let listen = config.read().await.listen.clone(); let listen = config.listen.clone();
let limit = get_limit_as_bytes(config.read().await.limitations.max_avatar_size as usize); let limit = get_limit_as_bytes(config.limitations.max_avatar_size as usize);
if config.read().await.assets_updater_enabled { if config.assets_updater_enabled {
// Force update assets if folder or hash file doesn't exists. // Force update assets if folder or hash file doesn't exists.
if !(PathBuf::from(&*ASSETS_VAR).is_dir() && get_path_to_assets_hash().is_file()) { if !(PathBuf::from(&*ASSETS_VAR).is_dir() && get_path_to_assets_hash().is_file()) {
tracing::debug!("Removing broken assets..."); tracing::debug!("Removing broken assets...");
@ -164,7 +162,7 @@ async fn app() -> Result<bool> {
session: Arc::new(DashMap::new()), session: Arc::new(DashMap::new()),
subscribes: Arc::new(DashMap::new()), subscribes: Arc::new(DashMap::new()),
figura_versions: Arc::new(RwLock::new(None)), figura_versions: Arc::new(RwLock::new(None)),
config, config: Arc::new(RwLock::new(config.clone())),
}; };
// Automatic update of configuration/ban list while the server is running // Automatic update of configuration/ban list while the server is running
@ -175,7 +173,7 @@ async fn app() -> Result<bool> {
Arc::clone(&state.config) Arc::clone(&state.config)
)); ));
// Blacklist auto update // Blacklist auto update
if state.config.read().await.mc_folder.exists() { if config.mc_folder.exists() {
tokio::spawn(update_bans_from_minecraft( tokio::spawn(update_bans_from_minecraft(
state.config.read().await.mc_folder.clone(), state.config.read().await.mc_folder.clone(),
Arc::clone(&state.user_manager), Arc::clone(&state.user_manager),
@ -200,8 +198,19 @@ async fn app() -> Result<bool> {
.nest("/api", api) .nest("/api", api)
.route("/api/", get(check_auth)) .route("/api/", get(check_auth))
.route("/ws", get(ws)) .route("/ws", get(ws))
.with_state(state) .layer(TraceLayer::new_for_http()
.layer(TraceLayer::new_for_http().on_request(())) // .on_request(|request: &axum::http::Request<_>, _span: &tracing::Span| {
// // only for developing purposes
// tracing::trace!(headers = ?request.headers(), "started processing request");
// })
.on_response(|response: &axum::http::Response<_>, latency: std::time::Duration, _span: &tracing::Span| {
tracing::trace!(latency = ?latency, status = ?response.status(), "finished processing request");
})
.on_request(())
)
.layer(axum::middleware::from_fn(track_metrics))
.merge(metrics::metrics_router(config.metrics_enabled))
.with_state(state)
.route("/health", get(|| async { "ok" })); .route("/health", get(|| async { "ok" }));
let listener = tokio::net::TcpListener::bind(listen).await?; let listener = tokio::net::TcpListener::bind(listen).await?;

71
src/metrics.rs Normal file
View file

@ -0,0 +1,71 @@
use std::{sync::LazyLock, time::Instant};
use axum::{body::Body, extract::State, http::{Request, Response}, middleware::Next, routing::get, Router};
use prometheus::{proto::{Metric, MetricType}, register_histogram_vec, register_int_counter};
use reqwest::StatusCode;
use crate::state::AppState;
pub fn metrics_router(enabled: bool) -> Router<AppState> {
if !enabled { return Router::new(); }
tracing::info!("Metrics enabled! You can access them on /metrics");
Router::new()
.route("/metrics", get(metrics))
}
async fn metrics(State(state): State<AppState>) -> String {
let mut metric_families = prometheus::gather();
// Add new custom metrics
let players = {
let mut metric = prometheus::proto::Metric::default();
metric.set_gauge(prometheus::proto::Gauge::default());
metric.mut_gauge().set_value(state.session.len() as f64);
create_mf("players_count".to_string(), "Number of players".to_string(), MetricType::GAUGE, metric)
};
metric_families.push(players);
prometheus::TextEncoder::new()
.encode_to_string(&metric_families)
.unwrap()
}
#[inline]
fn create_mf(name: String, help: String, field_type: MetricType, metric: Metric) -> prometheus::proto::MetricFamily {
let mut mf = prometheus::proto::MetricFamily::default();
mf.set_name(name);
mf.set_help(help);
mf.set_field_type(field_type);
mf.mut_metric().push(metric);
mf
}
pub async fn track_metrics(req: Request<Body>, next: Next) -> Result<Response<Body>, StatusCode> {
let start = Instant::now();
let uri = req.uri().path().to_string();
// Call the next middleware or handler
let response = next.run(req).await;
let latency = start.elapsed().as_secs_f64();
REQUESTS
.with_label_values(&[&uri, response.status().as_str()])
.observe(latency);
Ok(response)
}
pub static PINGS_ERROR: LazyLock<prometheus::IntCounter> = LazyLock::new(|| {
register_int_counter!("pings_error", "Number of ping decoding errors").unwrap()
});
pub static REQUESTS: LazyLock<prometheus::HistogramVec> = LazyLock::new(|| {
register_histogram_vec!("requests_count", "Number of requests", &["uri", "code"], vec![0.025, 0.250, 0.500]).unwrap()
});
pub static PINGS: LazyLock<prometheus::HistogramVec> = LazyLock::new(|| {
register_histogram_vec!("pings_count", "Number of pings", &["type"], vec![0.000003, 0.00002, 0.0002]).unwrap()
});

View file

@ -10,6 +10,8 @@ use crate::auth::{default_authproviders, AuthProviders, Userinfo};
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Config { pub struct Config {
pub listen: String, pub listen: String,
#[serde(default)]
pub metrics_enabled: bool,
pub token: Option<String>, pub token: Option<String>,
pub assets_updater_enabled: bool, pub assets_updater_enabled: bool,
pub motd: CMotd, pub motd: CMotd,