use std::{ collections::HashMap, net::SocketAddr, sync::{ Arc, atomic::{ AtomicUsize, Ordering }, }, fmt::Display, ops::{ Deref, DerefMut }, }; use warp::ws::Message; use tokio::sync::RwLock; use crate::minesweeper; #[derive(Debug, Clone)] pub struct Config { pub cert: String, pub pkey: String, pub index_pg: String, pub room_pg: String, pub client_code: String, pub stylesheet: String, pub socket_addr: SocketAddr, } #[derive(Debug)] pub struct Room { pub name: String, pub players: PlayerMap, pub peer_limit: usize, pub public: bool, pub driver: tokio::task::JoinHandle<()>, pub cmd_stream: CmdTx, pub board_conf: minesweeper::BoardConf, } #[derive(Debug)] pub enum MetaMove { Move(minesweeper::Move,SocketAddr), Dump, Reset, } #[derive(Debug)] pub struct Conn { pub tx: tokio::sync::mpsc::UnboundedSender, pub addr: SocketAddr, } #[derive(Debug)] pub struct Player { pub conn: Conn, pub uid: usize, pub name: String, pub clr: String, pub position: (usize, usize), } impl Display for Player { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "\"{}\"@{}", self.name, self.conn.addr) } } #[derive(Eq, PartialEq, Hash, Debug, Clone)] pub struct RoomId(pub String); impl Display for RoomId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl RoomId { pub fn new_in(map: &HashMap) -> Self { use rand::{ thread_rng, Rng, distributions::Alphanumeric }; let id = RoomId { 0: thread_rng() .sample_iter(&Alphanumeric) .take(16) .map(char::from) .collect::() }; if map.contains_key(&id) { RoomId::new_in(map) } else { id } } } pub type CmdTx = tokio::sync::mpsc::UnboundedSender; pub type RoomMap = Arc>>>>; pub type PlayerMapData = Arc>>; #[derive(Debug)] pub struct PlayerMap { inner: PlayerMapData, uid_counter: AtomicUsize, } impl Deref for PlayerMap { type Target = Arc>>; fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for PlayerMap { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } impl Default for PlayerMap { fn default() -> Self { Self { inner: Arc::new(RwLock::new(HashMap::new())), uid_counter: 0.into() } } } impl PlayerMap { pub async fn insert_conn(&mut self, conn: Conn, name: String, clr: String) -> usize { let mut map = self.write().await; let uid = self.uid_counter.fetch_add(1, Ordering::Relaxed); map.insert( conn.addr, Player { conn, uid, name, clr, position: (0,0) }, ); uid } }