Skip to main content

manabrew_server/
state.rs

1use dashmap::DashMap;
2use std::time::Instant;
3use tokio::sync::mpsc;
4use tokio_tungstenite::tungstenite::Message;
5
6use crate::analytics::AnalyticsHandle;
7use crate::client_build::ClientBuild;
8use crate::deck_play_events::DeckPlayEventHandle;
9use crate::identity::{IdentityVerifier, SessionIdentity};
10use crate::room::Room;
11
12pub struct ConnectedPlayer {
13    pub player_id: String,
14    pub username: String,
15    pub room_id: Option<String>,
16    pub sender: mpsc::UnboundedSender<Message>,
17    pub connected: bool,
18    pub generation: u64,
19    pub last_seen: Instant,
20    pub disconnected_at: Option<Instant>,
21    pub is_service: bool,
22    pub identity: Vec<SessionIdentity>,
23    pub name_verified: bool,
24    /// What the client reported at authentication. Read when deciding which
25    /// wire features this seat can be sent.
26    pub client: ClientBuild,
27}
28
29pub struct UsernameSession {
30    pub player_id: String,
31    pub room_id: Option<String>,
32    pub generation: u64,
33    pub connected: bool,
34    pub sender_closed: bool,
35    pub identity: Vec<SessionIdentity>,
36    pub name_verified: bool,
37}
38
39impl From<&ConnectedPlayer> for UsernameSession {
40    fn from(player: &ConnectedPlayer) -> Self {
41        UsernameSession {
42            player_id: player.player_id.clone(),
43            room_id: player.room_id.clone(),
44            generation: player.generation,
45            connected: player.connected,
46            sender_closed: player.sender.is_closed(),
47            identity: player.identity.clone(),
48            name_verified: player.name_verified,
49        }
50    }
51}
52
53pub struct ServerState {
54    pub players: DashMap<String, ConnectedPlayer>,
55    pub rooms: DashMap<String, Room>,
56    pub server_key: String,
57    pub max_rooms: usize,
58    pub official_key: Option<String>,
59    pub analytics: AnalyticsHandle,
60    pub deck_play_events: DeckPlayEventHandle,
61    pub identity: IdentityVerifier,
62}
63
64impl ServerState {
65    pub fn new(
66        server_key: String,
67        max_rooms: usize,
68        official_key: Option<String>,
69        analytics: AnalyticsHandle,
70        deck_play_events: DeckPlayEventHandle,
71        hub_jwks_url: Option<String>,
72    ) -> Self {
73        ServerState {
74            players: DashMap::new(),
75            rooms: DashMap::new(),
76            server_key,
77            max_rooms,
78            official_key,
79            analytics,
80            deck_play_events,
81            identity: IdentityVerifier::new(hub_jwks_url),
82        }
83    }
84
85    pub fn session_by_username(&self, username: &str) -> Option<UsernameSession> {
86        let mut connected = None;
87        for entry in self.players.iter() {
88            let player = entry.value();
89            if player.username != username {
90                continue;
91            }
92            if !player.connected {
93                return Some(UsernameSession::from(player));
94            }
95            connected.get_or_insert_with(|| UsernameSession::from(player));
96        }
97        connected
98    }
99}