cards/server/src/lib.rs

234 lines
6.3 KiB
Rust

#![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<String>,
}
impl User {
/// Create a new user object from incoming data
pub fn new(name: String, tx: Sender<String>) -> 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<Vec<String>> {
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<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 offline_users: RwLock<HashMap<String, Arc<RwLock<User>>>>,
pub packs: CardPacks,
pub packs_meta: CardPacksMeta,
}
/// Card Set
#[derive(Debug)]
struct CardSet {
white: Option<Vec<Arc<CardWhiteWithID>>>,
black: Option<Vec<Arc<CardBlackWithID>>>,
}
/// Card Packs
#[derive(Debug)]
pub struct CardPacks {
official: HashMap<u8, CardSet>,
unofficial: HashMap<u8, CardSet>,
}
/// 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<Vec<CardWhiteFromJSON>>,
/// Black card data
black: Option<Vec<CardBlackFromJSON>>,
}
/// Parse json for card data
pub fn load_cards_from_json(
path: &str,
) -> Result<(
CardPacks,
CardPacksMeta,
HashMap<String, Arc<CardWhiteWithID>>,
)> {
// Load in json
let data: String =
read_to_string(path).with_context(|| format!("Invalid JSON path: \"{}\"", path))?;
let jayson: Vec<CardPack> = serde_json::from_str(&data)
.with_context(|| format!("The contents of \"{path}\" is not valid 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_meta: Vec<CardPackMeta> = vec![];
let mut white_cards_by_id = HashMap::<String, Arc<CardWhiteWithID>>::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<u8> = 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))
}