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 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}