summaryrefslogtreecommitdiff
path: root/src/types.rs
blob: b2bc93ee1aab0f013fd3de8b8f20c17eb515eabc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::{
    collections::HashMap,
    net::SocketAddr,
    sync::{
        Arc,
        atomic::{ AtomicUsize, Ordering },
},
    fmt::Display,
    ops::{ Deref, DerefMut },
    num::NonZeroUsize,
};
use warp::ws::Message;
use tokio::sync::RwLock;
use serde::Serialize;
use crate::minesweeper;
use crate::livepos;
use crate::ircbot;

#[derive(Debug, Serialize, Clone)]
pub struct RoomConf {
    pub name: String,
    pub player_cap: NonZeroUsize,
    pub public: bool,
    pub board_conf: minesweeper::BoardConf,
}

pub struct Room {
    pub conf: RoomConf,
    pub players: Arc<RwLock<PlayerMap>>,
    pub game_driver: tokio::task::JoinHandle<()>,
    pub cmd_stream: CmdTx,
    pub livepos_driver: tokio::task::JoinHandle<()>,
    pub pos_stream: tokio::sync::mpsc::UnboundedSender<livepos::Req>,
    pub irc_driver: tokio::task::JoinHandle<()>,
    pub irc_stream: tokio::sync::mpsc::UnboundedSender<ircbot::IrcCmd>,
}

#[derive(Debug)]
pub enum MetaMove {
    Move(minesweeper::Move,SocketAddr),
    StateDump,
    StateSync,
    Reset,
}

#[derive(Debug, Clone)]
pub struct Conn {
    pub tx: tokio::sync::mpsc::UnboundedSender<Message>,
    pub addr: SocketAddr,
}

#[derive(Debug)]
pub struct Player {
    pub conn: Conn,
    pub uid: usize,
    pub name: String,
    pub clr: String,
}

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, serde::Serialize)]
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 std::borrow::Borrow<str> for RoomId {
    fn borrow(&self) -> &str {
        self.0.borrow()
    }
}

impl RoomId {
    pub fn new_among<'a, I>(existing: I) -> Self
        where
            I: IntoIterator<Item = &'a RoomId>,
            <I as IntoIterator>::IntoIter: Clone,
    {
        use rand::{ thread_rng, Rng, distributions::Alphanumeric };
        let id = RoomId(thread_rng()
            .sample_iter(&Alphanumeric)
            .take(16)
            .map(char::from)
            .collect::<String>());
        let existing = existing.into_iter();
        if existing.clone().any(|x| *x == id) { Self::new_among(existing) }
        else { id }
    }
}

pub type CmdTx = tokio::sync::mpsc::UnboundedSender<MetaMove>;
pub type RoomMap = HashMap<RoomId, Arc<RwLock<Room>>>;
pub type PlayerMapData = HashMap<SocketAddr, Player>;
#[derive(Debug)]
pub struct PlayerMap {
    inner: PlayerMapData,
    uid_counter: AtomicUsize,
}

impl Deref for PlayerMap {
    type Target = PlayerMapData;
    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: HashMap::new(), uid_counter: 0.into() }
    }
}

impl PlayerMap {
    pub fn insert_conn(&mut self, conn: Conn, name: String, clr: String) -> usize {
        let uid = self.uid_counter.fetch_add(1, Ordering::Relaxed);
        self.insert(
            conn.addr,
            Player { conn, uid, name, clr },
        );
        uid
    }
}