diff --git a/Cargo.lock b/Cargo.lock index 0334be7..f5d9b04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,6 +131,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-compression" version = "0.4.17" @@ -235,9 +241,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49c41b948da08fb481a94546cd874843adc1142278b0af4badf9b1b78599d68d" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core", @@ -318,6 +324,30 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bitcode" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1bce7608560cd4bf0296a4262d0dbf13e6bcec5ff2105724c8ab88cc7fc784" +dependencies = [ + "arrayvec", + "bitcode_derive", + "bytemuck", + "glam", + "serde", +] + +[[package]] +name = "bitcode_derive" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a539389a13af092cd345a2b47ae7dec12deb306d660b2223d25cd3419b253ebe" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bitflags" version = "2.6.0" @@ -366,6 +396,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" + [[package]] name = "byteorder" version = "1.5.0" @@ -446,6 +482,7 @@ checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" name = "client" version = "0.1.0" dependencies = [ + "bitcode", "codee", "console_error_panic_hook", "console_log", @@ -810,16 +847,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "event-listener" version = "5.3.1" @@ -847,18 +874,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" -[[package]] -name = "fastrand" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" version = "1.0.35" @@ -1018,6 +1033,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glam" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" + [[package]] name = "gloo-net" version = "0.6.0" @@ -1140,12 +1161,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - [[package]] name = "hermit-abi" version = "0.3.9" @@ -1311,9 +1326,9 @@ dependencies = [ [[package]] name = "icondata" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18db9eec46b6c870bf84281dd8065fb207b23a9c1c0cb367c49a919a61a38dec" +checksum = "805a2a031c06a768407b774240192b0ad82ddb94554bb5b52053453f2f6b0bf1" dependencies = [ "icondata_ai", "icondata_bi", @@ -1327,6 +1342,7 @@ dependencies = [ "icondata_im", "icondata_io", "icondata_lu", + "icondata_mdi", "icondata_oc", "icondata_ri", "icondata_si", @@ -1441,6 +1457,15 @@ dependencies = [ "icondata_core", ] +[[package]] +name = "icondata_mdi" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8e840a8faae895efc4f3a3d5e3a9fcf0fbb01e8b37f469951102dfa9588efe" +dependencies = [ + "icondata_core", +] + [[package]] name = "icondata_oc" version = "0.0.10" @@ -1923,8 +1948,7 @@ name = "lib" version = "0.1.0" dependencies = [ "anyhow", - "prost", - "prost-build", + "bitcode", "rand", "serde", "tracing", @@ -1932,9 +1956,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.162" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "linear-map" @@ -1942,12 +1966,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - [[package]] name = "litemap" version = "0.7.3" @@ -2067,12 +2085,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - [[package]] name = "next_tuple" version = "0.1.0-rc1" @@ -2240,16 +2252,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.6.0", -] - [[package]] name = "phf" version = "0.11.2" @@ -2460,27 +2462,6 @@ dependencies = [ "prost-derive", ] -[[package]] -name = "prost-build" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" -dependencies = [ - "bytes", - "heck", - "itertools", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn", - "tempfile", -] - [[package]] name = "prost-derive" version = "0.13.3" @@ -2717,19 +2698,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" -[[package]] -name = "rustix" -version = "0.38.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - [[package]] name = "rustversion" version = "1.0.18" @@ -2794,9 +2762,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -2852,6 +2820,7 @@ version = "0.1.0" dependencies = [ "anyhow", "axum", + "bitcode", "clap", "console-subscriber", "futures", @@ -3107,23 +3076,10 @@ dependencies = [ "web-sys", ] -[[package]] -name = "tempfile" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - [[package]] name = "thaw" version = "0.4.0-beta4" -source = "git+https://github.com/thaw-ui/thaw.git#bb5129bbef20240032bc37bd84d3b0527c98f2b4" +source = "git+https://github.com/thaw-ui/thaw.git#9e8d1c5daea8dcf213062fd1e432d069cb3fe168" dependencies = [ "cfg-if", "chrono", @@ -3145,7 +3101,7 @@ dependencies = [ [[package]] name = "thaw_components" version = "0.2.0-beta4" -source = "git+https://github.com/thaw-ui/thaw.git#bb5129bbef20240032bc37bd84d3b0527c98f2b4" +source = "git+https://github.com/thaw-ui/thaw.git#9e8d1c5daea8dcf213062fd1e432d069cb3fe168" dependencies = [ "cfg-if", "leptos", @@ -3158,7 +3114,7 @@ dependencies = [ [[package]] name = "thaw_macro" version = "0.1.0-beta4" -source = "git+https://github.com/thaw-ui/thaw.git#bb5129bbef20240032bc37bd84d3b0527c98f2b4" +source = "git+https://github.com/thaw-ui/thaw.git#9e8d1c5daea8dcf213062fd1e432d069cb3fe168" dependencies = [ "proc-macro2", "quote", @@ -3168,7 +3124,7 @@ dependencies = [ [[package]] name = "thaw_utils" version = "0.1.0-beta4" -source = "git+https://github.com/thaw-ui/thaw.git#bb5129bbef20240032bc37bd84d3b0527c98f2b4" +source = "git+https://github.com/thaw-ui/thaw.git#9e8d1c5daea8dcf213062fd1e432d069cb3fe168" dependencies = [ "cfg-if", "chrono", @@ -3446,9 +3402,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" +checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" dependencies = [ "async-compression", "bitflags", diff --git a/clients/leptos/Cargo.toml b/clients/leptos/Cargo.toml index 994b3af..5d7261a 100644 --- a/clients/leptos/Cargo.toml +++ b/clients/leptos/Cargo.toml @@ -8,6 +8,7 @@ authors = ["Adam Doyle "] [dependencies] # Cards +bitcode = "0" lib = { workspace = true } serde_json = "1" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 718e54d..e1bf23d 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -4,11 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] -anyhow = "1.0.86" -prost = "0" -rand = "0.8.5" -serde = "1.0.204" -tracing = "0.1.40" - -[build-dependencies] -prost-build = "0" +anyhow = "1" +bitcode = "0" +rand = "0" +serde = "1" +tracing = "0" diff --git a/lib/src/lib.rs b/lib/src/lib.rs index ad66e87..57d924a 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,206 +1,159 @@ -use prost::Message; +use bitcode::{Decode, Encode}; use serde::{Deserialize, Serialize}; /// Judge decision -#[derive(Clone, Serialize, Deserialize, Message)] +#[derive(Clone, Serialize, Deserialize, Encode, Decode)] pub struct JudgeDecisionRequest { - #[prost(string, tag = "1")] pub game_id: String, - #[prost(string, repeated, tag = "2")] pub winning_cards: Vec, } /// White Card Meta -#[derive(Clone, Message, Hash, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Hash, Eq, PartialEq, Serialize, Deserialize)] pub struct WhiteCardMeta { - #[prost(string, tag = "1")] pub uuid: String, - #[prost(string, tag = "2")] pub text: String, } /// Judge entry -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct JudgeEntry { - #[prost(message, repeated, tag = "1")] pub cards_to_judge: Vec, } /// Judge round -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct JudgeRound { - #[prost(message, repeated, tag = "1")] pub entries: Vec, } /// Delete game request -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct GameDeleteRequest { - #[prost(string, tag = "1")] pub delete_game_id: String, } /// Game join request -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct GameJoinRequest { - #[prost(string, tag = "1")] pub id: String, } /// Player Move Request -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct PlayerMoveRequest { - #[prost(string, tag = "1")] pub game_id: String, - #[prost(string, repeated, tag = "2")] pub card_ids: Vec, } /// Game Player Meta -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct GamePlayerMeta { - #[prost(string, tag = "1")] pub name: String, - #[prost(uint32, tag = "2")] pub score: u32, - #[prost(bool, tag = "3")] pub submitted: bool, } /// Game meta -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct GameMeta { - #[prost(string, tag = "1")] pub uuid: String, - #[prost(string, tag = "2")] pub name: String, - #[prost(string, tag = "3")] pub host: String, - #[prost(message, repeated, tag = "4")] pub players: Vec, - #[prost(string, tag = "5")] pub czar: String, - #[prost(bytes, tag = "6")] pub packs: Vec, - #[prost(uint32, tag = "7")] pub white_count: u32, - #[prost(uint32, tag = "8")] pub black_count: u32, - #[prost(uint32, tag = "9")] pub white_discard_count: u32, } /// Black card meta -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct BlackCardMeta { - #[prost(string, tag = "1")] pub text: String, - #[prost(uint32, tag = "2")] pub pick: u32, } /// Game state meta -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct GameStateMeta { - #[prost(message, tag = "1")] pub black: Option, // this has to be an option or prost gets cranky - #[prost(message, repeated, tag = "2")] pub white: Vec, } /// Game browser meta -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct GameBrowserMeta { - #[prost(string, tag = "1")] pub uuid: String, - #[prost(string, tag = "2")] pub name: String, - #[prost(string, tag = "3")] pub host: String, - #[prost(uint32, tag = "4")] pub players: u32, - #[prost(bytes, tag = "5")] pub packs: Vec, } /// Card Pack Meta -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct CardPackMeta { - #[prost(string, tag = "1")] pub name: String, - #[prost(string, tag = "2")] pub pack: String, - #[prost(uint32, tag = "3")] pub num_white: u32, - #[prost(uint32, tag = "4")] pub num_black: u32, } /// Card Packs Meta -#[derive(Clone, Message, Serialize, Deserialize)] +#[derive(Clone, Encode, Decode, Serialize, Deserialize)] pub struct CardPacksMeta { - #[prost(message, repeated, tag = "1")] pub official_meta: Vec, - #[prost(message, repeated, tag = "2")] pub unofficial_meta: Vec, } /// Games update -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct GamesUpdate { - #[prost(message, repeated, tag = "1")] pub games: Vec, } /// Chat update -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct ChatUpdate { - #[prost(string, tag = "1")] pub room: String, - #[prost(string, repeated, tag = "2")] pub users: Vec, } /// User login request (to change name) -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct UserLogInRequest { - #[prost(string, tag = "1")] pub username: String, } /// Response to user name change containing new name -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct UserUpdate { - #[prost(string, tag = "1")] pub username: String, } /// Chat message -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct ChatMessage { - #[prost(string, tag = "1")] pub text: String, } /// Server user count -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct ServerOnlineUsers { - #[prost(uint32, tag = "1")] pub online_users: u32, } /// Server games count -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct ServerActiveGames { - #[prost(uint32, tag = "1")] pub active_games: u32, } /// New game request structure -#[derive(Message, Serialize, Deserialize)] +#[derive(Encode, Decode, Serialize, Deserialize)] pub struct NewGameRequest { - #[prost(string, tag = "1")] pub game_name: String, - #[prost(string, repeated, tag = "2")] pub game_packs: Vec, } diff --git a/server/Cargo.toml b/server/Cargo.toml index 84df752..4caa619 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -9,6 +9,7 @@ lib = { workspace = true } anyhow = "1" axum = { version = "0", features = ["ws"] } +bitcode = "0" clap = { version = "4", features = ["cargo"] } futures = "0" rand = "0" diff --git a/server/src/game_handler.rs b/server/src/game_handler.rs index 59c5ab5..f881ebf 100644 --- a/server/src/game_handler.rs +++ b/server/src/game_handler.rs @@ -5,13 +5,13 @@ use crate::DmUserMethod::*; use crate::GameHandlerMessage::*; use crate::SendUserMessage::*; use crate::UserHandlerMessage::*; +use axum::extract::ws::Message; use lib::*; use serde_json::to_string; use std::collections::HashMap; use std::{net::SocketAddr, sync::Arc}; /// For interacting with the game handler -#[derive(Debug)] pub enum GameHandlerMessage { NewGame(NewGameRequest, SocketAddr), JoinGame(String, SocketAddr), @@ -95,7 +95,7 @@ impl GameHandler { match this_game.player_move(&request, player_user_id) { Err(err) => { let message = ChatMessage { text: err }; - let users_tx = self.state.users_tx.clone(); + let users_tx = self.state.tx_user_handler.clone(); tokio::spawn(async move { if let Err(e) = users_tx .send(DmUser(SendChatMessage(message), Addr(addr))) @@ -109,7 +109,7 @@ impl GameHandler { tracing::debug!("TODO: whatever i'm supposed to do") } Ok(Some((judge_round, czar_id))) => { - let users_tx = self.state.users_tx.clone(); + let users_tx = self.state.tx_user_handler.clone(); tokio::spawn(async move { if let Err(e) = users_tx .send(DmUser(SendJudgeRound(judge_round), Id(czar_id))) @@ -226,7 +226,7 @@ impl GameHandler { }; // Send user's update - let msg = serde_json::to_string(&meta).unwrap(); + let msg = Message::Text(to_string(&meta).unwrap()); let user_tx = player.user.read().unwrap().tx.clone(); tokio::spawn(async move { // channel can still close after this point but it'll catch most of it @@ -266,7 +266,7 @@ impl GameHandler { }; // Send user's update - let msg = serde_json::to_string(&meta).unwrap(); + let msg = Message::Text(to_string(&meta).unwrap()); let user_tx = player.user.read().unwrap().tx.clone(); tokio::spawn(async move { user_tx.send(msg).await }); } @@ -297,7 +297,7 @@ impl GameHandler { }; // Send user's update - let msg = serde_json::to_string(&meta).unwrap(); + let msg = Message::Text(to_string(&meta).unwrap()); let user_tx = player.user.read().unwrap().tx.clone(); tokio::spawn(async move { user_tx.send(msg).await }); } else { @@ -380,9 +380,9 @@ impl GameHandler { .collect::>(); let msg = to_string::(&GamesUpdate { games }).unwrap(); - let tx = self.state.broadcast_tx.clone(); + let tx = self.state.tx_broadcast.clone(); tokio::spawn(async move { - if let Err(e) = tx.send(msg) { + if let Err(e) = tx.send(Message::Text(msg)) { tracing::error!("Error broadcasting games update: {}", e); } }); @@ -390,11 +390,11 @@ impl GameHandler { /// Broadcast updated game count fn broadcast_game_count(&self) { - let tx = self.state.broadcast_tx.clone(); + let tx = self.state.tx_broadcast.clone(); let active_games: u32 = self.games.len().try_into().unwrap(); let msg = to_string(&ServerActiveGames { active_games }).unwrap(); tokio::spawn(async move { - if let Err(e) = tx.send(msg) { + if let Err(e) = tx.send(Message::Text(msg)) { tracing::error!("Error broadcasting game count: {}", e); } }); diff --git a/server/src/message_handler.rs b/server/src/incoming_message_handler.rs similarity index 89% rename from server/src/message_handler.rs rename to server/src/incoming_message_handler.rs index 97fb970..8e2fa44 100644 --- a/server/src/message_handler.rs +++ b/server/src/incoming_message_handler.rs @@ -9,15 +9,15 @@ use std::net::SocketAddr; use std::sync::Arc; /// Handles incoming messages -pub struct MessageHandler { +pub struct IncomingMessageHandler { /// Global state pointer state: Arc, } -impl MessageHandler { - /// Returns new MessageHandler object +impl IncomingMessageHandler { + /// Returns new IncomingMessageHandler object pub fn new(state: Arc) -> Self { - MessageHandler { state } + IncomingMessageHandler { state } } /// Handles incoming messages @@ -34,9 +34,10 @@ impl MessageHandler { } // Broadcast incoming chat message - let broadcast_message = - to_string::(&ChatMessage { text: msg }).unwrap(); - let tx = self.state.broadcast_tx.clone(); + let broadcast_message = Message::Text( + to_string::(&ChatMessage { text: msg }).unwrap(), + ); + let tx = self.state.tx_broadcast.clone(); tokio::spawn(async move { if let Err(e) = tx.send(broadcast_message) { tracing::error!("Error broadcasting Chat message: {}", e) @@ -47,7 +48,7 @@ impl MessageHandler { if let Ok(user_log_in) = from_str::(&text) => { let msg = UserLogIn(user_log_in, addr); - let tx = self.state.users_tx.clone(); + let tx = self.state.tx_user_handler.clone(); tokio::spawn(async move { if let Err(e) = tx.send(msg).await { tracing::error!("Error sending user login: {}", e) @@ -56,7 +57,7 @@ impl MessageHandler { } _new_game_request if let Ok(new_game) = from_str::(&text) => { let msg = NewGame(new_game, addr); - let tx = self.state.games_tx.clone(); + let tx = self.state.tx_game_handler.clone(); tokio::spawn(async move { if let Err(e) = tx.send(msg).await { tracing::error!("Error requesting new game: {}", e) @@ -66,7 +67,7 @@ impl MessageHandler { _join_game_request if let Ok(join_request) = from_str::(&text) => { let msg = JoinGame(join_request.id, addr); - let tx = self.state.games_tx.clone(); + let tx = self.state.tx_game_handler.clone(); tokio::spawn(async move { if let Err(e) = tx.send(msg).await { tracing::error!("Error requesting game join: {}", e) @@ -86,7 +87,7 @@ impl MessageHandler { return; } else { let msg = MoveRequest(move_request, addr); - let tx = self.state.games_tx.clone(); + let tx = self.state.tx_game_handler.clone(); tokio::spawn(async move { if let Err(e) = tx.send(msg).await { tracing::error!("Error sending move request: {}", e) @@ -100,7 +101,7 @@ impl MessageHandler { { if !judge_request.winning_cards.is_empty() { let msg = JudgeDecision(judge_request, addr); - let tx = self.state.games_tx.clone(); + let tx = self.state.tx_game_handler.clone(); tokio::spawn(async move { if let Err(e) = tx.send(msg).await { tracing::error!("Error sending Judge Decision: {}", e) @@ -113,7 +114,7 @@ impl MessageHandler { _delete_game if let Ok(delete_request) = from_str::(&text) => { let msg = DeleteGame(delete_request); - let tx = self.state.games_tx.clone(); + let tx = self.state.tx_game_handler.clone(); tokio::spawn(async move { if let Err(e) = tx.send(msg).await { tracing::error!("Error sending delete game: {}", e) @@ -151,7 +152,7 @@ impl MessageHandler { /// This runs when a connection closes fn handle_close(&self, close_frame: Option, addr: SocketAddr) { let msg = UserHandlerMessage::Cleanup(addr); - let tx = self.state.users_tx.clone(); + let tx = self.state.tx_user_handler.clone(); tokio::spawn(async move { tx.send(msg).await }); // Process close frame diff --git a/server/src/lib.rs b/server/src/lib.rs index 7619425..d71e0e1 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -19,7 +19,7 @@ use user_handler::*; use uuid::Uuid; pub mod game; pub mod game_handler; -pub mod message_handler; +pub mod incoming_message_handler; pub mod user_handler; pub mod websocket; @@ -28,16 +28,16 @@ pub mod websocket; pub struct User { pub uuid: String, pub name: String, - pub tx: Sender, + pub tx: Sender, } impl User { /// Create a new user object from incoming data - pub fn new(name: String, tx: Sender) -> User { + pub fn new(name: String, tx: Sender) -> User { User { - uuid: Uuid::now_v7().to_string(), name, tx, + uuid: Uuid::now_v7().to_string(), } } @@ -62,27 +62,27 @@ pub fn load_names(path: &str) -> Result> { // Our shared state pub struct AppState { - pub white_cards_by_id: HashMap>, - pub broadcast_tx: broadcast::Sender, - pub users_tx: mpsc::Sender, - pub messages_tx: mpsc::Sender<(SocketAddr, Message)>, - pub games_tx: mpsc::Sender, pub first_names: Vec, - pub last_names: Vec, - pub reserved_names: RwLock>, - pub users_by_id: RwLock>>>, pub games_by_user: RwLock>>, - pub online_users: RwLock>>>, + pub last_names: Vec, pub offline_users: RwLock>>>, + pub online_users: RwLock>>>, pub packs: CardPacks, pub packs_meta: CardPacksMeta, + pub reserved_names: RwLock>, + pub tx_broadcast: broadcast::Sender, + pub tx_game_handler: mpsc::Sender, + pub tx_incoming_message_handler: mpsc::Sender<(SocketAddr, Message)>, + pub tx_user_handler: mpsc::Sender, + pub users_by_id: RwLock>>>, + pub white_cards_by_id: HashMap>, } /// Card Set #[derive(Debug)] struct CardSet { - white: Option>>, black: Option>>, + white: Option>>, } /// Card Packs @@ -141,8 +141,8 @@ pub fn load_cards_from_json( // For global state let mut official: HashMap = HashMap::new(); - let mut unofficial: HashMap = HashMap::new(); let mut official_meta: Vec = vec![]; + let mut unofficial: HashMap = HashMap::new(); let mut unofficial_meta: Vec = vec![]; let mut white_cards_by_id = HashMap::>::new(); diff --git a/server/src/main.rs b/server/src/main.rs index ff764ab..6bc58be 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,5 +1,5 @@ use crate::game_handler::*; -use crate::message_handler::*; +use crate::incoming_message_handler::*; use crate::websocket::*; use anyhow::{Context, Result}; use axum::{routing::get, Router}; @@ -68,56 +68,56 @@ async fn main() -> Result<()> { }); // Set up state - let (broadcast_tx, _rx) = broadcast::channel(1000); - let (users_tx, mut users_rx) = mpsc::channel(1000); - let (messages_tx, mut messages_rx) = mpsc::channel(1000); - let (games_tx, mut games_rx) = mpsc::channel(1000); + let (packs, packs_meta, white_cards_by_id) = load_cards_from_json("data/cah-cards-full.json")?; + let (tx_broadcast, _rx_broadcast) = broadcast::channel(32); + let (tx_game_handler, mut rx_game_handler) = mpsc::channel(32); + let (tx_incoming_message_handler, mut rx_incoming_message_handler) = mpsc::channel(32); + let (tx_user_handler, mut rx_user_handler) = mpsc::channel(32); let first_names = load_names("data/first.txt")?; + let games_by_user = RwLock::new(HashMap::>::new()); let last_names = load_names("data/last.txt")?; + let offline_users = RwLock::new(HashMap::>>::new()); + let online_users = RwLock::new(HashMap::>>::new()); let reserved_names = RwLock::new(HashSet::::new()); let users_by_id = RwLock::new(HashMap::>>::new()); - let games_by_user = RwLock::new(HashMap::>::new()); - let online_users = RwLock::new(HashMap::>>::new()); - let offline_users = RwLock::new(HashMap::>>::new()); - let (packs, packs_meta, white_cards_by_id) = load_cards_from_json("data/cah-cards-full.json")?; let app_state = Arc::new(AppState { - white_cards_by_id, - broadcast_tx, - users_tx, - messages_tx, - games_tx, first_names, - last_names, - reserved_names, - users_by_id, games_by_user, - online_users, + last_names, offline_users, + online_users, packs, packs_meta, + reserved_names, + tx_broadcast, + tx_game_handler, + tx_incoming_message_handler, + tx_user_handler, + users_by_id, + white_cards_by_id, }); // Spawn task to handle incoming messages, also handles outging messages - let message_handler = MessageHandler::new(app_state.clone()); + let message_handler = IncomingMessageHandler::new(app_state.clone()); tokio::task::Builder::new() .name("Message Handler") .spawn(async move { - while let Some((addr, message)) = messages_rx.recv().await { + while let Some((addr, message)) = rx_incoming_message_handler.recv().await { message_handler.handle(addr, message).await } }) .unwrap(); // TODO: Restart handler threads if they crash - // TODO: Make an outgoing message handler handler? + // TODO: Make an outgoing message handler? // Spawn task to handle User things let user_handler = UserHandler::new(app_state.clone()); tokio::task::Builder::new() .name("User Handler") .spawn(async move { - while let Some(message) = users_rx.recv().await { + while let Some(message) = rx_user_handler.recv().await { user_handler.handle(message).await } }) @@ -128,7 +128,7 @@ async fn main() -> Result<()> { tokio::task::Builder::new() .name("Game Handler") .spawn(async move { - while let Some(message) = games_rx.recv().await { + while let Some(message) = rx_game_handler.recv().await { game_handler.handle(message).await } }) diff --git a/server/src/user_handler.rs b/server/src/user_handler.rs index 8bed24d..34dabcb 100644 --- a/server/src/user_handler.rs +++ b/server/src/user_handler.rs @@ -88,7 +88,7 @@ impl UserHandler { SendUserUpdate(message) => { let msg = to_string::(&message).unwrap(); tokio::spawn(async move { - if let Err(e) = tx.send(msg).await { + if let Err(e) = tx.send(Message::Text(msg)).await { tracing::error!("Error sending user update: {}", e) } }); @@ -96,7 +96,7 @@ impl UserHandler { SendChatMessage(message) => { let msg = to_string::(&message).unwrap(); tokio::spawn(async move { - if let Err(e) = tx.send(msg).await { + if let Err(e) = tx.send(Message::Text(msg)).await { tracing::error!("Error sending chat message: {}", e) } }); @@ -104,7 +104,7 @@ impl UserHandler { SendJudgeRound(message) => { let msg = to_string::(&message).unwrap(); tokio::spawn(async move { - if let Err(e) = tx.send(msg).await { + if let Err(e) = tx.send(Message::Text(msg)).await { tracing::error!("Error sending judge round: {}", e) } }); @@ -137,7 +137,7 @@ impl UserHandler { .insert(addr, new_user.clone()); // Hydrate client - let tx = self.state.games_tx.clone(); + let tx = self.state.tx_game_handler.clone(); let msg = GameHandlerMessage::BroadcastGamesUpdate(); tokio::spawn(async move { tx.send(msg).await }); let tx = user_tx.clone(); @@ -146,13 +146,13 @@ impl UserHandler { // Broadcast new user's existence // TODO: this should probably be combined and sent as one - let tx = self.state.broadcast_tx.clone(); + let tx = self.state.tx_broadcast.clone(); let msg = meta_announce_user_join(&self.state, &addr); tokio::spawn(async move { tx.send(msg) }); self.broadcast_user_count(); - let tx = self.state.broadcast_tx.clone(); + let tx = self.state.tx_broadcast.clone(); let msg = meta_chat_update(&self.state); tokio::spawn(async move { tx.send(msg) }); @@ -164,7 +164,7 @@ impl UserHandler { /// Handle user login async fn login(&self, request: UserLogInRequest, addr: SocketAddr) { let username_max_len = 66; // This is the longest name the generator may produce right now - let broadcast_tx = self.state.broadcast_tx.clone(); + let broadcast_tx = self.state.tx_broadcast.clone(); let new_name; if request.username.len() > username_max_len { @@ -218,7 +218,7 @@ impl UserHandler { }; let tx = broadcast_tx.clone(); let msg = to_string(&ChatMessage { text: msg }).unwrap(); - tokio::spawn(async move { tx.send(msg) }); + tokio::spawn(async move { tx.send(Message::Text(msg)) }); } // Check if name is taken by an online user else if self @@ -266,7 +266,7 @@ impl UserHandler { }; let chat_message = to_string::(&ChatMessage { text: msg }).unwrap(); let tx = broadcast_tx.clone(); - tokio::spawn(async move { tx.send(chat_message) }); + tokio::spawn(async move { tx.send(Message::Text(chat_message)) }); } // Send the user their new name @@ -297,14 +297,14 @@ impl UserHandler { .unwrap() .to_vec(), ); - let tx = self.state.games_tx.clone(); + let tx = self.state.tx_game_handler.clone(); tokio::spawn(async move { tx.send(msg).await }); } } } // Send client updates - let tx = self.state.games_tx.clone(); + let tx = self.state.tx_game_handler.clone(); let msg = GameHandlerMessage::BroadcastGamesUpdate(); tokio::spawn(async move { tx.send(msg).await }); let tx = broadcast_tx.clone(); @@ -314,7 +314,7 @@ impl UserHandler { /// Broadcast updated user count fn broadcast_user_count(&self) { - let tx = self.state.broadcast_tx.clone(); + let tx = self.state.tx_broadcast.clone(); let online_users: u32 = self .state .online_users @@ -324,7 +324,7 @@ impl UserHandler { .try_into() .unwrap(); let msg = to_string(&ServerOnlineUsers { online_users }).unwrap(); - tokio::spawn(async move { tx.send(msg) }); + tokio::spawn(async move { tx.send(Message::Text(msg)) }); } /// Clean up after a user when they disconnect @@ -346,9 +346,9 @@ impl UserHandler { text: format!("{0} left.", &user_name), }; let chat_message = to_string::(&msg).unwrap(); - let tx = self.state.broadcast_tx.clone(); + let tx = self.state.tx_broadcast.clone(); tokio::spawn(async move { - if let Err(e) = tx.send(chat_message) { + if let Err(e) = tx.send(Message::Text(chat_message)) { tracing::error!("Error broadcasting user leave message: {}", e) } }); @@ -367,7 +367,7 @@ impl UserHandler { self.broadcast_user_count(); let msg = meta_chat_update(&self.state); - let tx = self.state.broadcast_tx.clone(); + let tx = self.state.tx_broadcast.clone(); tokio::spawn(async move { if let Err(e) = tx.send(msg) { tracing::error!("Error broadcasting chat update: {}", e) @@ -377,15 +377,17 @@ impl UserHandler { } /// Generate message to notify client of user changes -pub fn user_client_self_update(new_user: &Arc>) -> String { - to_string::(&UserUpdate { - username: new_user.read().unwrap().name.clone(), - }) - .unwrap() +pub fn user_client_self_update(new_user: &Arc>) -> Message { + Message::Text( + to_string::(&UserUpdate { + username: new_user.read().unwrap().name.clone(), + }) + .unwrap(), + ) } /// Generate chatroom metadata update -pub fn meta_chat_update(state: &Arc) -> String { +pub fn meta_chat_update(state: &Arc) -> Message { // TODO: this may get expensive if there are many users let mut names = vec![]; @@ -393,35 +395,39 @@ pub fn meta_chat_update(state: &Arc) -> String { names.push(user.1.read().unwrap().name.clone()); } - to_string::(&ChatUpdate { - room: "Lobby".to_string(), - users: names, - }) - .unwrap() + Message::Text( + to_string::(&ChatUpdate { + room: "Lobby".to_string(), + users: names, + }) + .unwrap(), + ) } /// Generate chatroom join announcement -pub fn meta_announce_user_join(state: &Arc, addr: &SocketAddr) -> String { +pub fn meta_announce_user_join(state: &Arc, addr: &SocketAddr) -> Message { let msg = format!("{} joined.", { if let Some(user) = state.online_users.read().unwrap().get(addr) { user.read().unwrap().name.clone() } else { - return Default::default(); + return Message::Text("Error".to_string()); } }); - to_string::(&ChatMessage { text: msg }).unwrap() + Message::Text(to_string::(&ChatMessage { text: msg }).unwrap()) } /// Generage cards meta message -pub fn meta_new_game_card_packs(state: &Arc) -> String { - to_string::(&state.packs_meta).unwrap() +pub fn meta_new_game_card_packs(state: &Arc) -> Message { + Message::Text(to_string::(&state.packs_meta).unwrap()) } /// Generate message-of-the-day server greeting -pub fn meta_motd() -> String { - to_string::(&ChatMessage { - text: "Greetings from the game server!".to_string(), - }) - .unwrap() +pub fn meta_motd() -> Message { + Message::Text( + to_string::(&ChatMessage { + text: "Greetings from the game server!".to_string(), + }) + .unwrap(), + ) } diff --git a/server/src/websocket.rs b/server/src/websocket.rs index 25a20b8..5edc66e 100644 --- a/server/src/websocket.rs +++ b/server/src/websocket.rs @@ -31,7 +31,7 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc, ad let (mut sender, mut receiver) = stream.split(); // Create channel for direct messages - let (dm_tx, mut dm_rx) = mpsc::channel(1000000); + let (dm_tx, mut dm_rx) = mpsc::channel::(32); let mut map = HashMap::new(); map.insert(addr, dm_tx.clone()); @@ -51,17 +51,17 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc, ad } } - let tx = state.users_tx.clone(); + let tx = state.tx_user_handler.clone(); let msg = UserHandlerMessage::NewUser(User::new(username, dm_tx.clone()), addr); tokio::spawn(async move { tx.send(msg).await.expect("User handler is down") }); // Subscribe to receive from global broadcast channel - let mut rx = state.broadcast_tx.subscribe(); + let mut rx = state.tx_broadcast.subscribe(); // Send messages to this client let mut send_task = tokio::spawn(async move { let mut broadcast = None; - let mut dm = None; + let mut dm: Option = None; loop { tokio::select! { b = rx.recv() => broadcast = Some(b.unwrap()), @@ -69,13 +69,13 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc, ad }; if let Some(msg) = &dm { - if sender.send(Message::Text(msg.to_string())).await.is_err() { + if sender.send(msg.to_owned()).await.is_err() { break; } else { dm = Option::None; } } else if let Some(msg) = &broadcast { - if sender.send(Message::Text(msg.to_string())).await.is_err() { + if sender.send(msg.to_owned()).await.is_err() { } else { broadcast = Option::None; } @@ -87,7 +87,7 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc, ad let mut recv_task = tokio::spawn(async move { while let Some(Ok(message)) = receiver.next().await { if let Err(e) = state - .messages_tx + .tx_incoming_message_handler .send((addr.clone(), message.clone())) .await { diff --git a/tools/socket_blaster/src/main.rs b/tools/socket_blaster/src/main.rs index 5f12bf7..f5a76ae 100644 --- a/tools/socket_blaster/src/main.rs +++ b/tools/socket_blaster/src/main.rs @@ -1,5 +1,3 @@ -use std::collections::HashSet; - use clap::{command, Command}; use lib::*; use serde_json::to_string; @@ -18,9 +16,9 @@ fn zombie_horde() { fn spam_games() { println!("Spamming game creation"); - let mut packs = HashSet::new(); + let mut packs = Vec::new(); for pack in 0..205 { - packs.insert(pack.to_string()); + packs.push(pack.to_string()); } let (mut socket, _) = connect("ws://127.0.0.1:3030/websocket").expect("Can't connect"); @@ -28,8 +26,8 @@ fn spam_games() { socket .send(Message::Text( to_string(&NewGameRequest { - name: "ligma".to_string(), - packs: packs.clone(), + game_name: "ligma".to_string(), + game_packs: packs.clone(), }) .unwrap(), ))