cleanup and get ready for bitcode

This commit is contained in:
Adam 2024-11-19 01:32:06 -05:00
parent 36032f5718
commit 1feb57f580
12 changed files with 216 additions and 303 deletions

182
Cargo.lock generated
View file

@ -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",

View file

@ -8,6 +8,7 @@ authors = ["Adam Doyle <adam@doordesk.net>"]
[dependencies]
# Cards
bitcode = "0"
lib = { workspace = true }
serde_json = "1"

View file

@ -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"

View file

@ -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<String>,
}
/// 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<WhiteCardMeta>,
}
/// Judge round
#[derive(Clone, Message, Serialize, Deserialize)]
#[derive(Clone, Encode, Decode, Serialize, Deserialize)]
pub struct JudgeRound {
#[prost(message, repeated, tag = "1")]
pub entries: Vec<JudgeEntry>,
}
/// 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<String>,
}
/// 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<GamePlayerMeta>,
#[prost(string, tag = "5")]
pub czar: String,
#[prost(bytes, tag = "6")]
pub packs: Vec<u8>,
#[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<BlackCardMeta>, // this has to be an option or prost gets cranky
#[prost(message, repeated, tag = "2")]
pub white: Vec<WhiteCardMeta>,
}
/// 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<u8>,
}
/// 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<CardPackMeta>,
#[prost(message, repeated, tag = "2")]
pub unofficial_meta: Vec<CardPackMeta>,
}
/// Games update
#[derive(Message, Serialize, Deserialize)]
#[derive(Encode, Decode, Serialize, Deserialize)]
pub struct GamesUpdate {
#[prost(message, repeated, tag = "1")]
pub games: Vec<GameBrowserMeta>,
}
/// 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<String>,
}
/// 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<String>,
}

View file

@ -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"

View file

@ -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::<Vec<GameBrowserMeta>>();
let msg = to_string::<GamesUpdate>(&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);
}
});

View file

@ -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<AppState>,
}
impl MessageHandler {
/// Returns new MessageHandler object
impl IncomingMessageHandler {
/// Returns new IncomingMessageHandler object
pub fn new(state: Arc<AppState>) -> Self {
MessageHandler { state }
IncomingMessageHandler { state }
}
/// Handles incoming messages
@ -34,9 +34,10 @@ impl MessageHandler {
}
// Broadcast incoming chat message
let broadcast_message =
to_string::<ChatMessage>(&ChatMessage { text: msg }).unwrap();
let tx = self.state.broadcast_tx.clone();
let broadcast_message = Message::Text(
to_string::<ChatMessage>(&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::<UserLogInRequest>(&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::<NewGameRequest>(&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::<GameJoinRequest>(&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::<GameDeleteRequest>(&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<CloseFrame>, 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

View file

@ -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<String>,
pub tx: Sender<Message>,
}
impl User {
/// Create a new user object from incoming data
pub fn new(name: String, tx: Sender<String>) -> User {
pub fn new(name: String, tx: Sender<Message>) -> 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<Vec<String>> {
// Our shared state
pub struct AppState {
pub white_cards_by_id: HashMap<String, Arc<CardWhiteWithID>>,
pub broadcast_tx: broadcast::Sender<String>,
pub users_tx: mpsc::Sender<UserHandlerMessage>,
pub messages_tx: mpsc::Sender<(SocketAddr, Message)>,
pub games_tx: mpsc::Sender<GameHandlerMessage>,
pub first_names: Vec<String>,
pub last_names: Vec<String>,
pub reserved_names: RwLock<HashSet<String>>,
pub users_by_id: RwLock<HashMap<String, Arc<RwLock<User>>>>,
pub games_by_user: RwLock<HashMap<String, Vec<String>>>,
pub online_users: RwLock<HashMap<SocketAddr, Arc<RwLock<User>>>>,
pub last_names: Vec<String>,
pub offline_users: RwLock<HashMap<String, Arc<RwLock<User>>>>,
pub online_users: RwLock<HashMap<SocketAddr, Arc<RwLock<User>>>>,
pub packs: CardPacks,
pub packs_meta: CardPacksMeta,
pub reserved_names: RwLock<HashSet<String>>,
pub tx_broadcast: broadcast::Sender<Message>,
pub tx_game_handler: mpsc::Sender<GameHandlerMessage>,
pub tx_incoming_message_handler: mpsc::Sender<(SocketAddr, Message)>,
pub tx_user_handler: mpsc::Sender<UserHandlerMessage>,
pub users_by_id: RwLock<HashMap<String, Arc<RwLock<User>>>>,
pub white_cards_by_id: HashMap<String, Arc<CardWhiteWithID>>,
}
/// Card Set
#[derive(Debug)]
struct CardSet {
white: Option<Vec<Arc<CardWhiteWithID>>>,
black: Option<Vec<Arc<CardBlackWithID>>>,
white: Option<Vec<Arc<CardWhiteWithID>>>,
}
/// Card Packs
@ -141,8 +141,8 @@ pub fn load_cards_from_json(
// For global state
let mut official: HashMap<u8, CardSet> = HashMap::new();
let mut unofficial: HashMap<u8, CardSet> = HashMap::new();
let mut official_meta: Vec<CardPackMeta> = vec![];
let mut unofficial: HashMap<u8, CardSet> = HashMap::new();
let mut unofficial_meta: Vec<CardPackMeta> = vec![];
let mut white_cards_by_id = HashMap::<String, Arc<CardWhiteWithID>>::new();

View file

@ -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::<String, Vec<String>>::new());
let last_names = load_names("data/last.txt")?;
let offline_users = RwLock::new(HashMap::<String, Arc<RwLock<User>>>::new());
let online_users = RwLock::new(HashMap::<SocketAddr, Arc<RwLock<User>>>::new());
let reserved_names = RwLock::new(HashSet::<String>::new());
let users_by_id = RwLock::new(HashMap::<String, Arc<RwLock<User>>>::new());
let games_by_user = RwLock::new(HashMap::<String, Vec<String>>::new());
let online_users = RwLock::new(HashMap::<SocketAddr, Arc<RwLock<User>>>::new());
let offline_users = RwLock::new(HashMap::<String, Arc<RwLock<User>>>::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
}
})

View file

@ -88,7 +88,7 @@ impl UserHandler {
SendUserUpdate(message) => {
let msg = to_string::<UserUpdate>(&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::<ChatMessage>(&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::<JudgeRound>(&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>(&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::<ChatMessage>(&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<RwLock<User>>) -> String {
to_string::<UserUpdate>(&UserUpdate {
username: new_user.read().unwrap().name.clone(),
})
.unwrap()
pub fn user_client_self_update(new_user: &Arc<RwLock<User>>) -> Message {
Message::Text(
to_string::<UserUpdate>(&UserUpdate {
username: new_user.read().unwrap().name.clone(),
})
.unwrap(),
)
}
/// Generate chatroom metadata update
pub fn meta_chat_update(state: &Arc<AppState>) -> String {
pub fn meta_chat_update(state: &Arc<AppState>) -> 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<AppState>) -> String {
names.push(user.1.read().unwrap().name.clone());
}
to_string::<ChatUpdate>(&ChatUpdate {
room: "Lobby".to_string(),
users: names,
})
.unwrap()
Message::Text(
to_string::<ChatUpdate>(&ChatUpdate {
room: "Lobby".to_string(),
users: names,
})
.unwrap(),
)
}
/// Generate chatroom join announcement
pub fn meta_announce_user_join(state: &Arc<AppState>, addr: &SocketAddr) -> String {
pub fn meta_announce_user_join(state: &Arc<AppState>, 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>(&ChatMessage { text: msg }).unwrap()
Message::Text(to_string::<ChatMessage>(&ChatMessage { text: msg }).unwrap())
}
/// Generage cards meta message
pub fn meta_new_game_card_packs(state: &Arc<AppState>) -> String {
to_string::<CardPacksMeta>(&state.packs_meta).unwrap()
pub fn meta_new_game_card_packs(state: &Arc<AppState>) -> Message {
Message::Text(to_string::<CardPacksMeta>(&state.packs_meta).unwrap())
}
/// Generate message-of-the-day server greeting
pub fn meta_motd() -> String {
to_string::<ChatMessage>(&ChatMessage {
text: "Greetings from the game server!".to_string(),
})
.unwrap()
pub fn meta_motd() -> Message {
Message::Text(
to_string::<ChatMessage>(&ChatMessage {
text: "Greetings from the game server!".to_string(),
})
.unwrap(),
)
}

View file

@ -31,7 +31,7 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc<AppState>, 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::<Message>(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<AppState>, 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<Message> = 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<AppState>, 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<AppState>, 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
{

View file

@ -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(),
))