diff --git a/client/src/components/auth.rs b/client/src/components/auth.rs index 1c3cdde..0ee9eef 100644 --- a/client/src/components/auth.rs +++ b/client/src/components/auth.rs @@ -1,7 +1,7 @@ use crate::components::websocket::WebSocketContext; use html::Input; use leptos::*; -use lib::models::*; +use lib::*; use serde_json::to_string; #[component] diff --git a/client/src/components/browser.rs b/client/src/components/browser.rs index b980692..69b852b 100644 --- a/client/src/components/browser.rs +++ b/client/src/components/browser.rs @@ -2,7 +2,7 @@ use crate::components::websocket::WebSocketContext; use leptos::html::Input; use leptos::*; use leptos_use::core::ConnectionReadyState; -use lib::models::*; +use lib::*; use serde_json::to_string; use std::collections::BTreeSet; diff --git a/client/src/components/chat.rs b/client/src/components/chat.rs index da4e030..29412e0 100644 --- a/client/src/components/chat.rs +++ b/client/src/components/chat.rs @@ -2,7 +2,7 @@ use crate::components::websocket::WebSocketContext; use html::{Input, Textarea}; use leptos::*; use leptos_use::core::ConnectionReadyState; -use lib::models::*; +use lib::*; use serde_json::to_string; #[component] diff --git a/client/src/components/debug.rs b/client/src/components/debug.rs index 9fb072f..6ab38d8 100644 --- a/client/src/components/debug.rs +++ b/client/src/components/debug.rs @@ -1,7 +1,7 @@ use crate::components::websocket::WebSocketContext; use leptos::*; use leptos_use::core::ConnectionReadyState; -use lib::models::*; +use lib::*; #[component] pub fn Debug() -> impl IntoView { diff --git a/client/src/components/websocket.rs b/client/src/components/websocket.rs index 244fdd9..d10e415 100644 --- a/client/src/components/websocket.rs +++ b/client/src/components/websocket.rs @@ -1,6 +1,6 @@ use leptos::*; use leptos_use::{core::ConnectionReadyState, use_websocket, UseWebsocketReturn}; -use lib::models::*; +use lib::*; use serde_json::from_str; use std::rc::Rc; @@ -35,15 +35,15 @@ impl WebSocketContext { (self.send)(message) } - #[inline(always)] - pub fn open(&self) { - (self.open)() - } - - #[inline(always)] - pub fn close(&self) { - (self.close)() - } + // #[inline(always)] + // pub fn open(&self) { + // (self.open)() + // } + // + // #[inline(always)] + // pub fn close(&self) { + // (self.close)() + // } } #[component] diff --git a/lib/src/game_master.rs b/lib/src/game_master.rs deleted file mode 100644 index c03a785..0000000 --- a/lib/src/game_master.rs +++ /dev/null @@ -1,129 +0,0 @@ -use anyhow::Result; -use rand::prelude::IteratorRandom; -use rand::thread_rng; -use std::sync::{Arc, RwLock}; - -use crate::models::*; - -impl Game { - /// Build game decks from input data for game start. - /// This should only run once and at startup. - fn _build_decks(&mut self, cards_json: Vec) -> Result<()> { - for pack in cards_json { - if let Some(white) = pack.white { - self.white.extend(white) - } - if let Some(black) = pack.black { - self.black.extend(black) - } - } - - Ok(()) - } - - pub fn new(request: NewGameManifest) -> Result { - let mut game = Game { - ..Default::default() - }; - tracing::debug!( - "Creating game {} with {} as host", - &request.name, - request.host.read().unwrap().name - ); - game.name = request.name; - game.host = request.host.clone(); - - // game.build_decks(request.packs)?; - game.create_player(request.host)?; - game.deal_black()?; - - Ok(game) - } - - // pub fn join(request:GameJoinRequest) - - /// Log counts of current drawable cards - /// For testing - pub fn deck_counts(&self) { - tracing::debug!( - "Deck Counts:\n {} White cards\n {} Black cards", - self.white.len(), - self.black.len() - ); - } - - /// Draw one white card at random from play deck. - fn draw_one_white(&mut self) -> Result { - let deck = &mut self.white; - - // this feels sloppy - if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { - Ok(deck.swap_remove(index)) - } else { - Ok(CardWhite { - text: "Error.\n\nbtw if you see this tell me I'm lazy :)".to_string(), - pack: 0, - }) - } - } - - /// Draw one black card at random from play deck. - fn draw_one_black(&mut self) -> Result { - let deck = &mut self.black; - - // this feels sloppy - if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { - Ok(deck.swap_remove(index)) - } else { - Ok(CardBlack { - text: "Error.\n\nbtw if you see this tell me I'm lazy :)".to_string(), - pick: 0, - pack: 0, - }) - } - } - - /// Deal a black card and use it for the current round - fn deal_black(&mut self) -> Result<()> { - self.current_black = Some(self.draw_one_black()?); - - Ok(()) - } - - /// Create a new player and add them to the game. - pub fn create_player(&mut self, user: Arc>) -> Result<()> { - let mut new_player = Player { - user: user.clone(), - white: vec![], - black: vec![], - }; - - let new_player_name = user.read().unwrap().name.clone(); - tracing::debug!("Creating player for {}", &new_player_name); - - let mut hand_buf = vec![]; - for _ in 0..10 { - hand_buf.push(self.draw_one_white()?); - } - tracing::debug!("Dealing hand to {}", &new_player_name); - - new_player.white.extend(hand_buf); - - self.players.push(new_player); - - Ok(()) - } - - pub fn game_start(&mut self) -> Result<()> { - self.game_active = true; - tracing::debug!("Game Active!"); - - if let Some(black) = &self.current_black { - tracing::debug!("{}", black.text); - } else { - tracing::debug!("YOU DONE FUCKED UP (no current black card)"); - } - - Ok(()) - } -} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 5b508f2..07a7242 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,2 +1,63 @@ -pub mod game_master; -pub mod models; +use serde::{Deserialize, Serialize}; + +/// Card Pack Meta +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CardPackMeta { + pub name: String, + pub pack: u8, + pub num_white: usize, + pub num_black: usize, +} + +/// Card Packs Meta +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CardPacksMeta { + pub official_meta: Vec, + pub unofficial_meta: Vec, +} + +/// Games update +#[derive(Serialize, Deserialize, Debug)] +pub struct GamesUpdate { + pub games: Vec, +} + +/// Chat update +#[derive(Serialize, Deserialize, Debug)] +pub struct ChatUpdate { + pub room: String, + pub users: Vec, +} + +/// User login request (to change name) +#[derive(Serialize, Deserialize, Debug)] +pub struct UserLogIn { + pub username: String, +} + +/// Response to user name change containing new name +#[derive(Serialize, Deserialize, Debug)] +pub struct UserUpdate { + pub username: String, +} + +/// Chat message +#[derive(Serialize, Deserialize, Debug)] +pub struct ChatMessage { + pub text: String, +} + +/// Server state summary +#[derive(Serialize, Deserialize, Debug)] +pub struct ServerStateSummary { + pub online_users: usize, + pub active_games: usize, +} + +/// New game request structure +#[derive(Debug, Serialize, Deserialize)] +pub struct NewGameRequest { + /// Game name + pub name: String, + pub packs: Vec, +} diff --git a/lib/src/models.rs b/lib/src/models.rs deleted file mode 100644 index e6e5e0f..0000000 --- a/lib/src/models.rs +++ /dev/null @@ -1,190 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - sync::{Arc, RwLock}, -}; - -/// Card Set -#[derive(Debug)] -pub struct CardSet { - pub white: Option>, - pub black: Option>, -} - -/// Card Pack Meta -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CardPackMeta { - pub name: String, - pub pack: u8, - pub num_white: usize, - pub num_black: usize, -} -/// Card Packs Meta -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CardPacksMeta { - pub official_meta: Vec, - pub unofficial_meta: Vec, -} -/// Card Packs Meta -#[derive(Debug)] -pub struct CardPacks { - pub official: HashMap, - pub unofficial: HashMap, -} - -/// Games update -#[derive(Serialize, Deserialize, Debug)] -pub struct GamesUpdate { - pub games: Vec, -} - -/// Chat update -#[derive(Serialize, Deserialize, Debug)] -pub struct ChatUpdate { - pub room: String, - pub users: Vec, -} - -/// User update -#[derive(Serialize, Deserialize, Debug)] -pub struct UserUpdate { - pub username: String, -} - -/// User login -#[derive(Serialize, Deserialize, Debug)] -pub struct UserLogIn { - pub username: String, -} - -/// Chat message -#[derive(Serialize, Deserialize, Debug)] -pub struct ChatMessage { - pub text: String, -} - -/// Server state summary -#[derive(Serialize, Deserialize, Debug)] -pub struct ServerStateSummary { - pub online_users: usize, - pub active_games: usize, -} - -/// User -#[derive(Default, Debug, Eq, PartialEq, Hash)] -pub struct User { - pub name: String, -} - -impl User { - pub fn change_name(&mut self, new_name: String) { - self.name = new_name; - } -} - -/// New game request structure -#[derive(Debug, Serialize, Deserialize)] -pub struct NewGameRequest { - /// Game name - pub name: String, - pub packs: Vec, -} - -/// New game request structure -#[derive(Debug)] -pub struct NewGameManifest { - /// Game name - pub name: String, - /// Game host - pub host: Arc>, -} - -/// Game join request structure -pub struct GameJoinRequest { - /// Game id - pub id: u8, // increase later - /// Game password - pub password: Option, - /// Player info - pub player: Player, -} - -/// A white card -#[derive(Debug, Serialize, Deserialize)] -pub struct CardWhite { - /// Card text - pub text: String, - /// ID of the pack it came from - pub pack: u8, -} - -/// A black card -#[derive(Debug, Serialize, Deserialize)] -pub struct CardBlack { - /// Card text - pub text: String, - /// Amount of cards to submit for judging - pub pick: u8, - /// ID of the pack it came from - pub pack: u8, -} - -/// A card pack -#[derive(Debug, Serialize, Deserialize)] -pub struct CardPack { - /// Name of the pack - pub name: String, - /// Whether or not this is an official card pack - pub official: bool, - /// White card data - pub white: Option>, - /// Black card data - pub black: Option>, -} - -/// Player roles -#[derive(Debug, Serialize, Deserialize)] -pub enum PlayerRole { - /// Player is host - Host, - /// Player is a player in a game where another player is host - Player, - /// Player is just spectating - Spectator, -} - -/// A struct that represents a player -#[derive(Debug)] -pub struct Player { - /// Player's username - pub user: Arc>, - /// The player's hand - pub white: Vec, - /// The player's wins - pub black: Vec, -} - -/// The game master -#[derive(Default, Debug)] -pub struct Game { - /// The name of the game - pub name: String, - /// The host user of the game - pub host: Arc>, - /// White draw pile - pub white: Vec, - /// Black draw pile - pub black: Vec, - /// White discard pile - pub white_discard: Vec, - /// Black discard pile - pub black_discard: Vec, - /// Indicates game active/game over - pub game_active: bool, - /// List of current players - pub players: Vec, - // /// Reference to current card czar - // czar: &Player, - /// Black card for the current round - pub current_black: Option, -} diff --git a/server/src/api.rs b/server/src/api.rs index aa16920..bdb5a5a 100644 --- a/server/src/api.rs +++ b/server/src/api.rs @@ -9,9 +9,10 @@ use axum::{ }; use futures::stream::SplitSink; use futures::{SinkExt, StreamExt}; -use lib::models::*; +use lib::*; use rand::seq::SliceRandom; use serde_json::to_string; +use server::*; use std::{ net::SocketAddr, sync::{Arc, RwLock}, diff --git a/server/src/lib.rs b/server/src/lib.rs new file mode 100644 index 0000000..51178eb --- /dev/null +++ b/server/src/lib.rs @@ -0,0 +1,354 @@ +use anyhow::{Context, Result}; +use lib::*; +use rand::prelude::IteratorRandom; +use rand::thread_rng; +use serde::Deserialize; +use std::{ + collections::HashMap, + fs::{read_to_string, File}, + io::{BufRead, BufReader}, + net::SocketAddr, + sync::{Arc, RwLock}, +}; +use tokio::sync::broadcast; + +/// Card Set +#[derive(Debug)] +pub struct CardSet { + pub white: Option>, + pub black: Option>, +} + +/// Card Packs +#[derive(Debug)] +pub struct CardPacks { + pub official: HashMap, + pub unofficial: HashMap, +} + +/// A white card +#[derive(Debug, Deserialize)] +pub struct CardWhite { + /// Card text + pub text: String, + /// ID of the pack it came from + pub pack: u8, +} + +/// A black card +#[derive(Debug, Deserialize)] +pub struct CardBlack { + /// Card text + pub text: String, + /// Amount of cards to submit for judging + pub pick: u8, + /// ID of the pack it came from + pub pack: u8, +} + +/// A card pack +#[derive(Debug, Deserialize)] +pub struct CardPack { + /// Name of the pack + pub name: String, + /// Whether or not this is an official card pack + pub official: bool, + /// White card data + pub white: Option>, + /// Black card data + pub black: Option>, +} + +/// New game request structure +#[derive(Debug)] +pub struct NewGameManifest { + /// Game name + pub name: String, + /// Game host + pub host: Arc>, +} + +/// User +#[derive(Default, Debug, Eq, PartialEq, Hash)] +pub struct User { + pub name: String, +} + +impl User { + pub fn change_name(&mut self, new_name: String) { + self.name = new_name; + } +} + +/// A struct that represents a player +#[derive(Debug)] +pub struct Player { + /// Player's username + pub user: Arc>, + /// The player's hand + pub white: Vec, + /// The player's wins + pub black: Vec, +} + +/// The game master +#[derive(Default, Debug)] +pub struct Game { + /// The name of the game + pub name: String, + /// The host user of the game + pub host: Arc>, + /// White draw pile + pub white: Vec, + /// Black draw pile + pub black: Vec, + /// White discard pile + pub white_discard: Vec, + /// Black discard pile + pub black_discard: Vec, + /// Indicates game active/game over + pub game_active: bool, + /// List of current players + pub players: Vec, + // /// Reference to current card czar + // czar: &Player, + /// Black card for the current round + pub current_black: Option, +} + +impl Game { + /// Build game decks from input data for game start. + /// This should only run once and at startup. + fn _build_decks(&mut self, cards_json: Vec) -> Result<()> { + for pack in cards_json { + if let Some(white) = pack.white { + self.white.extend(white) + } + if let Some(black) = pack.black { + self.black.extend(black) + } + } + + Ok(()) + } + + pub fn new(request: NewGameManifest) -> Result { + let mut game = Game { + ..Default::default() + }; + tracing::debug!( + "Creating game {} with {} as host", + &request.name, + request.host.read().unwrap().name + ); + game.name = request.name; + game.host = request.host.clone(); + + // game.build_decks(request.packs)?; + game.create_player(request.host)?; + game.deal_black()?; + + Ok(game) + } + + // pub fn join(request:GameJoinRequest) + + /// Log counts of current drawable cards + /// For testing + pub fn deck_counts(&self) { + tracing::debug!( + "Deck Counts:\n {} White cards\n {} Black cards", + self.white.len(), + self.black.len() + ); + } + + /// Draw one white card at random from play deck. + fn draw_one_white(&mut self) -> Result { + let deck = &mut self.white; + + // this feels sloppy + if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { + Ok(deck.swap_remove(index)) + } else { + Ok(CardWhite { + text: "Error.\n\nbtw if you see this tell me I'm lazy :)".to_string(), + pack: 0, + }) + } + } + + /// Draw one black card at random from play deck. + fn draw_one_black(&mut self) -> Result { + let deck = &mut self.black; + + // this feels sloppy + if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { + Ok(deck.swap_remove(index)) + } else { + Ok(CardBlack { + text: "Error.\n\nbtw if you see this tell me I'm lazy :)".to_string(), + pick: 0, + pack: 0, + }) + } + } + + /// Deal a black card and use it for the current round + fn deal_black(&mut self) -> Result<()> { + self.current_black = Some(self.draw_one_black()?); + + Ok(()) + } + + /// Create a new player and add them to the game. + pub fn create_player(&mut self, user: Arc>) -> Result<()> { + let mut new_player = Player { + user: user.clone(), + white: vec![], + black: vec![], + }; + + let new_player_name = user.read().unwrap().name.clone(); + tracing::debug!("Creating player for {}", &new_player_name); + + let mut hand_buf = vec![]; + for _ in 0..10 { + hand_buf.push(self.draw_one_white()?); + } + tracing::debug!("Dealing hand to {}", &new_player_name); + + new_player.white.extend(hand_buf); + + self.players.push(new_player); + + Ok(()) + } + + pub fn game_start(&mut self) -> Result<()> { + self.game_active = true; + tracing::debug!("Game Active!"); + + if let Some(black) = &self.current_black { + tracing::debug!("{}", black.text); + } else { + tracing::debug!("YOU DONE FUCKED UP (no current black card)"); + } + + Ok(()) + } +} + +/// Parse json for card data +pub fn load_cards_from_json(path: &str) -> Result<(CardPacks, CardPacksMeta)> { + let data: String = + read_to_string(path).with_context(|| format!("Invalid JSON path: \"{}\"", path))?; + let jayson: Vec = serde_json::from_str(&data) + .with_context(|| format!("The contents of \"{path}\" is not valid JSON."))?; + + let mut official: HashMap = HashMap::new(); + let mut unofficial: HashMap = HashMap::new(); + + let mut official_meta: Vec = vec![]; + let mut unofficial_meta: Vec = vec![]; + + for set in jayson { + let mut num_white = 0; + let mut num_black = 0; + + let mut newset = CardSet { + white: Option::None, + black: Option::None, + }; + + // No safe default for this so make it an Option + let mut pack: Option = Option::None; + + if let Some(ref white) = set.white { + num_white = white.len(); + if num_white > 0 { + pack = Some(white[0].pack); + newset.white = Some(set.white.unwrap()); + } + } + + if let Some(ref black) = set.black { + num_black = black.len(); + if num_black > 0 { + pack = Some(black[0].pack); + newset.black = Some(set.black.unwrap()); + } + } + + let meta = CardPackMeta { + name: set.name, + pack: pack.expect("No card pack number!"), + num_white, + num_black, + }; + + if set.official { + official_meta.push(meta); + official.insert(pack.unwrap(), newset); + } else { + unofficial_meta.push(meta); + unofficial.insert(pack.unwrap(), newset); + } + } + + official.shrink_to_fit(); + unofficial.shrink_to_fit(); + + official_meta.shrink_to_fit(); + unofficial_meta.shrink_to_fit(); + + tracing::debug!("{} official", official.len()); + tracing::debug!("{} official meta", official_meta.len()); + tracing::debug!("{} unofficial", unofficial.len()); + tracing::debug!("{} unofficial meta", unofficial_meta.len()); + tracing::debug!("{:#?}", official_meta[0]); + tracing::debug!("{:#?}", unofficial_meta[0]); + + let packs = CardPacks { + official, + unofficial, + }; + + let packs_meta = CardPacksMeta { + official_meta, + unofficial_meta, + }; + + Ok((packs, packs_meta)) +} + +/// Parse name list +pub fn load_names(path: &str) -> Result> { + let f = File::open(path).with_context(|| format!("Invalid names path: \"{}\"", path))?; + let f = BufReader::new(f); + + let mut buf = vec![]; + + for line in f.lines() { + buf.push(line?) + } + + Ok(buf) +} + +// Our shared state +pub struct AppState { + // We require unique usernames. This tracks which usernames have been taken. + pub online_users: RwLock>>>, + pub offline_users: RwLock>>>, + // Channel used to send messages to all connected clients. + pub tx: broadcast::Sender, + // Master card decks + pub packs: CardPacks, + pub packs_meta: CardPacksMeta, + // Games list + pub games: RwLock>, + // chatrooms: Mutex>>, + pub first_names: Vec, + pub last_names: Vec, +} diff --git a/server/src/main.rs b/server/src/main.rs index aa9f8c9..48beb13 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -2,11 +2,8 @@ use anyhow::{Context, Result}; use axum::{routing::get, Router}; -use lib::models::*; use std::{ collections::HashMap, - fs::{read_to_string, File}, - io::{BufRead, BufReader}, net::SocketAddr, sync::{Arc, RwLock}, }; @@ -15,120 +12,7 @@ use tower_http::services::ServeDir; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; pub mod api; use crate::api::*; - -/// Parse json for card data -fn load_cards_from_json(path: &str) -> Result<(CardPacks, CardPacksMeta)> { - let data: String = - read_to_string(path).with_context(|| format!("Invalid JSON path: \"{}\"", path))?; - let jayson: Vec = serde_json::from_str(&data) - .with_context(|| format!("The contents of \"{path}\" is not valid JSON."))?; - - let mut official: HashMap = HashMap::new(); - let mut unofficial: HashMap = HashMap::new(); - - let mut official_meta: Vec = vec![]; - let mut unofficial_meta: Vec = vec![]; - - for set in jayson { - let mut num_white = 0; - let mut num_black = 0; - - let mut newset = CardSet { - white: Option::None, - black: Option::None, - }; - - // No safe default for this so make it an Option - let mut pack: Option = Option::None; - - if let Some(ref white) = set.white { - num_white = white.len(); - if num_white > 0 { - pack = Some(white[0].pack); - newset.white = Some(set.white.unwrap()); - } - } - - if let Some(ref black) = set.black { - num_black = black.len(); - if num_black > 0 { - pack = Some(black[0].pack); - newset.black = Some(set.black.unwrap()); - } - } - - let meta = CardPackMeta { - name: set.name, - pack: pack.expect("No card pack number!"), - num_white, - num_black, - }; - - if set.official { - official_meta.push(meta); - official.insert(pack.unwrap(), newset); - } else { - unofficial_meta.push(meta); - unofficial.insert(pack.unwrap(), newset); - } - } - - official.shrink_to_fit(); - unofficial.shrink_to_fit(); - - official_meta.shrink_to_fit(); - unofficial_meta.shrink_to_fit(); - - tracing::debug!("{} official", official.len()); - tracing::debug!("{} official meta", official_meta.len()); - tracing::debug!("{} unofficial", unofficial.len()); - tracing::debug!("{} unofficial meta", unofficial_meta.len()); - tracing::debug!("{:#?}", official_meta[0]); - tracing::debug!("{:#?}", unofficial_meta[0]); - - let packs = CardPacks { - official, - unofficial, - }; - - let packs_meta = CardPacksMeta { - official_meta, - unofficial_meta, - }; - - Ok((packs, packs_meta)) -} - -/// Parse name list -fn load_names(path: &str) -> Result> { - let f = File::open(path).with_context(|| format!("Invalid names path: \"{}\"", path))?; - let f = BufReader::new(f); - - let mut buf = vec![]; - - for line in f.lines() { - buf.push(line?) - } - - Ok(buf) -} - -// Our shared state -pub struct AppState { - // We require unique usernames. This tracks which usernames have been taken. - online_users: RwLock>>>, - offline_users: RwLock>>>, - // Channel used to send messages to all connected clients. - tx: broadcast::Sender, - // Master card decks - packs: CardPacks, - packs_meta: CardPacksMeta, - // Games list - games: RwLock>, - // chatrooms: Mutex>>, - first_names: Vec, - last_names: Vec, -} +use server::*; #[tokio::main] async fn main() -> Result<()> {