🎉WebSocket refactored!

This commit is contained in:
Shiroyasha 2024-10-28 03:19:33 +03:00
parent 7a4f3dc7a5
commit 4c0871e26c
Signed by: shiroyashik
GPG key ID: E4953D3940D7860A
30 changed files with 650 additions and 587 deletions

323
Cargo.lock generated
View file

@ -60,9 +60,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.89" version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
@ -75,13 +75,13 @@ dependencies = [
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.82" version = "0.1.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -103,9 +103,9 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "axum" name = "axum"
@ -139,7 +139,7 @@ dependencies = [
"sync_wrapper 1.0.1", "sync_wrapper 1.0.1",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
"tower 0.5.1", "tower",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing", "tracing",
@ -174,7 +174,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -233,9 +233,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.7.1" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
[[package]] [[package]]
name = "bzip2" name = "bzip2"
@ -260,9 +260,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.1.19" version = "1.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@ -529,7 +529,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -571,7 +571,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -594,9 +594,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.34" version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -635,9 +635,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.33" version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide 0.8.0", "miniz_oxide 0.8.0",
@ -675,9 +675,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@ -685,33 +685,33 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-io", "futures-io",
@ -762,7 +762,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"http", "http",
"indexmap 2.5.0", "indexmap 2.6.0",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -781,6 +781,12 @@ version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.1" version = "0.4.1"
@ -862,9 +868,9 @@ dependencies = [
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.9.4" version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
[[package]] [[package]]
name = "httpdate" name = "httpdate"
@ -874,9 +880,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.4.1" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@ -928,9 +934,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.8" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@ -941,7 +947,6 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio", "tokio",
"tower 0.4.13",
"tower-service", "tower-service",
"tracing", "tracing",
] ]
@ -997,12 +1002,12 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.5.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.14.5", "hashbrown 0.15.0",
"serde", "serde",
] ]
@ -1017,9 +1022,9 @@ dependencies = [
[[package]] [[package]]
name = "ipnet" name = "ipnet"
version = "2.10.0" version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
[[package]] [[package]]
name = "is_ci" name = "is_ci"
@ -1044,9 +1049,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.70" version = "0.3.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -1059,9 +1064,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.158" version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]] [[package]]
name = "libredox" name = "libredox"
@ -1244,15 +1249,15 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.19.0" version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.66" 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 = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"cfg-if", "cfg-if",
@ -1271,7 +1276,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -1282,9 +1287,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.103" version = "0.9.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1352,31 +1357,11 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pin-project"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.77",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.14" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
[[package]] [[package]]
name = "pin-utils" name = "pin-utils"
@ -1386,9 +1371,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]] [[package]]
name = "powerfmt" name = "powerfmt"
@ -1431,9 +1416,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.86" version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -1479,9 +1464,9 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.4" version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
] ]
@ -1499,14 +1484,14 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.6" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata 0.4.7", "regex-automata 0.4.8",
"regex-syntax 0.8.4", "regex-syntax 0.8.5",
] ]
[[package]] [[package]]
@ -1520,13 +1505,13 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
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 = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax 0.8.4", "regex-syntax 0.8.5",
] ]
[[package]] [[package]]
@ -1537,15 +1522,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
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 = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.12.7" version = "0.12.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
dependencies = [ dependencies = [
"base64", "base64",
"bytes", "bytes",
@ -1617,9 +1602,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.37" version = "0.38.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"errno", "errno",
@ -1630,9 +1615,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.13" version = "0.23.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"rustls-pki-types", "rustls-pki-types",
@ -1643,19 +1628,18 @@ dependencies = [
[[package]] [[package]]
name = "rustls-pemfile" name = "rustls-pemfile"
version = "2.1.3" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
dependencies = [ dependencies = [
"base64",
"rustls-pki-types", "rustls-pki-types",
] ]
[[package]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.8.0" version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
@ -1670,9 +1654,9 @@ dependencies = [
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.17" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
[[package]] [[package]]
name = "ryu" name = "ryu"
@ -1691,9 +1675,9 @@ dependencies = [
[[package]] [[package]]
name = "schannel" name = "schannel"
version = "0.1.24" version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1"
dependencies = [ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
@ -1716,7 +1700,7 @@ dependencies = [
"dashmap", "dashmap",
"dotenvy", "dotenvy",
"hex", "hex",
"indexmap 2.5.0", "indexmap 2.6.0",
"lazy_static", "lazy_static",
"rand", "rand",
"reqwest", "reqwest",
@ -1752,9 +1736,9 @@ dependencies = [
[[package]] [[package]]
name = "security-framework-sys" name = "security-framework-sys"
version = "2.11.1" version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -1768,22 +1752,22 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.210" version = "1.0.213"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.210" version = "1.0.213"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -1797,9 +1781,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.128" version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -1819,9 +1803,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_spanned" name = "serde_spanned"
version = "0.6.7" version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -1957,9 +1941,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.77" version = "2.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2004,9 +1988,9 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.12.0" version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
@ -2032,22 +2016,22 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.64" version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.64" version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -2108,9 +2092,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.40.0" version = "1.41.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@ -2132,7 +2116,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -2213,32 +2197,17 @@ dependencies = [
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.22.21" version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [ dependencies = [
"indexmap 2.5.0", "indexmap 2.6.0",
"serde", "serde",
"serde_spanned", "serde_spanned",
"toml_datetime", "toml_datetime",
"winnow", "winnow",
] ]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"pin-project",
"pin-project-lite",
"tokio",
"tower-layer",
"tower-service",
]
[[package]] [[package]]
name = "tower" name = "tower"
version = "0.5.1" version = "0.5.1"
@ -2315,7 +2284,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -2400,9 +2369,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.15" version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
@ -2412,9 +2381,9 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]] [[package]]
name = "unicode-normalization" name = "unicode-normalization"
version = "0.1.23" version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
dependencies = [ dependencies = [
"tinyvec", "tinyvec",
] ]
@ -2444,9 +2413,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.10.0" version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -2496,9 +2465,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.93" version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@ -2507,24 +2476,24 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.93" version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.43" version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@ -2534,9 +2503,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.93" version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -2544,28 +2513,28 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.93" version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.93" version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.70" version = "0.3.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -2737,9 +2706,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.6.18" version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -2762,7 +2731,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -2782,7 +2751,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.85",
] ]
[[package]] [[package]]
@ -2801,7 +2770,7 @@ dependencies = [
"displaydoc", "displaydoc",
"flate2", "flate2",
"hmac", "hmac",
"indexmap 2.5.0", "indexmap 2.6.0",
"lzma-rs", "lzma-rs",
"memchr", "memchr",
"pbkdf2", "pbkdf2",

View file

@ -7,40 +7,40 @@ publish = false
[dependencies] [dependencies]
# Logging # Logging
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "chrono"] } tracing-subscriber = { version = "0.3", features = ["env-filter", "chrono"] }
tracing-appender = "0.2.3" tracing-appender = "0.2"
tracing-panic = "0.1.2" tracing-panic = "0.1"
tracing = "0.1.40" tracing = "0.1"
# Errors handelers # Errors handelers
anyhow = "1.0.83" anyhow = "1.0"
thiserror = "1.0.64" thiserror = "1.0"
chrono = { version = "0.4.38", features = ["now", "serde"] } chrono = { version = "0.4", features = ["now", "serde"] }
serde = { version = "1.0.201", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.117" serde_json = "1.0"
toml = "0.8.19" toml = "0.8"
# Other # Other
dashmap = { version = "6.0.1", features = ["serde"] } dashmap = { version = "6.0", features = ["serde"] }
hex = "0.4.3" hex = "0.4"
uuid = { version = "1.8.0", features = ["serde"] } uuid = { version = "1.11", features = ["serde"] }
base64 = "0.22.1" base64 = "0.22"
reqwest = { version = "0.12.7", features = ["blocking", "json"] } reqwest = { version = "0.12", features = ["blocking", "json"] }
dotenvy = "0.15.7" dotenvy = "0.15"
semver = "1.0.23" semver = "1.0"
walkdir = "2.5.0" walkdir = "2.5"
# Crypto # Crypto
ring = "0.17.8" ring = "0.17"
rand = "0.8.5" rand = "0.8"
# Web framework # Web framework
axum = { version = "0.7.7", features = ["ws", "macros", "http2"] } axum = { version = "0.7", features = ["ws", "macros", "http2"] }
tower-http = { version = "0.6.1", features = ["trace"] } tower-http = { version = "0.6", features = ["trace"] }
tokio = { version = "1.37.0", features = ["full"] } tokio = { version = "1.37", features = ["full"] }
indexmap = { version = "2.5.0", features = ["serde"] } indexmap = { version = "2.6", features = ["serde"] }
zip = "2.2.0" zip = "2.2"
lazy_static = "1.5.0" lazy_static = "1.5"
[dev-dependencies] [dev-dependencies]
cross = "0.2.5" cross = "0.2.5"

View file

@ -1,6 +1,6 @@
## Chef ## Chef
# FROM clux/muslrust:stable AS chef # FROM clux/muslrust:stable AS chef
FROM rust:1.81.0-alpine3.20 AS chef FROM rust:1.82.0-alpine3.20 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

@ -4,6 +4,7 @@
# The Sculptor # The Sculptor
[![Push Dev](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml/badge.svg?branch=dev)](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml) [![Push Dev](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml/badge.svg?branch=dev)](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml)
![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg)
Unofficial backend for the Minecraft mod [Figura](https://github.com/FiguraMC/Figura). Unofficial backend for the Minecraft mod [Figura](https://github.com/FiguraMC/Figura).
@ -19,11 +20,11 @@ I'm keeping the public server running at the moment!
You can use it if running your own Sculptor instance is difficult for you. You can use it if running your own Sculptor instance is difficult for you.
To connect, simply change **IP Server** in Figura settings to the address below: To connect, simply change **Figura Cloud IP** in Figura settings to the address below:
> figura.shsr.ru > figura.shsr.ru
Authentication is enabled on the server via: Mojang and [Ely.By](https://ely.by/) Authentication is enabled on the server via: Mojang(Microsoft) and [Ely.By](https://ely.by/)
For reasons beyond my control, the server is not available in some countries. For reasons beyond my control, the server is not available in some countries.
@ -73,10 +74,15 @@ cargo run --release
``` ```
## Contributing ## Contributing
![Ask me anything!](https://img.shields.io/badge/Ask%20me-anything-1abc9c.svg)
on
[![Telegram](https://badgen.net/static/icon/telegram?icon=telegram&color=cyan&label)](https://t.me/shiroyashik)
or
![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)
If you have ideas for new features, have found a bug, or want to suggest improvements, If you have ideas for new features, have found a bug, or want to suggest improvements,
please create an [issue](https://github.com/shiroyashik/sculptor/issues) please create an [issue](https://github.com/shiroyashik/sculptor/issues)
or contact me directly via Discord/Telegram (@shiroyashik). or contact me directly via Discord/Telegram (**@shiroyashik**).
If you are a Rust developer, you can modify the code yourself and request a Pull Request: If you are a Rust developer, you can modify the code yourself and request a Pull Request:

View file

@ -3,12 +3,13 @@
# The Sculptor # The Sculptor
[![Push Dev](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml/badge.svg?branch=dev)](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml) [![Push Dev](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml/badge.svg?branch=dev)](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml)
![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg)
Неофициальный бэкенд для Minecraft мода [Figura](https://github.com/FiguraMC/Figura). Неофициальный бэкенд для Minecraft мода [Figura](https://github.com/FiguraMC/Figura).
Это полноценная замена официальной версии. Реализован весь функционал который вы можете использовать во время игры. Это полноценная замена официальной версии. Реализован весь функционал который вы можете использовать во время игры.
А также отличительной особенностью является возможность игры с сторонними провайдерерами аутентификации (таких как [Ely.By](https://ely.by/)) А также отличительной особенностью является возможность игры с сторонними провайдерерами аутентификации (такими как [Ely.By](https://ely.by/))
## Публичный сервер ## Публичный сервер
@ -18,13 +19,13 @@
Вы можете использовать его если запуск собственного сервера затруднителен для вас. Вы можете использовать его если запуск собственного сервера затруднителен для вас.
Для подключения достаточно сменить **Сервер IP** в настройках Figura на адрес ниже: Для подключения достаточно сменить **IP сервера Figura** в настройках Figura на адрес ниже:
> figura.shsr.ru > figura.shsr.ru
На сервере включена аутентификация через: Mojang и [Ely.By](https://ely.by/) На сервере включена аутентификация через: Mojang(Microsoft) и [Ely.By](https://ely.by/)
По неконтролируемым мною причинам, сервер не доступен в некоторых странах По неконтролируемым мною причинам, сервер не доступен в некоторых странах.
## Запуск ## Запуск
@ -71,15 +72,20 @@ cargo run --release
``` ```
## Вклад в развитие ## Вклад в развитие
![Спроси меня о чём угодно!](https://img.shields.io/badge/Ask%20me-anything-1abc9c.svg)
в
[![Telegram](https://badgen.net/static/icon/telegram?icon=telegram&color=cyan&label)](https://t.me/shiroyashik)
или
![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)
Если у вас есть идем, нашли баг или хотите предложить улучшения Если у вас есть идем, нашли баг или хотите предложить улучшения
создавайте [issue](https://github.com/shiroyashik/sculptor/issues) создавайте [issue](https://github.com/shiroyashik/sculptor/issues)
или свяжитесь со мной напрямую через Discord/Telegram (@shiroyashik). или свяжитесь со мной напрямую через Discord/Telegram (**@shiroyashik**).
Если вы Rust разработчик, буду рад вашим Pull Request'ам: Если вы Rust разработчик, буду рад вашим Pull Request'ам:
1. Форкните репу 1. Форкните репу
2. Создайте новую репу для вашего гения 2. Создайте новую ветку
3. Создайте PR! 3. Создайте PR!
Буду рад любой вашей помощи! ❤ Буду рад любой вашей помощи! ❤

View file

@ -21,10 +21,10 @@ async fn versions() -> ApiResult<Json<Value>> {
let mut directories = Vec::new(); let mut directories = Vec::new();
let mut entries = fs::read_dir(dir_path).await.map_err(|err| internal_and_log(err))?; let mut entries = fs::read_dir(dir_path).await.map_err(internal_and_log)?;
while let Some(entry) = entries.next_entry().await.map_err(|err| internal_and_log(err))? { while let Some(entry) = entries.next_entry().await.map_err(internal_and_log)? {
if entry.metadata().await.map_err(|err| internal_and_log(err))?.is_dir() { if entry.metadata().await.map_err(internal_and_log)?.is_dir() {
if let Some(name) = entry.file_name().to_str() { if let Some(name) = entry.file_name().to_str() {
let name = name.to_string(); let name = name.to_string();
if !name.starts_with('.') { if !name.starts_with('.') {
@ -38,7 +38,7 @@ async fn versions() -> ApiResult<Json<Value>> {
} }
async fn hashes(Path(version): Path<String>) -> ApiResult<Json<IndexMap<String, Value>>> { async fn hashes(Path(version): Path<String>) -> ApiResult<Json<IndexMap<String, Value>>> {
let map = index_assets(&version).await.map_err(|err| internal_and_log(err))?; let map = index_assets(&version).await.map_err(internal_and_log)?;
Ok(Json(map)) Ok(Json(map))
} }
@ -49,7 +49,7 @@ async fn download(Path((version, path)): Path<(String, String)>) -> ApiResult<Ve
return Err(ApiError::NotFound) return Err(ApiError::NotFound)
}; };
let mut buffer = Vec::new(); let mut buffer = Vec::new();
file.read_to_end(&mut buffer).await.map_err(|err| internal_and_log(err))?; file.read_to_end(&mut buffer).await.map_err(internal_and_log)?;
Ok(buffer) Ok(buffer)
} }
@ -65,13 +65,11 @@ async fn index_assets(version: &str) -> anyhow::Result<IndexMap<String, Value>>
Err(_) => continue Err(_) => continue
}; };
let path: String; let path: String = if cfg!(windows) {
entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string().replace("\\", "/")
if cfg!(windows) {
path = entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string().replace("\\", "/");
} else { } else {
path = entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string(); entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string()
} };
map.insert(path, Value::from(hex::encode(digest(&SHA256, &data).as_ref()))); map.insert(path, Value::from(hex::encode(digest(&SHA256, &data).as_ref())));
} }

View file

@ -5,4 +5,4 @@ pub mod profile;
pub mod info; pub mod info;
pub mod assets; pub mod assets;
pub use websocket::handler as ws; pub use websocket::{initial as ws, SessionMessage};

View file

@ -14,7 +14,7 @@ use crate::{
auth::Token, utils::{calculate_file_sha256, format_uuid}, auth::Token, utils::{calculate_file_sha256, format_uuid},
ApiError, ApiResult, AppState, AVATARS_VAR ApiError, ApiResult, AppState, AVATARS_VAR
}; };
use super::types::S2CMessage; use super::websocket::S2CMessage;
pub async fn user_info( pub async fn user_info(
Path(uuid): Path<Uuid>, Path(uuid): Path<Uuid>,
@ -85,7 +85,7 @@ pub async fn download_avatar(Path(uuid): Path<Uuid>) -> ApiResult<Vec<u8>> {
return Err(ApiError::NotFound) return Err(ApiError::NotFound)
}; };
let mut buffer = Vec::new(); let mut buffer = Vec::new();
file.read_to_end(&mut buffer).await.map_err(|err| internal_and_log(err))?; file.read_to_end(&mut buffer).await.map_err(internal_and_log)?;
Ok(buffer) Ok(buffer)
} }
@ -103,15 +103,15 @@ pub async fn upload_avatar(
user_info.username user_info.username
); );
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, user_info.uuid); let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, user_info.uuid);
let mut file = BufWriter::new(fs::File::create(&avatar_file).await.map_err(|err| internal_and_log(err))?); let mut file = BufWriter::new(fs::File::create(&avatar_file).await.map_err(internal_and_log)?);
io::copy(&mut request_data.as_ref(), &mut file).await.map_err(|err| internal_and_log(err))?; io::copy(&mut request_data.as_ref(), &mut file).await.map_err(internal_and_log)?;
} }
Ok("ok".to_string()) Ok("ok".to_string())
} }
pub async fn equip_avatar(Token(token): Token, State(state): State<AppState>) -> ApiResult<&'static str> { pub async fn equip_avatar(Token(token): Token, State(state): State<AppState>) -> ApiResult<&'static str> {
debug!("[API] S2C : Equip"); debug!("[API] S2C : Equip");
let uuid = state.user_manager.get(&token).ok_or_else(|| ApiError::Unauthorized)?.uuid; let uuid = state.user_manager.get(&token).ok_or(ApiError::Unauthorized)?.uuid;
send_event(&state, &uuid).await; send_event(&state, &uuid).await;
Ok("ok") Ok("ok")
} }
@ -124,7 +124,7 @@ pub async fn delete_avatar(Token(token): Token, State(state): State<AppState>) -
user_info.username user_info.username
); );
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, user_info.uuid); let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, user_info.uuid);
fs::remove_file(avatar_file).await.map_err(|err| internal_and_log(err))?; fs::remove_file(avatar_file).await.map_err(internal_and_log)?;
send_event(&state, &user_info.uuid).await; send_event(&state, &user_info.uuid).await;
} }
Ok("ok".to_string()) Ok("ok".to_string())
@ -132,16 +132,16 @@ pub async fn delete_avatar(Token(token): Token, State(state): State<AppState>) -
pub async fn send_event(state: &AppState, uuid: &Uuid) { pub async fn send_event(state: &AppState, uuid: &Uuid) {
// To user subscribers // To user subscribers
if let Some(broadcast) = state.broadcasts.get(&uuid) { if let Some(broadcast) = state.subscribes.get(uuid) {
if broadcast.send(S2CMessage::Event(*uuid).to_vec()).is_err() { if broadcast.send(S2CMessage::Event(*uuid).into()).is_err() {
debug!("[WebSocket] Failed to send Event! There is no one to send. UUID: {uuid}") debug!("[WebSocket] Failed to send Event! There is no one to send. UUID: {uuid}")
}; };
} else { } else {
debug!("[WebSocket] Failed to send Event! Can't find UUID: {uuid}") debug!("[WebSocket] Failed to send Event! Can't find UUID: {uuid}")
}; };
// To user // To user
if let Some(session) = state.session.get(&uuid) { if let Some(session) = state.session.get(uuid) {
if session.send(S2CMessage::Event(*uuid).to_vec()).await.is_err() { if session.send(super::SessionMessage::Ping(S2CMessage::Event(*uuid).into())).await.is_err() {
debug!("[WebSocket] Failed to send Event! WS doesn't connected? UUID: {uuid}") debug!("[WebSocket] Failed to send Event! WS doesn't connected? UUID: {uuid}")
}; };
} else { } else {

View file

@ -1,8 +1 @@
mod c2s;
mod errors;
mod s2c;
pub mod auth; pub mod auth;
pub use c2s::C2SMessage;
pub use errors::MessageLoadError;
pub use s2c::S2CMessage;

View file

@ -1,234 +0,0 @@
use std::sync::Arc;
use axum::{
extract::{
ws::{Message, WebSocket},
State, WebSocketUpgrade,
},
response::Response,
};
use dashmap::DashMap;
use tracing::{debug, error, info, trace, warn};
use tokio::sync::{
broadcast::{self, Receiver},
mpsc, Notify,
};
use uuid::Uuid;
use crate::AppState;
use super::types::{C2SMessage, S2CMessage};
pub async fn handler(ws: WebSocketUpgrade, State(state): State<AppState>) -> Response {
ws.on_upgrade(|socket| handle_socket(socket, state))
}
#[derive(Debug, Clone)]
struct WSUser {
username: String,
uuid: Uuid,
}
trait ExtWSUser {
fn name(&self) -> String;
}
impl ExtWSUser for Option<WSUser> {
fn name(&self) -> String {
if let Some(user) = self {
format!(" ({})", user.username)
} else {
String::new()
}
}
}
async fn handle_socket(mut socket: WebSocket, state: AppState) {
debug!("[WebSocket] New unknown connection!");
let mut owner: Option<WSUser> = None; // Information about user
let cutoff: DashMap<Uuid, Arc<Notify>> = DashMap::new(); // Отключение подписки
let (mtx, mut mrx) = mpsc::channel(64); // multiple tx and single receive
let mut bctx: Option<broadcast::Sender<Vec<u8>>> = None; // broadcast tx send
loop {
tokio::select! {
// Main loop what receving messages from WebSocket
Some(msg) = socket.recv() => {
trace!("[WebSocket{}] Raw: {msg:?}", owner.name());
let mut msg = if let Ok(msg) = msg {
if let Message::Close(_) = msg {
info!("[WebSocket{}] Connection successfully closed!", owner.name());
break;
}
msg
} else {
debug!("[WebSocket{}] Receive error! Connection terminated!", owner.name());
break;
};
// Checking ban list
if let Some(ref user) = owner {
if state.user_manager.is_banned(&user.uuid) {
warn!("[WebSocket] Detected banned user with active WebSocket! Sending close with Banned code.");
let _ = socket.send(Message::Binary(S2CMessage::Toast(2, "You're banned!", None).to_vec())).await; // option слищком жирный Some("Reason: Lorum Ipsum interсно сколько влезет~~~ 0w0.")
tokio::time::sleep(std::time::Duration::from_secs(6)).await;
debug!("{:?}", socket.send(Message::Close(Some(axum::extract::ws::CloseFrame { code: 4001, reason: "You're banned!".into() }))).await);
continue;
}
}
// Next is the code for processing msg
let msg_vec = msg.clone().into_data();
let msg_array = msg_vec.as_slice();
if msg_array.len() == 0 { tracing::debug!("[WebSocket{}] Deprecated len 0 msg", owner.name()); continue; };
let newmsg = match C2SMessage::try_from(msg_array) {
Ok(data) => data,
Err(e) => {
error!("[WebSocket{}] This message is not from Figura! {}", owner.name(), e.to_string());
debug!("[WebSocket{}] Broken data: {}", owner.name(), hex::encode(msg_vec));
continue;
// break;
},
};
debug!("[WebSocket{}] MSG: {:?}, HEX: {}", owner.name(), newmsg, hex::encode(newmsg.to_vec()));
match newmsg {
C2SMessage::Token(token) => {
trace!("[WebSocket{}] C2S : Token", owner.name());
let token = String::from_utf8(token.to_vec()).unwrap();
match state.user_manager.get(&token) { // The principle is simple: if there is no token in authenticated, then it's "dirty hacker" :D
Some(t) => {
//username = t.username.clone();
owner = Some(WSUser { username: t.username.clone(), uuid: t.uuid });
state.session.insert(t.uuid, mtx.clone());
msg = Message::Binary(S2CMessage::Auth.to_vec());
match state.broadcasts.get(&t.uuid) {
Some(tx) => {
bctx = Some(tx.to_owned());
},
None => {
let (tx, _rx) = broadcast::channel(64);
state.broadcasts.insert(t.uuid, tx.clone());
bctx = Some(tx.to_owned());
},
};
},
None => {
warn!("[WebSocket] Authentication error! Sending close with Re-auth code.");
debug!("[WebSocket] Tried to log in with {token}"); // Tried to log in with token: {token}
debug!("{:?}", socket.send(Message::Close(Some(axum::extract::ws::CloseFrame { code: 4000, reason: "Re-auth".into() }))).await);
continue;
},
};
},
C2SMessage::Ping(_, _, _) => {
trace!("[WebSocket{}] C2S : Ping", owner.name());
let data = into_s2c_ping(msg_vec, owner.clone().unwrap().uuid);
match bctx.clone().unwrap().send(data) {
Ok(_) => (),
Err(_) => debug!("[WebSocket{}] Failed to send Ping! Maybe there's no one to send", owner.name()),
};
continue;
},
// Subscribing
C2SMessage::Sub(uuid) => { // TODO: Eliminate the possibility of using SUB without authentication
trace!("[WebSocket{}] C2S : Sub", owner.name());
// Ignoring self Sub
if uuid == owner.clone().unwrap().uuid {
continue;
};
let rx = match state.broadcasts.get(&uuid) { // Get sender
Some(rx) => rx.to_owned().subscribe(), // Subscribe on sender to get receiver
None => {
warn!("[WebSocket{}] Attention! The required UUID for subscription was not found!", owner.name());
let (tx, rx) = broadcast::channel(64); // Pre creating broadcast for future
state.broadcasts.insert(uuid, tx); // Inserting into dashmap
rx
},
};
let shutdown = Arc::new(Notify::new()); // Creating new shutdown <Notify>
tokio::spawn(subscribe(mtx.clone(), rx, shutdown.clone())); // <For send pings to >
cutoff.insert(uuid, shutdown);
continue;
},
// Unsubscribing
C2SMessage::Unsub(uuid) => {
trace!("[WebSocket{}] C2S : Unsub", owner.name());
// Ignoring self Unsub
if uuid == owner.clone().unwrap().uuid {
continue;
};
let shutdown = cutoff.remove(&uuid).unwrap().1; // Getting <Notify> from list // FIXME: UNWRAP PANIC! NONE VALUE
shutdown.notify_one(); // Shutdown <subscribe> function
continue;
},
}
// Sending message
debug!("[WebSocket{}] Answering: {msg:?}", owner.name());
if socket.send(msg).await.is_err() {
warn!("[WebSocket{}] Send error! Connection terminated!", owner.name());
break;
}
}
msg = mrx.recv() => {
match socket.send(Message::Binary(msg.clone().unwrap())).await {
Ok(_) => {
debug!("[WebSocketSubscribe{}] Answering: {}", owner.name(), hex::encode(msg.unwrap()));
}
Err(_) => {
warn!("[WebSocketSubscriber{}] Send error! Connection terminated!", owner.name());
break;
}
}
}
}
}
// Closing connection
if let Some(u) = owner {
debug!("[WebSocket ({})] Removing session data", u.username);
state.session.remove(&u.uuid); // FIXME: Temporary solution
// state.broadcasts.remove(&u.uuid); // NOTE: Create broadcasts manager ??
state.user_manager.remove(&u.uuid);
} else {
debug!("[WebSocket] Nothing to remove");
}
}
async fn subscribe(
socket: mpsc::Sender<Vec<u8>>,
mut rx: Receiver<Vec<u8>>,
shutdown: Arc<Notify>,
) {
loop {
tokio::select! {
_ = shutdown.notified() => {
debug!("SUB successfully closed!");
return;
}
msg = rx.recv() => {
let msg = msg.ok();
if let Some(msg) = msg {
if socket.send(msg.clone()).await.is_err() {
debug!("Forced shutdown SUB! Client died?");
return;
};
} else {
debug!("Forced shutdown SUB! Source died?");
return;
}
}
}
}
}
fn into_s2c_ping(buf: Vec<u8>, uuid: Uuid) -> Vec<u8> {
use std::iter::once;
once(1)
.chain(uuid.into_bytes().iter().copied())
.chain(buf.as_slice()[1..].iter().copied())
.collect()
}

View file

@ -0,0 +1,212 @@
use anyhow::bail;
use axum::extract::{ws::{Message, WebSocket}, State};
use dashmap::DashMap;
use tokio::sync::{broadcast, mpsc};
use crate::{auth::Userinfo, AppState};
use super::{processor::*, AuthModeError, S2CMessage, C2SMessage, WSSession, SessionMessage, RADError};
pub async fn initial(
ws: axum::extract::WebSocketUpgrade,
State(state): State<AppState>
) -> axum::response::Response {
ws.on_upgrade(|socket| handle_socket(socket, state))
}
async fn handle_socket(mut ws: WebSocket, state: AppState) {
// Trying authenticate & get user data or dropping connection
match authenticate(&mut ws, &state).await {
Ok(user) => {
// Creating session & creating/getting channels
let mut session = {
let sub_workers_aborthandles = DashMap::new();
// Channel for receiving messages from internal functions.
let (own_tx, own_rx) = mpsc::channel(32);
state.session.insert(user.uuid, own_tx.clone());
// Channel for sending messages to subscribers
let subs_tx = match state.subscribes.get(&user.uuid) {
Some(tx) => tx.clone(),
None => {
tracing::debug!("[Subscribes] Can't find own subs channel for {}, creating new...", user.uuid);
let (subs_tx, _) = broadcast::channel(32);
state.subscribes.insert(user.uuid, subs_tx.clone());
subs_tx
},
};
WSSession { user: user.clone(), own_tx, own_rx, subs_tx, sub_workers_aborthandles }
};
// Starting main worker
match main_worker(&mut session, &mut ws, &state).await {
Ok(_) => (),
Err(kind) => tracing::error!("[WebSocket] Main worker halted due to {}.", kind),
}
for (_, handle) in session.sub_workers_aborthandles {
handle.abort();
}
// Removing session data
state.session.remove(&user.uuid);
state.user_manager.remove(&user.uuid);
},
Err(kind) => {
tracing::info!("[WebSocket] Can't authenticate: {}", kind);
}
}
// Closing connection
if let Err(kind) = ws.close().await { tracing::trace!("[WebSocket] Closing fault: {}", kind) }
}
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.username);
loop {
tokio::select! {
external_msg = ws.recv_and_decode() => {
// Getting a value or halt the worker without an error
let external_msg = match external_msg {
Ok(m) => m,
Err(kind) => {
match kind {
RADError::Close(_) => return Ok(()),
RADError::StreamClosed => return Ok(()),
_ => return Err(kind.into())
}
},
};
// Processing message
match external_msg {
C2SMessage::Token(_) => bail!("authentication passed, but the client sent the Token again"),
C2SMessage::Ping(func_id, echo, data) => {
let s2c_ping: Vec<u8> = S2CMessage::Ping(session.user.uuid, func_id, echo, data).into();
// Echo check
if echo {
ws.send(Message::Binary(s2c_ping.clone())).await?
}
// Sending to others
let _ = session.subs_tx.send(s2c_ping);
},
C2SMessage::Sub(uuid) => {
tracing::debug!("[WebSocket] {} subscribes to {}", session.user.username, uuid);
// Doesn't allow to subscribe to yourself
if session.user.uuid != uuid {
// Creates a channel to send pings to a subscriber if it can't find an existing one
let rx = match state.subscribes.get(&uuid) {
Some(tx) => tx.subscribe(),
None => {
let (tx, rx) = broadcast::channel(32);
state.subscribes.insert(uuid, tx);
rx
},
};
let handle = tokio::spawn(sub_worker(session.own_tx.clone(), rx)).abort_handle();
session.sub_workers_aborthandles.insert(uuid, handle);
}
},
C2SMessage::Unsub(uuid) => {
tracing::debug!("[WebSocket] {} unsubscribes from {}", session.user.username, uuid);
match session.sub_workers_aborthandles.get(&uuid) {
Some(handle) => handle.abort(),
None => tracing::warn!("[WebSocket] {} was not subscribed.", session.user.username),
};
},
}
},
internal_msg = session.own_rx.recv() => {
let internal_msg = internal_msg.ok_or(anyhow::anyhow!("Unexpected error! Session channel broken!"))?;
match internal_msg {
SessionMessage::Ping(msg) => {
ws.send(Message::Binary(msg)).await?
},
SessionMessage::Banned => {
let _ = ban_action(ws).await
.inspect_err(
|kind| tracing::warn!("[WebSocket] Didn't get the ban message due to {}", kind)
);
bail!("{} banned!", session.user.username)
},
}
}
}
}
}
async fn sub_worker(tx_main: mpsc::Sender<SessionMessage>, mut rx: broadcast::Receiver<Vec<u8>>) {
loop {
let msg = match rx.recv().await {
Ok(m) => m,
Err(kind) => {
tracing::error!("[Subscribes_Worker] Broadcast error! {}", kind);
return;
},
};
match tx_main.send(SessionMessage::Ping(msg)).await {
Ok(_) => (),
Err(kind) => {
tracing::error!("[Subscribes_Worker] Session error! {}", kind);
return;
},
}
}
}
async fn authenticate(socket: &mut WebSocket, state: &AppState) -> Result<Userinfo, AuthModeError> {
match socket.recv_and_decode().await {
Ok(msg) => {
match msg {
C2SMessage::Token(token) => {
let token = String::from_utf8(token.to_vec()).map_err(|_| AuthModeError::ConvertError)?;
match state.user_manager.get(&token) {
Some(user) => {
if socket.send(Message::Binary(S2CMessage::Auth.into())).await.is_err() {
Err(AuthModeError::SendError)
} else if !user.banned {
Ok(user.clone())
} else {
let _ = ban_action(socket).await
.inspect_err(
|kind| tracing::warn!("[WebSocket] Didn't get the ban message due to {}", kind)
);
Err(AuthModeError::Banned(user.username.clone()))
}
},
None => {
if socket.send(
Message::Close(Some(axum::extract::ws::CloseFrame { code: 4000, reason: "Re-auth".into() }))
).await.is_err() {
Err(AuthModeError::SendError)
} else {
Err(AuthModeError::AuthenticationFailure)
}
},
}
},
_ => {
Err(AuthModeError::UnauthorizedAction)
}
}
},
Err(err) => {
Err(AuthModeError::RecvError(err))
},
}
}
async fn ban_action(ws: &mut WebSocket) -> anyhow::Result<()> {
ws.send(Message::Binary(S2CMessage::Toast(2, "You're banned!".to_string(), None).into())).await?;
tokio::time::sleep(std::time::Duration::from_secs(6)).await;
ws.send(Message::Close(Some(axum::extract::ws::CloseFrame { code: 4001, reason: "You're banned!".into() }))).await?;
Ok(())
}

View file

@ -0,0 +1,8 @@
// mod websocket;
mod handler;
mod processor;
mod types;
// pub use websocket::*;
pub use handler::initial;
pub use types::*;

View file

@ -0,0 +1,32 @@
use axum::extract::ws::{Message, WebSocket};
use super::{C2SMessage, RADError};
pub trait RecvAndDecode {
async fn recv_and_decode(&mut self) -> Result<C2SMessage, RADError>;
}
impl RecvAndDecode for WebSocket {
async fn recv_and_decode(&mut self) -> Result<C2SMessage, RADError> {
if let Some(msg) = self.recv().await {
match msg {
Ok(msg) => {
match msg {
Message::Close(frame) => Err(RADError::Close(frame.map(|f| format!("code: {}, reason: {}", f.code, f.reason)))),
_ => {
match C2SMessage::try_from(msg.clone().into_data().as_slice()) {
Ok(decoded) => Ok(decoded),
Err(e) => {
Err(RADError::DecodeError(e, hex::encode(msg.into_data())))
},
}
}
}
},
Err(e) => Err(RADError::WebSocketError(e)),
}
} else {
Err(RADError::StreamClosed)
}
}
}

View file

@ -5,27 +5,27 @@ use std::convert::{TryFrom, TryInto};
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum C2SMessage<'a> { pub enum C2SMessage {
Token(&'a [u8]) = 0, Token(Vec<u8>) = 0,
Ping(u32, bool, &'a [u8]) = 1, Ping(u32, bool, Vec<u8>) = 1,
Sub(Uuid) = 2, // owo Sub(Uuid) = 2, // owo
Unsub(Uuid) = 3, Unsub(Uuid) = 3,
} }
// 6 - 6 // 6 - 6
impl<'a> TryFrom<&'a [u8]> for C2SMessage<'a> { impl TryFrom<&[u8]> for C2SMessage {
type Error = MessageLoadError; type Error = MessageLoadError;
fn try_from(buf: &'a [u8]) -> Result<Self, <Self as TryFrom<&'a [u8]>>::Error> { fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
if buf.is_empty() { if buf.is_empty() {
Err(MessageLoadError::BadLength("C2SMessage", 1, false, 0)) Err(MessageLoadError::BadLength("C2SMessage", 1, false, 0))
} else { } else {
match buf[0] { match buf[0] {
0 => Ok(C2SMessage::Token(&buf[1..])), 0 => Ok(C2SMessage::Token(buf[1..].to_vec())),
1 => { 1 => {
if buf.len() >= 6 { if buf.len() >= 6 {
Ok(C2SMessage::Ping( Ok(C2SMessage::Ping(
u32::from_be_bytes((&buf[1..5]).try_into().unwrap()), u32::from_be_bytes((&buf[1..5]).try_into().unwrap()),
buf[5] != 0, buf[5] != 0,
&buf[6..], buf[6..].to_vec(),
)) ))
} else { } else {
Err(MessageLoadError::BadLength( Err(MessageLoadError::BadLength(
@ -73,10 +73,10 @@ impl<'a> TryFrom<&'a [u8]> for C2SMessage<'a> {
} }
} }
} }
impl<'a> From<C2SMessage<'a>> for Box<[u8]> { impl From<C2SMessage> for Vec<u8> {
fn from(val: C2SMessage<'a>) -> Self { fn from(val: C2SMessage) -> Self {
use std::iter; use std::iter;
let a: Box<[u8]> = match val { let a: Vec<u8> = match val {
C2SMessage::Token(t) => iter::once(0).chain(t.iter().copied()).collect(), C2SMessage::Token(t) => iter::once(0).chain(t.iter().copied()).collect(),
C2SMessage::Ping(p, s, d) => iter::once(1) C2SMessage::Ping(p, s, d) => iter::once(1)
.chain(p.to_be_bytes()) .chain(p.to_be_bytes())
@ -90,11 +90,11 @@ impl<'a> From<C2SMessage<'a>> for Box<[u8]> {
} }
} }
impl<'a> C2SMessage<'a> { // impl<'a> C2SMessage<'a> {
pub fn to_array(&self) -> Box<[u8]> { // pub fn to_array(&self) -> Box<[u8]> {
<C2SMessage as Into<Box<[u8]>>>::into(self.clone()) // <C2SMessage as Into<Box<[u8]>>>::into(self.clone())
} // }
pub fn to_vec(&self) -> Vec<u8> { // pub fn to_vec(&self) -> Vec<u8> {
self.to_array().to_vec() // self.to_array().to_vec()
} // }
} // }

View file

@ -1,6 +1,8 @@
use std::fmt::*; use std::fmt::*;
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
use thiserror::Error;
#[derive(Debug)] #[derive(Debug)]
pub enum MessageLoadError { pub enum MessageLoadError {
BadEnum(&'static str, RangeInclusive<usize>, usize), BadEnum(&'static str, RangeInclusive<usize>, usize),
@ -23,6 +25,35 @@ impl Display for MessageLoadError {
} }
} }
} }
#[derive(Error, Debug)]
pub enum RADError {
#[error("message decode error due: {0}, invalid data: {1}")]
DecodeError(MessageLoadError, String),
#[error("close, frame: {0:?}")]
Close(Option<String>),
#[error(transparent)]
WebSocketError(#[from] axum::Error),
#[error("stream closed")]
StreamClosed,
}
#[derive(Error, Debug)]
pub enum AuthModeError {
#[error("token recieve error due {0}")]
RecvError(RADError),
#[error("action attempt without authentication")]
UnauthorizedAction,
#[error("convert error, bytes into string")]
ConvertError,
#[error("can't send, websocket broken")]
SendError,
#[error("authentication failure, sending re-auth...")]
AuthenticationFailure,
#[error("{0} banned")]
Banned(String),
}
#[cfg(test)] #[cfg(test)]
#[test] #[test]
fn message_load_error_display() { fn message_load_error_display() {

View file

@ -0,0 +1,9 @@
mod c2s;
mod s2c;
mod errors;
mod session;
pub use session::*;
pub use errors::*;
pub use c2s::*;
pub use s2c::*;

View file

@ -5,17 +5,19 @@ use uuid::Uuid;
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum S2CMessage<'a> { pub enum S2CMessage {
Auth = 0, Auth = 0,
Ping(Uuid, u32, bool, &'a [u8]) = 1, Ping(Uuid, u32, bool, Vec<u8>) = 1,
Event(Uuid) = 2, // Updates avatar for other players Event(Uuid) = 2, // Updates avatar for other players
Toast(u8, &'a str, Option<&'a str>) = 3, Toast(u8, String, Option<String>) = 3,
Chat(&'a str) = 4, Chat(String) = 4,
Notice(u8) = 5, Notice(u8) = 5,
} }
impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> { impl TryFrom<&[u8]> for S2CMessage {
type Error = MessageLoadError; type Error = MessageLoadError;
fn try_from(buf: &'a [u8]) -> Result<Self, <Self as TryFrom<&'a [u8]>>::Error> {
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
if buf.is_empty() { if buf.is_empty() {
Err(MessageLoadError::BadLength("S2CMessage", 1, false, 0)) Err(MessageLoadError::BadLength("S2CMessage", 1, false, 0))
} else { } else {
@ -35,7 +37,7 @@ impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> {
Uuid::from_bytes((&buf[1..17]).try_into().unwrap()), Uuid::from_bytes((&buf[1..17]).try_into().unwrap()),
u32::from_be_bytes((&buf[17..21]).try_into().unwrap()), u32::from_be_bytes((&buf[17..21]).try_into().unwrap()),
buf[21] != 0, buf[21] != 0,
&buf[22..], buf[22..].to_vec(),
)) ))
} else { } else {
Err(BadLength("S2CMessage::Ping", 22, false, buf.len())) Err(BadLength("S2CMessage::Ping", 22, false, buf.len()))
@ -56,12 +58,13 @@ impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> {
} }
} }
} }
impl<'a> From<S2CMessage<'a>> for Box<[u8]> {
fn from(val: S2CMessage<'a>) -> Self { impl From<S2CMessage> for Vec<u8> {
fn from(val: S2CMessage) -> Self {
use std::iter::once; use std::iter::once;
use S2CMessage::*; use S2CMessage::*;
match val { match val {
Auth => Box::new([0]), Auth => vec![0],
Ping(u, i, s, d) => once(1) Ping(u, i, s, d) => once(1)
.chain(u.into_bytes().iter().copied()) .chain(u.into_bytes().iter().copied())
.chain(i.to_be_bytes().iter().copied()) .chain(i.to_be_bytes().iter().copied())
@ -74,20 +77,20 @@ impl<'a> From<S2CMessage<'a>> for Box<[u8]> {
.chain(h.as_bytes().iter().copied()) .chain(h.as_bytes().iter().copied())
.chain( .chain(
d.into_iter() d.into_iter()
.flat_map(|s| once(0).chain(s.as_bytes().iter().copied())), .flat_map(|s| once(0).chain(s.as_bytes().iter().copied()).collect::<Vec<_>>()), // FIXME: Try find other solution
) )
.collect(), .collect(),
Chat(c) => once(4).chain(c.as_bytes().iter().copied()).collect(), Chat(c) => once(4).chain(c.as_bytes().iter().copied()).collect(),
Notice(t) => Box::new([5, t]), Notice(t) => vec![5, t],
} }
} }
} }
impl<'a> S2CMessage<'a> { // impl<'a> S2CMessage<'a> {
pub fn to_array(&self) -> Box<[u8]> { // pub fn to_array(&self) -> Box<[u8]> {
<S2CMessage as Into<Box<[u8]>>>::into(self.clone()) // <S2CMessage as Into<Box<[u8]>>>::into(self.clone())
} // }
pub fn to_vec(&self) -> Vec<u8> { // pub fn to_vec(&self) -> Vec<u8> {
self.to_array().to_vec() // self.to_array().to_vec()
} // }
} // }

View file

@ -0,0 +1,15 @@
use dashmap::DashMap;
use tokio::{sync::{broadcast, mpsc}, task::AbortHandle};
pub struct WSSession {
pub user: crate::auth::Userinfo,
pub own_tx: mpsc::Sender<SessionMessage>,
pub own_rx: mpsc::Receiver<SessionMessage>,
pub subs_tx: broadcast::Sender<Vec<u8>>,
pub sub_workers_aborthandles: DashMap<uuid::Uuid, AbortHandle>,
}
pub enum SessionMessage {
Ping(Vec<u8>),
Banned,
}

View file

@ -28,7 +28,7 @@ pub(super) async fn raw(
Some(uuid) => { Some(uuid) => {
// for only one // for only one
let tx = state.session.get(&uuid).ok_or_else(|| { warn!("unknown uuid"); crate::ApiError::NotFound })?; let tx = state.session.get(&uuid).ok_or_else(|| { warn!("unknown uuid"); crate::ApiError::NotFound })?;
tx.value().send(payload).await.map_err(|err| internal_and_log(err))?; tx.value().send(crate::api::figura::SessionMessage::Ping(payload)).await.map_err(internal_and_log)?;
Ok("ok") Ok("ok")
}, },
None => { None => {
@ -53,8 +53,8 @@ pub(super) async fn sub_raw(
match query.uuid { match query.uuid {
Some(uuid) => { Some(uuid) => {
// for only one // for only one
let tx = state.broadcasts.get(&uuid).ok_or_else(|| { warn!("unknown uuid"); crate::ApiError::NotFound })?; let tx = state.subscribes.get(&uuid).ok_or_else(|| { warn!("unknown uuid"); crate::ApiError::NotFound })?;
tx.value().send(payload).map_err(|err| internal_and_log(err))?; tx.value().send(payload).map_err(internal_and_log)?;
Ok("ok") Ok("ok")
}, },
None => { None => {

View file

@ -29,7 +29,8 @@ pub(super) async fn ban(
info!("Trying ban user: {uuid}"); info!("Trying ban user: {uuid}");
state.user_manager.ban(&Userinfo { uuid: uuid, banned: true, ..Default::default() }); if let Some(tx) = state.session.get(&uuid) {let _ = tx.send(crate::api::figura::SessionMessage::Banned).await;}
state.user_manager.ban(&Userinfo { uuid, banned: true, ..Default::default() });
Ok("ok") Ok("ok")
} }

View file

@ -83,8 +83,8 @@ async fn fetch_json(
trace!("{res:?}"); trace!("{res:?}");
match res.status().as_u16() { match res.status().as_u16() {
200 => { 200 => {
let json = serde_json::from_str::<serde_json::Value>(&res.text().await?).with_context(|| format!("Cant deserialize"))?; let json = serde_json::from_str::<serde_json::Value>(&res.text().await?).with_context(|| "Cant deserialize".to_string())?;
let uuid = get_id_json(&json).with_context(|| format!("Cant get UUID"))?; let uuid = get_id_json(&json).with_context(|| "Cant get UUID".to_string())?;
Ok((uuid, auth_provider.clone())) Ok((uuid, auth_provider.clone()))
} }
_ => Err(FetchError::WrongResponse(res.status().as_u16(), res.text().await)), _ => Err(FetchError::WrongResponse(res.status().as_u16(), res.text().await)),
@ -131,7 +131,7 @@ pub async fn has_joined(
// Choosing what error return // Choosing what error return
// Returns if some internals errors occured // Returns if some internals errors occured
if errors.len() != 0 { if !errors.is_empty() {
error!("Something wrong with your authentification providers!\nMisses: {misses:?}\nErrors: {errors:?}"); error!("Something wrong with your authentification providers!\nMisses: {misses:?}\nErrors: {errors:?}");
Err(anyhow::anyhow!("{:?}", errors)) Err(anyhow::anyhow!("{:?}", errors))
@ -203,7 +203,7 @@ impl UManager {
pub fn insert_user(&self, uuid: Uuid, userinfo: Userinfo) { pub fn insert_user(&self, uuid: Uuid, userinfo: Userinfo) {
// self.registered.insert(uuid, userinfo) // self.registered.insert(uuid, userinfo)
let usercopy = userinfo.clone(); let usercopy = userinfo.clone();
self.registered.entry(uuid.clone()) self.registered.entry(uuid)
.and_modify(|exist| { .and_modify(|exist| {
if !userinfo.username.is_empty() { exist.username = userinfo.username }; if !userinfo.username.is_empty() { exist.username = userinfo.username };
if !userinfo.auth_provider.is_empty() { exist.auth_provider = userinfo.auth_provider }; if !userinfo.auth_provider.is_empty() { exist.auth_provider = userinfo.auth_provider };

View file

@ -51,11 +51,7 @@ impl Default for AuthProvider {
impl AuthProvider { impl AuthProvider {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
if self.name == "Unknown".to_string() { self.name == "Unknown"
true
} else {
false
}
} }
} }

View file

@ -1,22 +1,22 @@
// Environment // Environment
pub const LOGGER_ENV: &'static str = "RUST_LOG"; pub const LOGGER_ENV: &str = "RUST_LOG";
pub const CONFIG_ENV: &'static str = "RUST_CONFIG"; pub const CONFIG_ENV: &str = "RUST_CONFIG";
pub const LOGS_ENV: &'static str = "LOGS_FOLDER"; pub const LOGS_ENV: &str = "LOGS_FOLDER";
pub const ASSETS_ENV: &'static str = "ASSETS_FOLDER"; pub const ASSETS_ENV: &str = "ASSETS_FOLDER";
pub const AVATARS_ENV: &'static str = "AVATARS_FOLDER"; pub const AVATARS_ENV: &str = "AVATARS_FOLDER";
// Instance info // Instance info
pub const SCULPTOR_VERSION: &'static str = env!("CARGO_PKG_VERSION"); pub const SCULPTOR_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const REPOSITORY: &'static str = "shiroyashik/sculptor"; pub const REPOSITORY: &str = "shiroyashik/sculptor";
// reqwest parameters // reqwest parameters
pub const USER_AGENT: &'static str = "reqwest"; pub const USER_AGENT: &str = "reqwest";
pub const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); pub const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
// Figura update checker // Figura update checker
pub const FIGURA_RELEASES_URL: &'static str = "https://api.github.com/repos/figuramc/figura/releases"; pub const FIGURA_RELEASES_URL: &str = "https://api.github.com/repos/figuramc/figura/releases";
pub const FIGURA_DEFAULT_VERSION: &'static str = "0.1.4"; pub const FIGURA_DEFAULT_VERSION: &str = "0.1.4";
// Figura Assets // Figura Assets
pub const FIGURA_ASSETS_ZIP_URL: &'static str = "https://github.com/FiguraMC/Assets/archive/refs/heads/main.zip"; pub const FIGURA_ASSETS_ZIP_URL: &str = "https://github.com/FiguraMC/Assets/archive/refs/heads/main.zip";
pub const FIGURA_ASSETS_COMMIT_URL: &'static str = "https://api.github.com/repos/FiguraMC/Assets/commits/main"; pub const FIGURA_ASSETS_COMMIT_URL: &str = "https://api.github.com/repos/FiguraMC/Assets/commits/main";

View file

@ -1,3 +1,4 @@
#![allow(clippy::module_inception)]
use anyhow::Result; use anyhow::Result;
use axum::{ use axum::{
extract::DefaultBodyLimit, routing::{delete, get, post, put}, Router extract::DefaultBodyLimit, routing::{delete, get, post, put}, Router
@ -6,9 +7,8 @@ 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::{path::PathBuf, sync::Arc, env::var};
use tokio::{fs, sync::{broadcast, mpsc, RwLock}, time::Instant}; use tokio::{fs, sync::RwLock, time::Instant};
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
use uuid::Uuid;
use lazy_static::lazy_static; use lazy_static::lazy_static;
// Consts // Consts
@ -31,28 +31,12 @@ use auth::{UManager, check_auth};
// Config // Config
mod state; mod state;
use state::Config; use state::{Config, AppState};
// Utils // Utils
mod utils; mod utils;
use utils::*; use utils::*;
#[derive(Debug, Clone)]
pub struct AppState {
/// Uptime
uptime: Instant,
/// User manager
user_manager: Arc<UManager>,
/// Send into WebSocket
session: Arc<DashMap<Uuid, mpsc::Sender<Vec<u8>>>>,
/// Ping broadcasts for WebSocket connections
broadcasts: Arc<DashMap<Uuid, broadcast::Sender<Vec<u8>>>>,
/// Current configuration
config: Arc<RwLock<state::Config>>,
/// Caching Figura Versions
figura_versions: Arc<RwLock<Option<FiguraVersions>>>,
}
lazy_static! { lazy_static! {
pub static ref LOGGER_VAR: String = { pub static ref LOGGER_VAR: String = {
var(LOGGER_ENV).unwrap_or(String::from("info")) var(LOGGER_ENV).unwrap_or(String::from("info"))
@ -77,7 +61,7 @@ async fn main() -> Result<()> {
let _ = dotenvy::dotenv(); let _ = dotenvy::dotenv();
// 2. Set up logging // 2. Set up logging
let file_appender = tracing_appender::rolling::never(&*LOGS_VAR, get_log_file(&*LOGS_VAR)); let file_appender = tracing_appender::rolling::never(&*LOGS_VAR, get_log_file(&LOGS_VAR));
let timer = ChronoLocal::new(String::from("%Y-%m-%dT%H:%M:%S%.3f%:z")); let timer = ChronoLocal::new(String::from("%Y-%m-%dT%H:%M:%S%.3f%:z"));
let file_layer = fmt::layer() let file_layer = fmt::layer()
@ -147,7 +131,7 @@ async fn app() -> Result<bool> {
// Config // Config
let config = Arc::new(RwLock::new(Config::parse(CONFIG_VAR.clone().into()))); let config = Arc::new(RwLock::new(Config::parse(CONFIG_VAR.clone().into())));
let listen = config.read().await.listen.clone(); let listen = config.read().await.listen.clone();
let limit = get_limit_as_bytes(config.read().await.limitations.max_avatar_size.clone() as usize); let limit = get_limit_as_bytes(config.read().await.limitations.max_avatar_size as usize);
if config.read().await.assets_updater_enabled { if config.read().await.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.
@ -179,15 +163,17 @@ async fn app() -> Result<bool> {
uptime: Instant::now(), uptime: Instant::now(),
user_manager: Arc::new(UManager::new()), user_manager: Arc::new(UManager::new()),
session: Arc::new(DashMap::new()), session: Arc::new(DashMap::new()),
broadcasts: 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,
}; };
// FIXME: FIXME: FIXME: ПЕРЕДЕЛАЙ ЭТО! НЕМЕДЛЕННО! ЕБУЧИЙ ПОЗОР :<
// Automatic update of configuration while the server is running // Automatic update of configuration while the server is running
let config_update = Arc::clone(&state.config); let config_update = Arc::clone(&state.config);
let user_manager = Arc::clone(&state.user_manager); let umanager = Arc::clone(&state.user_manager);
update_advanced_users(&config_update.read().await.advanced_users.clone(), &user_manager); let session = Arc::clone(&state.session);
update_advanced_users(&config_update.read().await.advanced_users.clone(), &umanager, &session).await;
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
tokio::time::sleep(std::time::Duration::from_secs(10)).await; tokio::time::sleep(std::time::Duration::from_secs(10)).await;
@ -197,14 +183,15 @@ async fn app() -> Result<bool> {
if new_config != *config { if new_config != *config {
tracing::info!("Server configuration modification detected!"); tracing::info!("Server configuration modification detected!");
*config = new_config; *config = new_config;
update_advanced_users(&config.advanced_users.clone(), &user_manager); update_advanced_users(&config.advanced_users.clone(), &umanager, &session).await;
} }
} }
}); });
if state.config.read().await.mc_folder.exists() { if state.config.read().await.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),
Arc::clone(&state.session)
)); ));
} }

View file

@ -62,11 +62,11 @@ pub struct BannedPlayer {
pub name: String, pub name: String,
} }
impl Into<Userinfo> for BannedPlayer { impl From<BannedPlayer> for Userinfo {
fn into(self) -> Userinfo { fn from(val: BannedPlayer) -> Self {
Userinfo { Userinfo {
uuid: self.uuid, uuid: val.uuid,
username: self.name, username: val.name,
banned: true, banned: true,
..Default::default() ..Default::default()
} }

View file

@ -2,3 +2,4 @@ mod config;
mod state; mod state;
pub use config::*; pub use config::*;
pub use state::*;

View file

@ -0,0 +1,23 @@
use std::sync::Arc;
use dashmap::DashMap;
use tokio::{sync::*, time::Instant};
use uuid::Uuid;
use crate::{api::figura::SessionMessage, auth::UManager, FiguraVersions};
#[derive(Debug, Clone)]
pub struct AppState {
/// Uptime
pub uptime: Instant,
/// User manager
pub user_manager: Arc<UManager>,
/// Send into WebSocket
pub session: Arc<DashMap<Uuid, mpsc::Sender<SessionMessage>>>,
/// Send messages for subscribers
pub subscribes: Arc<DashMap<Uuid, broadcast::Sender<Vec<u8>>>>,
/// Current configuration
pub config: Arc<RwLock<super::Config>>,
/// Caching Figura Versions
pub figura_versions: Arc<RwLock<Option<FiguraVersions>>>,
}

View file

@ -30,14 +30,18 @@ pub fn _generate_hex_string(length: usize) -> String {
hex::encode(random_bytes) hex::encode(random_bytes)
} }
pub fn update_advanced_users(value: &std::collections::HashMap<Uuid, AdvancedUsers>, umanager: &UManager) { pub async fn update_advanced_users(
value: &std::collections::HashMap<Uuid, AdvancedUsers>,
umanager: &UManager,
sessions: &dashmap::DashMap<Uuid, tokio::sync::mpsc::Sender<crate::api::figura::SessionMessage>>
) {
let users: Vec<(Uuid, Userinfo)> = value let users: Vec<(Uuid, Userinfo)> = value
.iter() .iter()
.map( |(uuid, userdata)| { .map( |(uuid, userdata)| {
( (
uuid.clone(), *uuid,
Userinfo { Userinfo {
uuid: uuid.clone(), uuid: *uuid,
username: userdata.username.clone(), username: userdata.username.clone(),
banned: userdata.banned, banned: userdata.banned,
..Default::default() ..Default::default()
@ -48,12 +52,17 @@ pub fn update_advanced_users(value: &std::collections::HashMap<Uuid, AdvancedUse
for (uuid, userinfo) in users { for (uuid, userinfo) in users {
umanager.insert_user(uuid, userinfo.clone()); umanager.insert_user(uuid, userinfo.clone());
if userinfo.banned { if userinfo.banned {
umanager.ban(&userinfo) umanager.ban(&userinfo);
if let Some(tx) = sessions.get(&uuid) {let _ = tx.send(crate::api::figura::SessionMessage::Banned).await;}
} }
} }
} }
pub async fn update_bans_from_minecraft(folder: PathBuf, umanager: std::sync::Arc<UManager>) { pub async fn update_bans_from_minecraft(
folder: PathBuf,
umanager: std::sync::Arc<UManager>,
sessions: std::sync::Arc<dashmap::DashMap<Uuid, tokio::sync::mpsc::Sender<crate::api::figura::SessionMessage>>>
) {
let path = folder.join("banned-players.json"); let path = folder.join("banned-players.json");
let mut file = tokio::fs::File::open(path.clone()).await.expect("Access denied or banned-players.json doesn't exists!"); let mut file = tokio::fs::File::open(path.clone()).await.expect("Access denied or banned-players.json doesn't exists!");
let mut data = String::new(); let mut data = String::new();
@ -70,6 +79,7 @@ pub async fn update_bans_from_minecraft(folder: PathBuf, umanager: std::sync::Ar
for player in &old_bans { for player in &old_bans {
umanager.ban(&player.clone().into()); umanager.ban(&player.clone().into());
if let Some(tx) = sessions.get(&player.uuid) {let _ = tx.send(crate::api::figura::SessionMessage::Banned).await;}
} }
// old_bans // old_bans
@ -97,6 +107,7 @@ pub async fn update_bans_from_minecraft(folder: PathBuf, umanager: std::sync::Ar
if !ban.is_empty() { if !ban.is_empty() {
for player in ban { for player in ban {
umanager.ban(&player.clone().into()); umanager.ban(&player.clone().into());
if let Some(tx) = sessions.get(&player.uuid) {let _ = tx.send(crate::api::figura::SessionMessage::Banned).await;}
} }
} else { ban_names = String::from("-")}; } else { ban_names = String::from("-")};
info!("List of changes:\n Banned: {ban_names}\n Unbanned: {unban_names}"); info!("List of changes:\n Banned: {ban_names}\n Unbanned: {unban_names}");

View file

@ -65,12 +65,10 @@ pub async fn get_figura_versions() -> anyhow::Result<FiguraVersions> {
if tag_ver > prerelease_ver { if tag_ver > prerelease_ver {
prerelease_ver = tag_ver prerelease_ver = tag_ver
} }
} else { } else if tag_ver > release_ver {
if tag_ver > release_ver {
release_ver = tag_ver release_ver = tag_ver
} }
} }
}
if release_ver > prerelease_ver { if release_ver > prerelease_ver {
prerelease_ver = release_ver.clone(); prerelease_ver = release_ver.clone();
} }
@ -115,14 +113,12 @@ pub async fn is_assets_outdated(last_sha: &str) -> anyhow::Result<bool> {
if contents.lines().count() != 1 { if contents.lines().count() != 1 {
// Lines count in file abnormal // Lines count in file abnormal
Ok(true) Ok(true)
} else { } else if contents == last_sha {
if contents == last_sha {
Ok(false) Ok(false)
} else { } else {
// SHA in file mismatches with provided SHA // SHA in file mismatches with provided SHA
Ok(true) Ok(true)
} }
}
}, },
Err(err) => if err.kind() == tokio::io::ErrorKind::NotFound { Err(err) => if err.kind() == tokio::io::ErrorKind::NotFound {
// Can't find file // Can't find file

View file

@ -1,7 +1,7 @@
mod utils; mod auxiliary;
mod check_updates; mod check_updates;
mod motd; mod motd;
pub use utils::*; pub use auxiliary::*;
pub use motd::*; pub use motd::*;
pub use check_updates::*; pub use check_updates::*;