1use dashmap::DashMap;
2use std::time::Instant;
3use tokio::sync::mpsc;
4use tokio_tungstenite::tungstenite::Message;
5
6use crate::analytics::AnalyticsHandle;
7use crate::deck_play_events::DeckPlayEventHandle;
8use crate::room::Room;
9
10pub struct ConnectedPlayer {
11 pub player_id: String,
12 pub username: String,
13 pub room_id: Option<String>,
14 pub sender: mpsc::UnboundedSender<Message>,
15 pub connected: bool,
16 pub generation: u64,
17 pub last_seen: Instant,
18 pub disconnected_at: Option<Instant>,
19 pub is_service: bool,
20}
21
22pub struct ServerState {
23 pub players: DashMap<String, ConnectedPlayer>,
24 pub rooms: DashMap<String, Room>,
25 pub server_key: String,
26 pub max_rooms: usize,
27 pub official_key: Option<String>,
28 pub analytics: AnalyticsHandle,
29 pub deck_play_events: DeckPlayEventHandle,
30}
31
32impl ServerState {
33 pub fn new(
34 server_key: String,
35 max_rooms: usize,
36 official_key: Option<String>,
37 analytics: AnalyticsHandle,
38 deck_play_events: DeckPlayEventHandle,
39 ) -> Self {
40 ServerState {
41 players: DashMap::new(),
42 rooms: DashMap::new(),
43 server_key,
44 max_rooms,
45 official_key,
46 analytics,
47 deck_play_events,
48 }
49 }
50
51 pub fn username_taken_by_connected(&self, username: &str) -> bool {
52 self.players
53 .iter()
54 .any(|entry| entry.value().username == username && entry.value().connected)
55 }
56
57 pub fn find_disconnected_by_username(
58 &self,
59 username: &str,
60 ) -> Option<(String, Option<String>, u64)> {
61 self.players
62 .iter()
63 .find(|entry| entry.value().username == username && !entry.value().connected)
64 .map(|entry| {
65 (
66 entry.value().player_id.clone(),
67 entry.value().room_id.clone(),
68 entry.value().generation,
69 )
70 })
71 }
72
73 pub fn find_connected_by_username(&self, username: &str) -> Option<(String, u64, bool)> {
74 self.players
75 .iter()
76 .find(|entry| entry.value().username == username && entry.value().connected)
77 .map(|entry| {
78 (
79 entry.value().player_id.clone(),
80 entry.value().generation,
81 entry.value().sender.is_closed(),
82 )
83 })
84 }
85}