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

|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -73,10 +74,15 @@ cargo run --release
|
|||
```
|
||||
|
||||
## Contributing
|
||||

|
||||
on
|
||||
[](https://t.me/shiroyashik)
|
||||
or
|
||||

|
||||
|
||||
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)
|
||||
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:
|
||||
|
||||
|
|
|
|||
18
README.ru.md
18
README.ru.md
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
# The Sculptor
|
||||
[](https://github.com/shiroyashik/sculptor/actions/workflows/dev-release.yml)
|
||||

|
||||
|
||||
Неофициальный бэкенд для 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
|
||||
|
||||
На сервере включена аутентификация через: Mojang и [Ely.By](https://ely.by/)
|
||||
На сервере включена аутентификация через: Mojang(Microsoft) и [Ely.By](https://ely.by/)
|
||||
|
||||
По неконтролируемым мною причинам, сервер не доступен в некоторых странах
|
||||
По неконтролируемым мною причинам, сервер не доступен в некоторых странах.
|
||||
|
||||
## Запуск
|
||||
|
||||
|
|
@ -71,15 +72,20 @@ cargo run --release
|
|||
```
|
||||
|
||||
## Вклад в развитие
|
||||

|
||||
в
|
||||
[](https://t.me/shiroyashik)
|
||||
или
|
||||

|
||||
|
||||
Если у вас есть идем, нашли баг или хотите предложить улучшения
|
||||
создавайте [issue](https://github.com/shiroyashik/sculptor/issues)
|
||||
или свяжитесь со мной напрямую через Discord/Telegram (@shiroyashik).
|
||||
или свяжитесь со мной напрямую через Discord/Telegram (**@shiroyashik**).
|
||||
|
||||
Если вы Rust разработчик, буду рад вашим Pull Request'ам:
|
||||
|
||||
1. Форкните репу
|
||||
2. Создайте новую репу для вашего гения
|
||||
2. Создайте новую ветку
|
||||
3. Создайте PR!
|
||||
|
||||
Буду рад любой вашей помощи! ❤
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ async fn versions() -> ApiResult<Json<Value>> {
|
|||
|
||||
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))? {
|
||||
if entry.metadata().await.map_err(|err| internal_and_log(err))?.is_dir() {
|
||||
while let Some(entry) = entries.next_entry().await.map_err(internal_and_log)? {
|
||||
if entry.metadata().await.map_err(internal_and_log)?.is_dir() {
|
||||
if let Some(name) = entry.file_name().to_str() {
|
||||
let name = name.to_string();
|
||||
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>>> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ async fn download(Path((version, path)): Path<(String, String)>) -> ApiResult<Ve
|
|||
return Err(ApiError::NotFound)
|
||||
};
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -65,13 +65,11 @@ async fn index_assets(version: &str) -> anyhow::Result<IndexMap<String, Value>>
|
|||
Err(_) => continue
|
||||
};
|
||||
|
||||
let path: String;
|
||||
|
||||
if cfg!(windows) {
|
||||
path = entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string().replace("\\", "/");
|
||||
let path: String = if cfg!(windows) {
|
||||
entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string().replace("\\", "/")
|
||||
} 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())));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ pub mod profile;
|
|||
pub mod info;
|
||||
pub mod assets;
|
||||
|
||||
pub use websocket::handler as ws;
|
||||
pub use websocket::{initial as ws, SessionMessage};
|
||||
|
|
@ -14,7 +14,7 @@ use crate::{
|
|||
auth::Token, utils::{calculate_file_sha256, format_uuid},
|
||||
ApiError, ApiResult, AppState, AVATARS_VAR
|
||||
};
|
||||
use super::types::S2CMessage;
|
||||
use super::websocket::S2CMessage;
|
||||
|
||||
pub async fn user_info(
|
||||
Path(uuid): Path<Uuid>,
|
||||
|
|
@ -85,7 +85,7 @@ pub async fn download_avatar(Path(uuid): Path<Uuid>) -> ApiResult<Vec<u8>> {
|
|||
return Err(ApiError::NotFound)
|
||||
};
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -103,15 +103,15 @@ pub async fn upload_avatar(
|
|||
user_info.username
|
||||
);
|
||||
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))?);
|
||||
io::copy(&mut request_data.as_ref(), &mut 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(internal_and_log)?;
|
||||
}
|
||||
Ok("ok".to_string())
|
||||
}
|
||||
|
||||
pub async fn equip_avatar(Token(token): Token, State(state): State<AppState>) -> ApiResult<&'static str> {
|
||||
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;
|
||||
Ok("ok")
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ pub async fn delete_avatar(Token(token): Token, State(state): State<AppState>) -
|
|||
user_info.username
|
||||
);
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
// To user subscribers
|
||||
if let Some(broadcast) = state.broadcasts.get(&uuid) {
|
||||
if broadcast.send(S2CMessage::Event(*uuid).to_vec()).is_err() {
|
||||
if let Some(broadcast) = state.subscribes.get(uuid) {
|
||||
if broadcast.send(S2CMessage::Event(*uuid).into()).is_err() {
|
||||
debug!("[WebSocket] Failed to send Event! There is no one to send. UUID: {uuid}")
|
||||
};
|
||||
} else {
|
||||
debug!("[WebSocket] Failed to send Event! Can't find UUID: {uuid}")
|
||||
};
|
||||
// To user
|
||||
if let Some(session) = state.session.get(&uuid) {
|
||||
if session.send(S2CMessage::Event(*uuid).to_vec()).await.is_err() {
|
||||
if let Some(session) = state.session.get(uuid) {
|
||||
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}")
|
||||
};
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,8 +1 @@
|
|||
mod c2s;
|
||||
mod errors;
|
||||
mod s2c;
|
||||
pub mod auth;
|
||||
|
||||
pub use c2s::C2SMessage;
|
||||
pub use errors::MessageLoadError;
|
||||
pub use s2c::S2CMessage;
|
||||
|
|
@ -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()
|
||||
}
|
||||
212
src/api/figura/websocket/handler.rs
Normal file
212
src/api/figura/websocket/handler.rs
Normal 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(())
|
||||
}
|
||||
8
src/api/figura/websocket/mod.rs
Normal file
8
src/api/figura/websocket/mod.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// mod websocket;
|
||||
mod handler;
|
||||
mod processor;
|
||||
mod types;
|
||||
|
||||
// pub use websocket::*;
|
||||
pub use handler::initial;
|
||||
pub use types::*;
|
||||
32
src/api/figura/websocket/processor.rs
Normal file
32
src/api/figura/websocket/processor.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,27 +5,27 @@ use std::convert::{TryFrom, TryInto};
|
|||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum C2SMessage<'a> {
|
||||
Token(&'a [u8]) = 0,
|
||||
Ping(u32, bool, &'a [u8]) = 1,
|
||||
pub enum C2SMessage {
|
||||
Token(Vec<u8>) = 0,
|
||||
Ping(u32, bool, Vec<u8>) = 1,
|
||||
Sub(Uuid) = 2, // owo
|
||||
Unsub(Uuid) = 3,
|
||||
}
|
||||
// 6 - 6
|
||||
impl<'a> TryFrom<&'a [u8]> for C2SMessage<'a> {
|
||||
impl TryFrom<&[u8]> for C2SMessage {
|
||||
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() {
|
||||
Err(MessageLoadError::BadLength("C2SMessage", 1, false, 0))
|
||||
} else {
|
||||
match buf[0] {
|
||||
0 => Ok(C2SMessage::Token(&buf[1..])),
|
||||
0 => Ok(C2SMessage::Token(buf[1..].to_vec())),
|
||||
1 => {
|
||||
if buf.len() >= 6 {
|
||||
Ok(C2SMessage::Ping(
|
||||
u32::from_be_bytes((&buf[1..5]).try_into().unwrap()),
|
||||
buf[5] != 0,
|
||||
&buf[6..],
|
||||
buf[6..].to_vec(),
|
||||
))
|
||||
} else {
|
||||
Err(MessageLoadError::BadLength(
|
||||
|
|
@ -73,10 +73,10 @@ impl<'a> TryFrom<&'a [u8]> for C2SMessage<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl<'a> From<C2SMessage<'a>> for Box<[u8]> {
|
||||
fn from(val: C2SMessage<'a>) -> Self {
|
||||
impl From<C2SMessage> for Vec<u8> {
|
||||
fn from(val: C2SMessage) -> Self {
|
||||
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::Ping(p, s, d) => iter::once(1)
|
||||
.chain(p.to_be_bytes())
|
||||
|
|
@ -90,11 +90,11 @@ impl<'a> From<C2SMessage<'a>> for Box<[u8]> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> C2SMessage<'a> {
|
||||
pub fn to_array(&self) -> Box<[u8]> {
|
||||
<C2SMessage as Into<Box<[u8]>>>::into(self.clone())
|
||||
}
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
self.to_array().to_vec()
|
||||
}
|
||||
}
|
||||
// impl<'a> C2SMessage<'a> {
|
||||
// pub fn to_array(&self) -> Box<[u8]> {
|
||||
// <C2SMessage as Into<Box<[u8]>>>::into(self.clone())
|
||||
// }
|
||||
// pub fn to_vec(&self) -> Vec<u8> {
|
||||
// self.to_array().to_vec()
|
||||
// }
|
||||
// }
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
use std::fmt::*;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MessageLoadError {
|
||||
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)]
|
||||
#[test]
|
||||
fn message_load_error_display() {
|
||||
9
src/api/figura/websocket/types/mod.rs
Normal file
9
src/api/figura/websocket/types/mod.rs
Normal 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::*;
|
||||
|
|
@ -5,17 +5,19 @@ use uuid::Uuid;
|
|||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum S2CMessage<'a> {
|
||||
pub enum S2CMessage {
|
||||
Auth = 0,
|
||||
Ping(Uuid, u32, bool, &'a [u8]) = 1,
|
||||
Ping(Uuid, u32, bool, Vec<u8>) = 1,
|
||||
Event(Uuid) = 2, // Updates avatar for other players
|
||||
Toast(u8, &'a str, Option<&'a str>) = 3,
|
||||
Chat(&'a str) = 4,
|
||||
Toast(u8, String, Option<String>) = 3,
|
||||
Chat(String) = 4,
|
||||
Notice(u8) = 5,
|
||||
}
|
||||
impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> {
|
||||
impl TryFrom<&[u8]> for S2CMessage {
|
||||
|
||||
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() {
|
||||
Err(MessageLoadError::BadLength("S2CMessage", 1, false, 0))
|
||||
} else {
|
||||
|
|
@ -35,7 +37,7 @@ impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> {
|
|||
Uuid::from_bytes((&buf[1..17]).try_into().unwrap()),
|
||||
u32::from_be_bytes((&buf[17..21]).try_into().unwrap()),
|
||||
buf[21] != 0,
|
||||
&buf[22..],
|
||||
buf[22..].to_vec(),
|
||||
))
|
||||
} else {
|
||||
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 S2CMessage::*;
|
||||
match val {
|
||||
Auth => Box::new([0]),
|
||||
Auth => vec![0],
|
||||
Ping(u, i, s, d) => once(1)
|
||||
.chain(u.into_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(
|
||||
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(),
|
||||
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> {
|
||||
pub fn to_array(&self) -> Box<[u8]> {
|
||||
<S2CMessage as Into<Box<[u8]>>>::into(self.clone())
|
||||
}
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
self.to_array().to_vec()
|
||||
}
|
||||
}
|
||||
// impl<'a> S2CMessage<'a> {
|
||||
// pub fn to_array(&self) -> Box<[u8]> {
|
||||
// <S2CMessage as Into<Box<[u8]>>>::into(self.clone())
|
||||
// }
|
||||
// pub fn to_vec(&self) -> Vec<u8> {
|
||||
// self.to_array().to_vec()
|
||||
// }
|
||||
// }
|
||||
15
src/api/figura/websocket/types/session.rs
Normal file
15
src/api/figura/websocket/types/session.rs
Normal 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,
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ pub(super) async fn raw(
|
|||
Some(uuid) => {
|
||||
// for only one
|
||||
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")
|
||||
},
|
||||
None => {
|
||||
|
|
@ -53,8 +53,8 @@ pub(super) async fn sub_raw(
|
|||
match query.uuid {
|
||||
Some(uuid) => {
|
||||
// for only one
|
||||
let tx = state.broadcasts.get(&uuid).ok_or_else(|| { warn!("unknown uuid"); crate::ApiError::NotFound })?;
|
||||
tx.value().send(payload).map_err(|err| internal_and_log(err))?;
|
||||
let tx = state.subscribes.get(&uuid).ok_or_else(|| { warn!("unknown uuid"); crate::ApiError::NotFound })?;
|
||||
tx.value().send(payload).map_err(internal_and_log)?;
|
||||
Ok("ok")
|
||||
},
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ pub(super) async fn ban(
|
|||
|
||||
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")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@ async fn fetch_json(
|
|||
trace!("{res:?}");
|
||||
match res.status().as_u16() {
|
||||
200 => {
|
||||
let json = serde_json::from_str::<serde_json::Value>(&res.text().await?).with_context(|| format!("Cant deserialize"))?;
|
||||
let uuid = get_id_json(&json).with_context(|| format!("Cant get UUID"))?;
|
||||
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(|| "Cant get UUID".to_string())?;
|
||||
Ok((uuid, auth_provider.clone()))
|
||||
}
|
||||
_ => Err(FetchError::WrongResponse(res.status().as_u16(), res.text().await)),
|
||||
|
|
@ -131,7 +131,7 @@ pub async fn has_joined(
|
|||
// Choosing what error return
|
||||
|
||||
// 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:?}");
|
||||
Err(anyhow::anyhow!("{:?}", errors))
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ impl UManager {
|
|||
pub fn insert_user(&self, uuid: Uuid, userinfo: Userinfo) {
|
||||
// self.registered.insert(uuid, userinfo)
|
||||
let usercopy = userinfo.clone();
|
||||
self.registered.entry(uuid.clone())
|
||||
self.registered.entry(uuid)
|
||||
.and_modify(|exist| {
|
||||
if !userinfo.username.is_empty() { exist.username = userinfo.username };
|
||||
if !userinfo.auth_provider.is_empty() { exist.auth_provider = userinfo.auth_provider };
|
||||
|
|
|
|||
|
|
@ -51,11 +51,7 @@ impl Default for AuthProvider {
|
|||
|
||||
impl AuthProvider {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
if self.name == "Unknown".to_string() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.name == "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
// Environment
|
||||
pub const LOGGER_ENV: &'static str = "RUST_LOG";
|
||||
pub const CONFIG_ENV: &'static str = "RUST_CONFIG";
|
||||
pub const LOGS_ENV: &'static str = "LOGS_FOLDER";
|
||||
pub const ASSETS_ENV: &'static str = "ASSETS_FOLDER";
|
||||
pub const AVATARS_ENV: &'static str = "AVATARS_FOLDER";
|
||||
pub const LOGGER_ENV: &str = "RUST_LOG";
|
||||
pub const CONFIG_ENV: &str = "RUST_CONFIG";
|
||||
pub const LOGS_ENV: &str = "LOGS_FOLDER";
|
||||
pub const ASSETS_ENV: &str = "ASSETS_FOLDER";
|
||||
pub const AVATARS_ENV: &str = "AVATARS_FOLDER";
|
||||
|
||||
// Instance info
|
||||
pub const SCULPTOR_VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
pub const REPOSITORY: &'static str = "shiroyashik/sculptor";
|
||||
pub const SCULPTOR_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
pub const REPOSITORY: &str = "shiroyashik/sculptor";
|
||||
|
||||
// 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);
|
||||
|
||||
// Figura update checker
|
||||
pub const FIGURA_RELEASES_URL: &'static str = "https://api.github.com/repos/figuramc/figura/releases";
|
||||
pub const FIGURA_DEFAULT_VERSION: &'static str = "0.1.4";
|
||||
pub const FIGURA_RELEASES_URL: &str = "https://api.github.com/repos/figuramc/figura/releases";
|
||||
pub const FIGURA_DEFAULT_VERSION: &str = "0.1.4";
|
||||
|
||||
// Figura Assets
|
||||
pub const FIGURA_ASSETS_ZIP_URL: &'static 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_ZIP_URL: &str = "https://github.com/FiguraMC/Assets/archive/refs/heads/main.zip";
|
||||
pub const FIGURA_ASSETS_COMMIT_URL: &str = "https://api.github.com/repos/FiguraMC/Assets/commits/main";
|
||||
39
src/main.rs
39
src/main.rs
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(clippy::module_inception)]
|
||||
use anyhow::Result;
|
||||
use axum::{
|
||||
extract::DefaultBodyLimit, routing::{delete, get, post, put}, Router
|
||||
|
|
@ -6,9 +7,8 @@ use dashmap::DashMap;
|
|||
use tracing_panic::panic_hook;
|
||||
use tracing_subscriber::{fmt::{self, time::ChronoLocal}, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||
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 uuid::Uuid;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
// Consts
|
||||
|
|
@ -31,28 +31,12 @@ use auth::{UManager, check_auth};
|
|||
|
||||
// Config
|
||||
mod state;
|
||||
use state::Config;
|
||||
use state::{Config, AppState};
|
||||
|
||||
// Utils
|
||||
mod 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! {
|
||||
pub static ref LOGGER_VAR: String = {
|
||||
var(LOGGER_ENV).unwrap_or(String::from("info"))
|
||||
|
|
@ -77,7 +61,7 @@ async fn main() -> Result<()> {
|
|||
let _ = dotenvy::dotenv();
|
||||
|
||||
// 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 file_layer = fmt::layer()
|
||||
|
|
@ -147,7 +131,7 @@ async fn app() -> Result<bool> {
|
|||
// Config
|
||||
let config = Arc::new(RwLock::new(Config::parse(CONFIG_VAR.clone().into())));
|
||||
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 {
|
||||
// Force update assets if folder or hash file doesn't exists.
|
||||
|
|
@ -179,15 +163,17 @@ async fn app() -> Result<bool> {
|
|||
uptime: Instant::now(),
|
||||
user_manager: Arc::new(UManager::new()),
|
||||
session: Arc::new(DashMap::new()),
|
||||
broadcasts: Arc::new(DashMap::new()),
|
||||
subscribes: Arc::new(DashMap::new()),
|
||||
figura_versions: Arc::new(RwLock::new(None)),
|
||||
config,
|
||||
};
|
||||
|
||||
// FIXME: FIXME: FIXME: ПЕРЕДЕЛАЙ ЭТО! НЕМЕДЛЕННО! ЕБУЧИЙ ПОЗОР :<
|
||||
// Automatic update of configuration while the server is running
|
||||
let config_update = Arc::clone(&state.config);
|
||||
let user_manager = Arc::clone(&state.user_manager);
|
||||
update_advanced_users(&config_update.read().await.advanced_users.clone(), &user_manager);
|
||||
let umanager = Arc::clone(&state.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 {
|
||||
loop {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
|
||||
|
|
@ -197,14 +183,15 @@ async fn app() -> Result<bool> {
|
|||
if new_config != *config {
|
||||
tracing::info!("Server configuration modification detected!");
|
||||
*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() {
|
||||
tokio::spawn(update_bans_from_minecraft(
|
||||
state.config.read().await.mc_folder.clone(),
|
||||
Arc::clone(&state.user_manager)
|
||||
Arc::clone(&state.user_manager),
|
||||
Arc::clone(&state.session)
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,11 +62,11 @@ pub struct BannedPlayer {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
impl Into<Userinfo> for BannedPlayer {
|
||||
fn into(self) -> Userinfo {
|
||||
impl From<BannedPlayer> for Userinfo {
|
||||
fn from(val: BannedPlayer) -> Self {
|
||||
Userinfo {
|
||||
uuid: self.uuid,
|
||||
username: self.name,
|
||||
uuid: val.uuid,
|
||||
username: val.name,
|
||||
banned: true,
|
||||
..Default::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ mod config;
|
|||
mod state;
|
||||
|
||||
pub use config::*;
|
||||
pub use state::*;
|
||||
|
|
@ -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>>>,
|
||||
}
|
||||
|
|
@ -30,14 +30,18 @@ pub fn _generate_hex_string(length: usize) -> String {
|
|||
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
|
||||
.iter()
|
||||
.map( |(uuid, userdata)| {
|
||||
(
|
||||
uuid.clone(),
|
||||
*uuid,
|
||||
Userinfo {
|
||||
uuid: uuid.clone(),
|
||||
uuid: *uuid,
|
||||
username: userdata.username.clone(),
|
||||
banned: userdata.banned,
|
||||
..Default::default()
|
||||
|
|
@ -48,12 +52,17 @@ pub fn update_advanced_users(value: &std::collections::HashMap<Uuid, AdvancedUse
|
|||
for (uuid, userinfo) in users {
|
||||
umanager.insert_user(uuid, userinfo.clone());
|
||||
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 mut file = tokio::fs::File::open(path.clone()).await.expect("Access denied or banned-players.json doesn't exists!");
|
||||
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 {
|
||||
umanager.ban(&player.clone().into());
|
||||
if let Some(tx) = sessions.get(&player.uuid) {let _ = tx.send(crate::api::figura::SessionMessage::Banned).await;}
|
||||
}
|
||||
|
||||
// old_bans
|
||||
|
|
@ -97,6 +107,7 @@ pub async fn update_bans_from_minecraft(folder: PathBuf, umanager: std::sync::Ar
|
|||
if !ban.is_empty() {
|
||||
for player in ban {
|
||||
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("-")};
|
||||
info!("List of changes:\n Banned: {ban_names}\n Unbanned: {unban_names}");
|
||||
|
|
@ -65,12 +65,10 @@ pub async fn get_figura_versions() -> anyhow::Result<FiguraVersions> {
|
|||
if tag_ver > prerelease_ver {
|
||||
prerelease_ver = tag_ver
|
||||
}
|
||||
} else {
|
||||
if tag_ver > release_ver {
|
||||
} else if tag_ver > release_ver {
|
||||
release_ver = tag_ver
|
||||
}
|
||||
}
|
||||
}
|
||||
if release_ver > prerelease_ver {
|
||||
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 {
|
||||
// Lines count in file abnormal
|
||||
Ok(true)
|
||||
} else {
|
||||
if contents == last_sha {
|
||||
} else if contents == last_sha {
|
||||
Ok(false)
|
||||
} else {
|
||||
// SHA in file mismatches with provided SHA
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => if err.kind() == tokio::io::ErrorKind::NotFound {
|
||||
// Can't find file
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
mod utils;
|
||||
mod auxiliary;
|
||||
mod check_updates;
|
||||
mod motd;
|
||||
|
||||
pub use utils::*;
|
||||
pub use auxiliary::*;
|
||||
pub use motd::*;
|
||||
pub use check_updates::*;
|
||||
Loading…
Add table
Add a link
Reference in a new issue