#![feature(if_let_guard)] use crate::game::*; use crate::game_handler::*; use anyhow::{Context, Result}; use axum::extract::ws::Message; use lib::*; use serde::Deserialize; use std::{ collections::{HashMap, HashSet}, fs::{read_to_string, File}, io::{BufRead, BufReader}, net::SocketAddr, sync::{Arc, RwLock}, }; use tokio::sync::mpsc::Sender; use tokio::sync::{broadcast, mpsc}; use user_handler::*; use uuid::Uuid; pub mod game; pub mod game_handler; pub mod message_handler; pub mod user_handler; pub mod websocket; /// User #[derive(Debug)] pub struct User { pub uuid: String, pub name: String, pub tx: Sender, } impl User { /// Create a new user object from incoming data pub fn new(name: String, tx: Sender) -> User { User { uuid: Uuid::now_v7().to_string(), name, tx, } } pub fn change_name(&mut self, new_name: String) { self.name = new_name; } } /// 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 { 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 offline_users: RwLock>>>, pub packs: CardPacks, pub packs_meta: CardPacksMeta, } /// Card Set #[derive(Debug)] struct CardSet { white: Option>>, black: Option>>, } /// Card Packs #[derive(Debug)] pub struct CardPacks { official: HashMap, unofficial: HashMap, } /// A raw white card as it exists in the source json #[derive(Debug, Deserialize)] struct CardWhiteFromJSON { /// Card text text: String, /// ID of the pack it came from pack: u8, } /// A raw black card as it exists in the source json #[derive(Debug, Deserialize)] struct CardBlackFromJSON { /// Card text text: String, /// Amount of cards to submit for judging pick: u8, /// ID of the pack it came from pack: u8, } /// A card pack #[derive(Debug, Deserialize)] struct CardPack { /// Name of the pack name: String, /// Whether or not this is an official card pack official: bool, /// White card data white: Option>, /// Black card data black: Option>, } /// Parse json for card data pub fn load_cards_from_json( path: &str, ) -> Result<( CardPacks, CardPacksMeta, HashMap>, )> { // Load in json 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."))?; // For global state let mut official: HashMap = HashMap::new(); let mut unofficial: HashMap = HashMap::new(); let mut official_meta: Vec = vec![]; let mut unofficial_meta: Vec = vec![]; let mut white_cards_by_id = HashMap::>::new(); // Unpack the json for sets 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; // Process white cards if there are any if let Some(ref white) = sets.white { num_white = white.len(); if num_white > 0 { pack = Some(white[0].pack); let mut white_buf = vec![]; for card in sets.white.unwrap() { let uuid = Uuid::now_v7(); let new_card = Arc::new(CardWhiteWithID { uuid, text: card.text, }); white_cards_by_id.insert(uuid.to_string(), new_card.clone()); white_buf.push(new_card); } newset.white = Some(white_buf); } } // Process black cards if there are any if let Some(ref black) = sets.black { num_black = black.len(); if num_black > 0 { pack = Some(black[0].pack); let mut black_buf = vec![]; for card in sets.black.unwrap() { black_buf.push(Arc::new(CardBlackWithID { uuid: Uuid::now_v7(), text: card.text, pick: card.pick, })); } newset.black = Some(black_buf); } } // Start repackaging let meta = CardPackMeta { name: sets.name, pack: pack.expect("No card pack number!").to_string(), num_white, num_black, }; if sets.official { official_meta.push(meta); official.insert(pack.unwrap(), newset); } else { unofficial_meta.push(meta); unofficial.insert(pack.unwrap(), newset); } } // These are now the largest size they should ever be official.shrink_to_fit(); unofficial.shrink_to_fit(); official_meta.shrink_to_fit(); unofficial_meta.shrink_to_fit(); // Package for export let packs = CardPacks { official, unofficial, }; let packs_meta = CardPacksMeta { official_meta, unofficial_meta, }; Ok((packs, packs_meta, white_cards_by_id)) }