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