Skip to main content

wrym/
server.rs

1use std::{
2    collections::{HashMap, VecDeque},
3    time::{Duration, Instant},
4};
5
6use wrym_transport::{ReliableTransport, Transport};
7
8use crate::Opcode;
9
10pub struct ServerConfig {
11    pub client_timeout: Duration,
12}
13
14impl Default for ServerConfig {
15    fn default() -> Self {
16        Self {
17            client_timeout: Duration::from_secs(60),
18        }
19    }
20}
21
22pub struct ClientData {
23    last_activity: Instant,
24}
25
26pub enum ServerEvent {
27    ClientConnected(String),
28    ClientDisconnected(String),
29    MessageReceived(String, Vec<u8>),
30}
31
32pub struct Server<T: Transport> {
33    transport: T,
34    config: ServerConfig,
35    clients: HashMap<String, ClientData>,
36    events: VecDeque<ServerEvent>,
37}
38
39impl<T: Transport> Server<T> {
40    pub fn new(transport: T, config: ServerConfig) -> Self {
41        Self {
42            transport,
43            config,
44            clients: HashMap::new(),
45            events: VecDeque::new(),
46        }
47    }
48
49    fn add_client(&mut self, addr: &str) {
50        if self
51            .clients
52            .insert(
53                addr.to_string(),
54                ClientData {
55                    last_activity: Instant::now(),
56                },
57            )
58            .is_none()
59        {
60            self.transport
61                .send_to(&addr, &[Opcode::ClientConnected as u8]);
62            self.events
63                .push_back(ServerEvent::ClientConnected(addr.to_string()));
64        }
65    }
66
67    fn drop_client(&mut self, addr: &str) {
68        if self.clients.remove(addr).is_some() {
69            self.transport
70                .send_to(&addr, &[Opcode::ClientDisconnected as u8]);
71            self.events
72                .push_back(ServerEvent::ClientDisconnected(addr.to_string()));
73        }
74    }
75
76    fn drop_inactive_clients(&mut self, timeout: Duration) {
77        let to_disconnect: Vec<String> = self
78            .clients
79            .iter()
80            .filter_map(|(addr, data)| {
81                if Instant::now().duration_since(data.last_activity) > timeout {
82                    Some(addr.to_owned())
83                } else {
84                    None
85                }
86            })
87            .collect();
88
89        for addr in to_disconnect {
90            self.drop_client(&addr);
91        }
92    }
93
94    pub fn poll(&mut self) {
95        self.drop_inactive_clients(self.config.client_timeout);
96
97        if let Some((addr, mut bytes)) = self.transport.recv() {
98            if bytes.is_empty() {
99                return;
100            }
101
102            if let Some(data) = self.clients.get_mut(&addr) {
103                data.last_activity = Instant::now();
104            }
105
106            match bytes.remove(0).into() {
107                Opcode::ClientConnected => self.add_client(&addr),
108                Opcode::ClientDisconnected => self.drop_client(&addr),
109                Opcode::Message => {
110                    self.events
111                        .push_back(ServerEvent::MessageReceived(addr, bytes));
112                }
113            }
114        }
115    }
116
117    pub fn recv_event(&mut self) -> Option<ServerEvent> {
118        self.events.pop_front()
119    }
120
121    pub fn send_to(&self, addr: &str, bytes: &[u8]) {
122        self.transport
123            .send_to(addr, &Opcode::Message.with_bytes(bytes));
124    }
125
126    pub fn broadcast(&self, bytes: &[u8]) {
127        let msg = Opcode::Message.with_bytes(bytes);
128
129        for addr in self.clients.keys() {
130            self.transport.send_to(addr, &msg);
131        }
132    }
133}
134
135impl<T: Transport + ReliableTransport> Server<T> {
136    pub fn send_reliable_to(&self, addr: &str, bytes: &[u8], ordered: bool) {
137        self.transport
138            .send_reliable_to(addr, &Opcode::Message.with_bytes(bytes), ordered);
139    }
140
141    pub fn broadcast_reliable(&self, bytes: &[u8], ordered: bool) {
142        let msg = Opcode::Message.with_bytes(bytes);
143
144        for addr in self.clients.keys() {
145            self.transport.send_reliable_to(addr, &msg, ordered)
146        }
147    }
148}