From d15bb20183a6adde2b6c846605ca5c925cdb1101 Mon Sep 17 00:00:00 2001 From: Tipragot Date: Sun, 28 Apr 2024 14:43:53 +0200 Subject: [PATCH] COMMIT DES COPAINS Co-authored-by: CoCoSol --- Cargo.lock | 320 ++++++----------------- crates/server/Cargo.toml | 21 +- crates/server/save src/lib.rs | 5 + crates/server/save src/lobby.rs | 13 + crates/server/save src/main.rs | 112 ++++++++ crates/server/src save/lib.rs | 38 +++ crates/server/{src => src save}/lobby.rs | 0 crates/server/src save/main.rs | 202 ++++++++++++++ crates/server/src/lib.rs | 19 +- crates/server/src/main.rs | 244 +++++------------ crates/server/src/manager.rs | 182 +++++++++++++ 11 files changed, 716 insertions(+), 440 deletions(-) create mode 100644 crates/server/save src/lib.rs create mode 100644 crates/server/save src/lobby.rs create mode 100644 crates/server/save src/main.rs create mode 100644 crates/server/src save/lib.rs rename crates/server/{src => src save}/lobby.rs (100%) create mode 100644 crates/server/src save/main.rs create mode 100644 crates/server/src/manager.rs diff --git a/Cargo.lock b/Cargo.lock index baa815f..33a5c20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,29 +18,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "ahash" -version = "0.8.11" +name = "ascon" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "9fe9a0cff241855e9166670d259192aacf1e9a81b865dc9905afbbab31a9d2c1" + +[[package]] +name = "ascon-hash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d629b6e580029d416158998cf0ae2d355d68cde3ed25715549533b0de9fd90b6" dependencies = [ - "cfg-if", - "const-random", - "once_cell", - "version_check", - "zerocopy", + "ascon", + "digest", ] -[[package]] -name = "anyhow" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" - [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", @@ -55,9 +52,9 @@ checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "axum" @@ -119,9 +116,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -147,12 +144,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "block-buffer" version = "0.10.4" @@ -170,18 +161,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" [[package]] name = "cfg-if" @@ -189,26 +177,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom", - "once_cell", - "tiny-keccak", -] - [[package]] name = "cpufeatures" version = "0.2.12" @@ -218,12 +186,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - [[package]] name = "crypto-common" version = "0.1.6" @@ -234,19 +196,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core", -] - [[package]] name = "data-encoding" version = "2.5.0" @@ -263,18 +212,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "flurry" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7874ce5eeafa5e546227f7c62911e586387bf03d6c9a45ac78aa1c3bc2fedb61" -dependencies = [ - "ahash", - "num_cpus", - "parking_lot", - "seize", -] - [[package]] name = "fnv" version = "1.0.7" @@ -406,12 +343,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - [[package]] name = "hermit-abi" version = "0.3.9" @@ -466,9 +397,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", @@ -511,9 +442,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "lazy_static" @@ -527,16 +458,6 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.21" @@ -551,9 +472,9 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mime" @@ -572,9 +493,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", @@ -606,29 +527,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -657,9 +555,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -721,15 +619,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -744,31 +633,9 @@ checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "scc" -version = "2.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c10d60d2fd9faf0e8b6540623f5e502343bde2ac585a7d158b3db24d93fcbe" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "seize" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e5739de653b129b0a59da381599cf17caf24bc586f6a797c52d3d6147c5b85a" -dependencies = [ - "num_cpus", - "once_cell", -] +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "serde" @@ -792,9 +659,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -827,18 +694,13 @@ dependencies = [ name = "server" version = "0.1.0" dependencies = [ - "anyhow", + "ascon-hash", "axum", "bincode", - "dashmap", - "flurry", "futures", "lazy_static", - "log", "rand", - "scc", "serde", - "slotmap", "tokio", "uuid", ] @@ -863,21 +725,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "slotmap" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" -dependencies = [ - "serde", - "version_check", -] - [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -914,33 +766,24 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -1083,9 +926,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -1145,7 +988,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.5", ] [[package]] @@ -1165,17 +1008,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -1186,9 +1030,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -1198,9 +1042,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -1210,9 +1054,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -1222,9 +1072,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -1234,9 +1084,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -1246,9 +1096,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -1258,26 +1108,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "zerocopy" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 40eb39e..28b1b7f 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -7,20 +7,15 @@ description = "The server of Border Wars" repository = "https://git.tipragot.fr/corentin/border-wars.git" [dependencies] -anyhow = "1.0.81" -axum = { version = "0.7.5", features = ["ws"] } -bincode = "1.3.3" -dashmap = "5.5.3" -flurry = "0.5.0" -futures = "0.3.30" -lazy_static = "1.4.0" -log = "0.4.21" -rand = "0.8.5" -scc = "2.0.19" +tokio = { version = "1.37.0", features = ["rt-multi-thread"] } +uuid = { version = "1.8.0", features = ["serde", "v7"] } serde = { version = "1.0.197", features = ["derive"] } -slotmap = { version = "1.0.7", features = ["serde"] } -tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread"] } -uuid = { version = "1.8.0", features = ["v4", "serde", "v7"] } +axum = { version = "0.7.5", features = ["ws"] } +ascon-hash = "0.2.0" +rand = "0.8.5" +futures = "0.3.30" +bincode = "1.3.3" +lazy_static = "1.4.0" # [lints] # workspace = true diff --git a/crates/server/save src/lib.rs b/crates/server/save src/lib.rs new file mode 100644 index 0000000..13fb59d --- /dev/null +++ b/crates/server/save src/lib.rs @@ -0,0 +1,5 @@ +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Serialize, Deserialize)] +pub struct JoinRequest(pub String, pub Option); diff --git a/crates/server/save src/lobby.rs b/crates/server/save src/lobby.rs new file mode 100644 index 0000000..7e877af --- /dev/null +++ b/crates/server/save src/lobby.rs @@ -0,0 +1,13 @@ +use std::collections::HashMap; + +use uuid::Uuid; + +pub struct LobbyManager { + connections: HashMap, + lobbies: HashMap, +} + +pub struct Lobby { + id: Uuid, + connections: HashMap, +} diff --git a/crates/server/save src/main.rs b/crates/server/save src/main.rs new file mode 100644 index 0000000..ef091d4 --- /dev/null +++ b/crates/server/save src/main.rs @@ -0,0 +1,112 @@ +use std::collections::hash_map::Entry; +use std::collections::HashMap; +use std::convert::Infallible; +use std::sync::Arc; +use std::time::Duration; + +use ascon_hash::{AsconXof, ExtendableOutput, Update, XofReader}; +use axum::extract::ws::{Message, WebSocket}; +use axum::extract::{State, WebSocketUpgrade}; +use axum::http::HeaderMap; +use axum::response::sse::{Event, KeepAlive}; +use axum::response::{IntoResponse, Sse}; +use axum::routing::get; +use axum::Router; +use futures::{SinkExt, StreamExt}; +use server::JoinRequest; +use tokio::sync::mpsc::{channel, Sender}; +use tokio::sync::RwLock; +use uuid::Uuid; + +mod lobby; + +#[derive(Clone, Default)] +struct GameManager { + lobbies: Arc>>>>>, +} + +#[tokio::main] +async fn main() { + let app = Router::new() + .route("/ws", get(ws_handler)) + .with_state(GameManager::default()); + let listener = tokio::net::TcpListener::bind("0.0.0.0:80").await.unwrap(); + axum::serve(listener, app).await.unwrap(); +} + +async fn ws_handler( + State(manager): State, + headers: HeaderMap, + ws: WebSocketUpgrade, +) -> impl IntoResponse { + ws.on_upgrade(|mut socket| async move { + // Handle authentication + let Some(Ok(message)) = socket.recv().await else { + return; + }; + let mut reader = AsconXof::default() + .chain(message.into_data()) + .finalize_xof(); + let mut hash = [0u8; 16]; + reader.read(&mut hash); + let id = Uuid::from_bytes(hash); + + // Get client request + let Some(Ok(message)) = socket.recv().await else { + return; + }; + let Ok(JoinRequest(username, lobby_id)) = bincode::deserialize(&message.into_data()) else { + return; + }; + + // Check if the client is in a game, if so, connect him to the game + todo!(); + + // Check if the client is already in a lobby, if so, refuse the connection + let mut lobbies = manager.lobbies.write().await; + for lobby in lobbies.values() { + if lobby.contains_key(&id) { + return; + } + } + + // Find or create the lobby + let (lobby_id, lobby) = match lobby_id { + Some(id) if id == Uuid::nil() => lobbies + .iter_mut() + .min_by_key(|(_, lobby)| lobby.len()) + .map(|(&id, lobby)| (id, lobby)) + .unwrap_or_else(|| { + let id = Uuid::now_v7(); + (id, lobbies.entry(id).or_default()) + }), + Some(id) => { + let Some(lobby) = lobbies.get_mut(&id) else { + return; + }; + (id, lobby) + } + None => { + let id = Uuid::now_v7(); + (id, lobbies.entry(id).or_default()) + } + }; + + // Initialize the sending loop + let (sender, mut receiver) = channel(1); + tokio::spawn(async move { + while let Some(message) = receiver.recv().await { + socket.send(Message::Binary(message)).await.ok(); + } + }); + + // Insert the client in the lobby + lobby.insert(id, sender); + drop(lobbies); + + // Wait for the client to be ready + let Some(Ok(message)) = socket.recv().await else { + return; + }; + }) +} diff --git a/crates/server/src save/lib.rs b/crates/server/src save/lib.rs new file mode 100644 index 0000000..4fd27df --- /dev/null +++ b/crates/server/src save/lib.rs @@ -0,0 +1,38 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Serialize, Deserialize)] +pub enum ClientPacket { + Disconnect, + CreateLobby { + username: String, + public: bool, + }, + JoinLobby { + lobby_id: Option, + username: String, + }, + IAmReady, + IAmNotReady, +} + +#[derive(Serialize, Deserialize)] +pub enum ServerPacket { + Refused(String), + LobbyJoined(Uuid), + LobbyUpdated(Lobby), +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct Lobby { + pub public: bool, + pub players: HashMap, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct LobbyPlayer { + pub username: String, + pub ready: bool, +} diff --git a/crates/server/src/lobby.rs b/crates/server/src save/lobby.rs similarity index 100% rename from crates/server/src/lobby.rs rename to crates/server/src save/lobby.rs diff --git a/crates/server/src save/main.rs b/crates/server/src save/main.rs new file mode 100644 index 0000000..c8c231a --- /dev/null +++ b/crates/server/src save/main.rs @@ -0,0 +1,202 @@ +use std::borrow::{Borrow, Cow}; +use std::collections::HashMap; + +use axum::extract::ws::{Message, WebSocket}; +use axum::extract::WebSocketUpgrade; +use axum::routing::get; +use axum::Router; +use futures::{SinkExt, StreamExt}; +use lazy_static::lazy_static; +use log::warn; +use server::{ClientPacket, Lobby, LobbyPlayer, ServerPacket}; +use tokio::sync::mpsc::{channel, Sender}; +use tokio::sync::RwLock; +use uuid::Uuid; + +struct Client { + status: ClientStatus, + sender: Sender>, +} + +enum ClientStatus { + Unauthenticated, + InLobby(Uuid), + InGame(Uuid), +} + +lazy_static! { + static ref CLIENTS: RwLock> = RwLock::new(HashMap::new()); + static ref LOBBIES: RwLock> = RwLock::new(HashMap::new()); +} + +pub async fn send_message<'a>(client_id: Uuid, message: impl Into>) { + if let Some(client) = CLIENTS.read().await.get(&client_id) { + client.sender.send(message.into().into_owned()).await.ok(); + } +} + +pub async fn send_packet(client_id: Uuid, packet: impl Borrow) { + let message = match bincode::serialize(packet.borrow()) { + Ok(message) => message, + Err(error) => { + warn!("failed to serialize packet for {}: {}", client_id, error); + return; + } + }; + send_message(client_id, message).await; +} + +#[tokio::main] +async fn main() { + let app = Router::new().route( + "/", + get(|ws: WebSocketUpgrade| async { ws.on_upgrade(handle_client) }), + ); + let listener = tokio::net::TcpListener::bind("0.0.0.0:80") + .await + .expect("failed to bind"); + axum::serve(listener, app).await.expect("failed to serve"); +} + +async fn handle_client(socket: WebSocket) { + let client_id = Uuid::now_v7(); + + let (mut sender, mut receiver) = socket.split(); + let (send_tx, mut send_rx) = channel(16); + tokio::spawn(async move { + while let Some(message) = send_rx.recv().await { + sender.send(Message::Binary(message)).await?; + } + Ok::<(), axum::Error>(()) + }); + + CLIENTS.write().await.insert( + client_id, + Client { + status: ClientStatus::Unauthenticated, + sender: send_tx, + }, + ); + + while let Some(Ok(message)) = receiver.next().await { + let Message::Binary(message) = message else { + continue; + }; + let Ok(packet) = bincode::deserialize::(&message) else { + warn!("failed to deserialize packet from {}", client_id); + continue; + }; + packet_received(client_id, packet).await; + } + + packet_received(client_id, ClientPacket::Disconnect).await; + CLIENTS.write().await.remove(&client_id); +} + +async fn packet_received(client_id: Uuid, packet: ClientPacket) { + let client = &CLIENTS.read().await[&client_id]; + match client.status { + ClientStatus::Unauthenticated => handle_unauthenticated(client_id, packet).await, + ClientStatus::InLobby(lobby_id) => handle_in_lobby(client_id, lobby_id, packet).await, + ClientStatus::InGame(game_id) => handle_in_game(client_id, game_id, packet).await, + } +} + +async fn handle_unauthenticated(client_id: Uuid, packet: ClientPacket) { + match packet { + ClientPacket::CreateLobby { username, public } => { + let lobby_id = Uuid::now_v7(); + let lobby = Lobby { + public, + players: HashMap::from_iter([( + client_id, + LobbyPlayer { + username, + ready: false, + }, + )]), + }; + let message = bincode::serialize(&ServerPacket::LobbyUpdated(lobby.clone())) + .expect("failed to serialize lobby"); + let mut lobbies = LOBBIES.write().await; + lobbies.insert(lobby_id, lobby); + CLIENTS + .write() + .await + .get_mut(&client_id) + .expect("client not found") + .status = ClientStatus::InLobby(lobby_id); + send_packet(client_id, ServerPacket::LobbyJoined(lobby_id)).await; + send_message(client_id, message).await; + } + ClientPacket::JoinLobby { lobby_id, username } => { + let mut lobbies = LOBBIES.write().await; + + let (lobby_id, lobby) = match lobby_id { + Some(id) => { + let Some(lobby) = lobbies.get_mut(&id) else { + return send_packet( + client_id, + ServerPacket::Refused("lobby not found".to_string()), + ) + .await; + }; + (id, lobby) + } + None => { + let random_lobby = lobbies + .iter_mut() + .filter(|(_, lobby)| lobby.public) + .min_by_key(|(_, lobby)| lobby.players.len()); + match random_lobby { + Some((&id, lobby)) => (id, lobby), + None => { + let id = Uuid::now_v7(); + ( + id, + lobbies.entry(id).or_insert(Lobby { + public: true, + players: HashMap::new(), + }), + ) + } + } + } + }; + + lobby.players.insert( + client_id, + LobbyPlayer { + username, + ready: false, + }, + ); + + CLIENTS + .write() + .await + .get_mut(&client_id) + .expect("client not found") + .status = ClientStatus::InLobby(lobby_id); + send_packet(client_id, ServerPacket::LobbyJoined(lobby_id)).await; + + let message = bincode::serialize(&ServerPacket::LobbyUpdated(lobby.clone())) + .expect("failed to serialize lobby"); // PAS BON + for player_id in lobby.players.keys() { + send_message(*player_id, &message).await; + } + } + _ => (), + } +} + +async fn handle_in_lobby(client_id: Uuid, lobby_id: Uuid, packet: ClientPacket) { + match packet { + ClientPacket::Disconnect => todo!(), + ClientPacket::IAmReady => todo!(), + ClientPacket::IAmNotReady => todo!(), + _ => (), + } +} + +async fn handle_in_game(client_id: Uuid, game_id: Uuid, packet: ClientPacket) {} diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs index 4fd27df..6c22495 100644 --- a/crates/server/src/lib.rs +++ b/crates/server/src/lib.rs @@ -4,35 +4,34 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; #[derive(Serialize, Deserialize)] -pub enum ClientPacket { - Disconnect, +pub enum ClientMessage { CreateLobby { username: String, public: bool, }, JoinLobby { - lobby_id: Option, username: String, + lobby_id: Option, }, - IAmReady, - IAmNotReady, + Ready(bool), } #[derive(Serialize, Deserialize)] -pub enum ServerPacket { +pub enum ServerMessage { Refused(String), - LobbyJoined(Uuid), - LobbyUpdated(Lobby), + LobbyUpdate(Lobby), } #[derive(Clone, Serialize, Deserialize)] pub struct Lobby { + pub id: Uuid, pub public: bool, - pub players: HashMap, + pub players: HashMap, } #[derive(Clone, Serialize, Deserialize)] -pub struct LobbyPlayer { +pub struct Player { + pub id: Uuid, pub username: String, pub ready: bool, } diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index c8c231a..b7e5fbd 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs @@ -1,202 +1,102 @@ -use std::borrow::{Borrow, Cow}; +use std::borrow::Borrow; +use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::sync::Arc; -use axum::extract::ws::{Message, WebSocket}; -use axum::extract::WebSocketUpgrade; +use ascon_hash::{AsconXof, ExtendableOutput, Update, XofReader}; +use axum::extract::ws::Message; +use axum::extract::{State, WebSocketUpgrade}; +use axum::response::IntoResponse; use axum::routing::get; use axum::Router; use futures::{SinkExt, StreamExt}; use lazy_static::lazy_static; -use log::warn; -use server::{ClientPacket, Lobby, LobbyPlayer, ServerPacket}; +use manager::handle_event; +use server::{ClientMessage, ServerMessage}; use tokio::sync::mpsc::{channel, Sender}; use tokio::sync::RwLock; use uuid::Uuid; -struct Client { - status: ClientStatus, - sender: Sender>, -} - -enum ClientStatus { - Unauthenticated, - InLobby(Uuid), - InGame(Uuid), -} +mod manager; lazy_static! { - static ref CLIENTS: RwLock> = RwLock::new(HashMap::new()); - static ref LOBBIES: RwLock> = RwLock::new(HashMap::new()); + pub static ref CONNECTIONS: ConnectionManager = ConnectionManager::default(); } -pub async fn send_message<'a>(client_id: Uuid, message: impl Into>) { - if let Some(client) = CLIENTS.read().await.get(&client_id) { - client.sender.send(message.into().into_owned()).await.ok(); +#[derive(Default)] +pub struct ConnectionManager(RwLock>>>); + +impl ConnectionManager { + pub async fn send(&self, id: Uuid, message: impl Borrow) { + if let Some(sender) = self.0.read().await.get(&id) { + let Ok(message) = bincode::serialize(message.borrow()) else { + eprintln!("failed to serialize message"); + return; + }; + sender.send(message).await.ok(); + } } } -pub async fn send_packet(client_id: Uuid, packet: impl Borrow) { - let message = match bincode::serialize(packet.borrow()) { - Ok(message) => message, - Err(error) => { - warn!("failed to serialize packet for {}: {}", client_id, error); - return; - } - }; - send_message(client_id, message).await; +pub enum ClientEvent { + Connected, + Message(ClientMessage), + Disconnected, } #[tokio::main] async fn main() { - let app = Router::new().route( - "/", - get(|ws: WebSocketUpgrade| async { ws.on_upgrade(handle_client) }), - ); - let listener = tokio::net::TcpListener::bind("0.0.0.0:80") - .await - .expect("failed to bind"); - axum::serve(listener, app).await.expect("failed to serve"); + let app = Router::new().route("/ws", get(ws_handler)); + let listener = tokio::net::TcpListener::bind("0.0.0.0:80").await.unwrap(); + axum::serve(listener, app).await.unwrap(); } -async fn handle_client(socket: WebSocket) { - let client_id = Uuid::now_v7(); - - let (mut sender, mut receiver) = socket.split(); - let (send_tx, mut send_rx) = channel(16); - tokio::spawn(async move { - while let Some(message) = send_rx.recv().await { - sender.send(Message::Binary(message)).await?; - } - Ok::<(), axum::Error>(()) - }); - - CLIENTS.write().await.insert( - client_id, - Client { - status: ClientStatus::Unauthenticated, - sender: send_tx, - }, - ); - - while let Some(Ok(message)) = receiver.next().await { - let Message::Binary(message) = message else { - continue; +async fn ws_handler(ws: WebSocketUpgrade) -> impl IntoResponse { + ws.on_upgrade(|mut socket| async move { + // Handle authentication + let Some(Ok(message)) = socket.recv().await else { + return; }; - let Ok(packet) = bincode::deserialize::(&message) else { - warn!("failed to deserialize packet from {}", client_id); - continue; - }; - packet_received(client_id, packet).await; - } + let mut reader = AsconXof::default() + .chain(message.into_data()) + .finalize_xof(); + let mut hash = [0u8; 16]; + reader.read(&mut hash); + let id = Uuid::from_bytes(hash); - packet_received(client_id, ClientPacket::Disconnect).await; - CLIENTS.write().await.remove(&client_id); -} + // Start the sending loop + let (mut writer, mut reader) = socket.split(); + let (sender, mut receiver) = channel(1); + tokio::spawn(async move { + while let Some(message) = receiver.recv().await { + writer.send(Message::Binary(message)).await?; + } + Ok::<(), axum::Error>(()) + }); -async fn packet_received(client_id: Uuid, packet: ClientPacket) { - let client = &CLIENTS.read().await[&client_id]; - match client.status { - ClientStatus::Unauthenticated => handle_unauthenticated(client_id, packet).await, - ClientStatus::InLobby(lobby_id) => handle_in_lobby(client_id, lobby_id, packet).await, - ClientStatus::InGame(game_id) => handle_in_game(client_id, game_id, packet).await, - } -} - -async fn handle_unauthenticated(client_id: Uuid, packet: ClientPacket) { - match packet { - ClientPacket::CreateLobby { username, public } => { - let lobby_id = Uuid::now_v7(); - let lobby = Lobby { - public, - players: HashMap::from_iter([( - client_id, - LobbyPlayer { - username, - ready: false, - }, - )]), - }; - let message = bincode::serialize(&ServerPacket::LobbyUpdated(lobby.clone())) - .expect("failed to serialize lobby"); - let mut lobbies = LOBBIES.write().await; - lobbies.insert(lobby_id, lobby); - CLIENTS - .write() - .await - .get_mut(&client_id) - .expect("client not found") - .status = ClientStatus::InLobby(lobby_id); - send_packet(client_id, ServerPacket::LobbyJoined(lobby_id)).await; - send_message(client_id, message).await; - } - ClientPacket::JoinLobby { lobby_id, username } => { - let mut lobbies = LOBBIES.write().await; - - let (lobby_id, lobby) = match lobby_id { - Some(id) => { - let Some(lobby) = lobbies.get_mut(&id) else { - return send_packet( - client_id, - ServerPacket::Refused("lobby not found".to_string()), - ) - .await; - }; - (id, lobby) - } - None => { - let random_lobby = lobbies - .iter_mut() - .filter(|(_, lobby)| lobby.public) - .min_by_key(|(_, lobby)| lobby.players.len()); - match random_lobby { - Some((&id, lobby)) => (id, lobby), - None => { - let id = Uuid::now_v7(); - ( - id, - lobbies.entry(id).or_insert(Lobby { - public: true, - players: HashMap::new(), - }), - ) - } - } - } - }; - - lobby.players.insert( - client_id, - LobbyPlayer { - username, - ready: false, - }, - ); - - CLIENTS - .write() - .await - .get_mut(&client_id) - .expect("client not found") - .status = ClientStatus::InLobby(lobby_id); - send_packet(client_id, ServerPacket::LobbyJoined(lobby_id)).await; - - let message = bincode::serialize(&ServerPacket::LobbyUpdated(lobby.clone())) - .expect("failed to serialize lobby"); // PAS BON - for player_id in lobby.players.keys() { - send_message(*player_id, &message).await; + // Register the client + match CONNECTIONS.0.write().await.entry(id) { + Entry::Occupied(_) => return, + Entry::Vacant(entry) => { + entry.insert(sender); } } - _ => (), - } -} -async fn handle_in_lobby(client_id: Uuid, lobby_id: Uuid, packet: ClientPacket) { - match packet { - ClientPacket::Disconnect => todo!(), - ClientPacket::IAmReady => todo!(), - ClientPacket::IAmNotReady => todo!(), - _ => (), - } -} + // Send the connection event + handle_event(id, ClientEvent::Connected).await; -async fn handle_in_game(client_id: Uuid, game_id: Uuid, packet: ClientPacket) {} + // Handle incoming messages + while let Some(Ok(message)) = reader.next().await { + let Ok(message) = bincode::deserialize(&message.into_data()) else { + continue; + }; + handle_event(id, ClientEvent::Message(message)).await; + } + + // Send the disconnection event + handle_event(id, ClientEvent::Disconnected).await; + + // Unregister the client + CONNECTIONS.0.write().await.remove(&id); + }) +} diff --git a/crates/server/src/manager.rs b/crates/server/src/manager.rs new file mode 100644 index 0000000..1ff5ecc --- /dev/null +++ b/crates/server/src/manager.rs @@ -0,0 +1,182 @@ +use std::collections::hash_map::{Entry, VacantEntry}; +use std::collections::HashMap; + +use lazy_static::lazy_static; +use server::{Lobby, Player, ServerMessage}; +use tokio::sync::mpsc::Sender; +use tokio::sync::{RwLock, RwLockWriteGuard}; +use uuid::Uuid; + +use crate::{ClientEvent, ClientMessage, CONNECTIONS}; + +#[derive(Clone, Copy)] +pub enum ClientStatus { + InLobby(Uuid), + InGame(Uuid), +} + +lazy_static! { + pub static ref CLIENT_STATUS: RwLock> = RwLock::new(HashMap::new()); + pub static ref LOBBIES: RwLock> = RwLock::new(HashMap::new()); +} + +pub async fn handle_event(id: Uuid, event: ClientEvent) { + let status = CLIENT_STATUS.read().await.get(&id).copied(); + match status { + None => handle_unauthenticated_event(id, event).await, + Some(ClientStatus::InLobby(lobby_id)) => handle_lobby_event(lobby_id, id, event).await, + Some(ClientStatus::InGame(game_id)) => handle_game_event(game_id, id, event).await, + } +} + +async fn handle_unauthenticated_event(id: Uuid, event: ClientEvent) { + match event { + ClientEvent::Message(ClientMessage::CreateLobby { username, public }) => { + // Create the lobby + let mut lobbies = LOBBIES.write().await; + let lobby_id = Uuid::now_v7(); + let lobby = lobbies.entry(lobby_id).or_insert(Lobby { + id: lobby_id, + public, + players: HashMap::from_iter([( + id, + Player { + id, + username, + ready: false, + }, + )]), + }); + + // Change the client status + CLIENT_STATUS + .write() + .await + .insert(id, ClientStatus::InLobby(lobby.id)); + + // Send the lobby update + CONNECTIONS + .send(id, ServerMessage::LobbyUpdate(lobby.clone())) + .await; + } + ClientEvent::Message(ClientMessage::JoinLobby { username, lobby_id }) => { + // Find or create the lobby + let mut lobbies = LOBBIES.write().await; + let lobby = match lobby_id { + Some(lobby_id) => { + let Some(lobby) = lobbies.get_mut(&lobby_id) else { + CONNECTIONS + .send(id, ServerMessage::Refused("Lobby not found".to_string())) + .await; + return; + }; + lobby + } + None => { + if let Some((_, lobby)) = lobbies + .iter_mut() + .min_by_key(|(_, value)| value.players.len()) + { + lobby + } else { + let lobby_id = Uuid::now_v7(); + lobbies.entry(lobby_id).or_insert(Lobby { + id: lobby_id, + public: true, + players: HashMap::new(), + }) + } + } + }; + + // Change the client status + CLIENT_STATUS + .write() + .await + .insert(id, ClientStatus::InLobby(lobby.id)); + + // Add the player to the lobby + lobby.players.insert( + id, + Player { + id, + username, + ready: false, + }, + ); + + // Send the lobby update to all players + let message = ServerMessage::LobbyUpdate(lobby.clone()); + for player_id in lobby.players.keys() { + CONNECTIONS.send(*player_id, &message).await; + } + } + _ => (), + }; +} + +async fn handle_lobby_event(lobby_id: Uuid, id: Uuid, event: ClientEvent) { + match event { + ClientEvent::Message(ClientMessage::Ready(ready)) => { + // Get the lobby + let mut lobbies = LOBBIES.write().await; + let Some(lobby) = lobbies.get_mut(&lobby_id) else { + return; + }; + + // Get the lobby player + let Some(player) = lobby.players.get_mut(&id) else { + return; + }; + + // Update the player ready status + player.ready = ready; + + // If everyone is ready, start the game + if lobby.players.len() >= 2 && lobby.players.values().all(|p| p.ready) { + todo!("start the game"); + return; + } + + // Send the lobby update to all players + let message = ServerMessage::LobbyUpdate(lobby.clone()); + for player_id in lobby.players.keys() { + CONNECTIONS.send(*player_id, &message).await; + } + } + ClientEvent::Disconnected => { + // Remove the client status + CLIENT_STATUS.write().await.remove(&id); + + // Remove the client from the lobby + let mut lobbies = LOBBIES.write().await; + let Some(lobby) = lobbies.get_mut(&lobby_id) else { + return; + }; + lobby.players.remove(&id); + + // If the lobby is empty, remove it + if lobby.players.is_empty() { + lobbies.remove(&lobby_id); + return; + } + + // If everyone is ready, start the game + if lobby.players.len() >= 2 && lobby.players.values().all(|p| p.ready) { + todo!("start the game"); + return; + } + + // Send the lobby update to all players + let message = ServerMessage::LobbyUpdate(lobby.clone()); + for player_id in lobby.players.keys() { + CONNECTIONS.send(*player_id, &message).await; + } + } + _ => (), + } +} + +async fn handle_game_event(game_id: Uuid, id: Uuid, event: ClientEvent) { + todo!() +}