1use std::{collections::HashMap, time::SystemTime};
2
3use gn_redisadapter_derive::{
4 RedisIdentifiable, RedisInsertWriter, RedisOutputReader, RedisUpdater,
5};
6use serde::Deserialize;
7
8#[cfg(feature = "redis")]
9use gn_matchmaking_state::adapters::redis::RedisFilter;
10
11#[derive(Debug, Clone, PartialEq, Deserialize, RedisInsertWriter, RedisIdentifiable)]
12#[name("game_servers")]
13pub struct GameServer {
14 pub region: String,
15 pub game: String,
16 pub mode: String,
17 pub server_pub: String,
18 pub server_priv: String,
19 pub healthy: bool,
20 pub min_players: u32,
21 pub max_players: u32,
22}
23
24#[derive(Debug, Clone, RedisOutputReader, RedisIdentifiable)]
25#[name("game_servers")]
26pub struct DBGameServer {
27 #[cfg_attr(feature = "redis", uuid)]
28 pub uuid: String,
29 pub region: String,
30 pub game: String,
31 pub mode: String,
32 pub server_pub: String,
33 pub server_priv: String,
34 pub healthy: bool,
35 pub min_players: u32,
36 pub max_players: u32,
37}
38
39impl PartialEq for DBGameServer {
40 fn eq(&self, other: &Self) -> bool {
41 self.uuid == other.uuid
42 }
43}
44
45#[derive(Debug, Clone, Default, RedisUpdater)]
46#[name("game_servers")]
47pub struct GameServerUpdater {
48 pub game: Option<String>,
49 pub mode: Option<String>,
50 pub region: Option<String>,
51 pub server_pub: Option<String>,
52 pub server_priv: Option<String>,
53 pub healthy: Option<bool>,
54 pub min_players: Option<u32>,
55 pub max_players: Option<u32>,
56}
57
58#[derive(Debug, Default)]
59pub struct GameServerFilter {
60 pub game: Option<String>,
61}
62
63#[cfg(feature = "redis")]
64impl RedisFilter<DBGameServer> for GameServerFilter {
65 fn is_ok(&self, check: &DBGameServer) -> bool {
66 if self.game.is_none() {
67 return true;
68 }
69 return self.game.clone().unwrap() == check.game;
70 }
71}
72
73#[derive(Debug, Clone, RedisInsertWriter, RedisIdentifiable)]
74#[name("host_requests")]
75
76pub struct HostRequest {
77 pub player_id: String,
78 pub mode: String,
79 pub game: String,
80 pub region: String,
81 pub join_token: String,
82 pub joined_players: Vec<String>,
83 pub start_requested: bool,
84 pub min_players: u32,
85 pub max_players: u32,
86 pub wait_start: SystemTime,
87}
88
89#[derive(Debug, Clone, RedisOutputReader, RedisIdentifiable)]
90#[name("host_requests")]
91pub struct HostRequestDB {
92 #[cfg_attr(feature = "redis", uuid)]
93 pub uuid: String,
94 pub player_id: String,
95 pub mode: String,
96 pub game: String,
97 pub region: String,
98 pub join_token: String,
99 pub joined_players: Vec<String>,
100 pub start_requested: bool,
101 pub min_players: u32,
102 pub max_players: u32,
103 pub wait_start: SystemTime,
104}
105
106#[derive(Debug, Clone, Default, RedisUpdater)]
107#[name("host_requests")]
108pub struct HostRequestUpdate {
109 pub player_id: Option<String>,
110 pub mode: Option<String>,
111 pub game: Option<String>,
112 pub region: Option<String>,
113 pub join_token: Option<String>,
114 pub joined_players: Option<Vec<String>>,
115 pub start_requested: Option<bool>,
116 pub min_players: Option<u32>,
117 pub max_players: Option<u32>,
118 pub wait_start: Option<SystemTime>,
119}
120#[derive(Debug, Clone, RedisInsertWriter, RedisIdentifiable)]
121#[name("searchers")]
122pub struct Searcher {
123 pub player_id: String,
124 pub elo: u32,
125 pub mode: String,
126 pub ai: Option<String>,
127 pub game: String,
128 pub region: String,
129 pub min_players: u32,
130 pub max_players: u32,
131 pub wait_start: SystemTime,
132}
133
134#[derive(Debug, Clone, RedisUpdater)]
135#[name("searchers")]
136pub struct SearcherUpdate {
137 pub player_id: Option<String>,
138 pub elo: Option<u32>,
139 pub mode: Option<String>,
140 pub ai: Option<Option<String>>,
141 pub game: Option<String>,
142 pub region: Option<String>,
143 pub wait_start: Option<SystemTime>,
144}
145
146#[derive(Debug, Clone, RedisOutputReader, RedisIdentifiable)]
147#[name("searchers")]
148pub struct DBSearcher {
149 #[cfg_attr(feature = "redis", uuid)]
150 pub uuid: String,
151 pub player_id: String,
152 pub elo: u32,
153 pub mode: String,
154 pub ai: Option<String>,
155 pub game: String,
156 pub region: String,
157 pub min_players: u32,
158 pub max_players: u32,
159 pub wait_start: SystemTime,
160}
161
162#[derive(Debug, Default)]
163pub struct SearcherFilter {
164 pub game: Option<String>,
165 pub mode: Option<String>,
166}
167
168#[cfg(feature = "redis")]
169#[derive(Debug, Clone, RedisInsertWriter, RedisOutputReader, RedisIdentifiable)]
170#[name("config")]
171#[single_instance(true)]
172pub struct SearcherMatchConfig {
173 pub max_elo_diff: u32,
174 pub wait_time_to_elo_factor: f32,
175 pub wait_time_to_server_factor: f32,
176}
177
178#[derive(Debug, Clone, RedisInsertWriter, RedisIdentifiable)]
179#[name("active_matches")]
180pub struct ActiveMatch {
181 pub game: String,
182 pub mode: String,
183 pub ai: bool,
184 pub server_pub: String,
185 pub server_priv: String,
186 pub region: String,
187 pub read: String,
188 pub player_write: HashMap<String, String>,
189 pub chat_id: String
190}
191
192#[derive(Debug, Clone, RedisOutputReader, RedisIdentifiable)]
193#[name("active_matches")]
194pub struct ActiveMatchDB {
195 #[cfg_attr(feature = "redis", uuid)]
196 pub uuid: String,
197 pub game: String,
198 pub mode: String,
199 pub ai: bool,
200 pub server_pub: String,
201 pub server_priv: String,
202 pub region: String,
203 pub read: String,
204 pub player_write: HashMap<String, String>,
205 pub chat_id: String
206}
207
208#[derive(Debug, Clone, RedisInsertWriter, RedisIdentifiable)]
209#[name("ai_players")]
210pub struct AIPlayer {
211 pub game: String,
212 pub mode: String,
213 pub elo: u32,
214 pub display_name: String,
215}
216
217#[derive(Debug, Clone, RedisOutputReader, RedisIdentifiable)]
218#[name("ai_players")]
219pub struct AIPlayerDB {
220 #[uuid]
221 pub uuid: String,
222 pub game: String,
223 pub mode: String,
224 pub elo: u32,
225 pub display_name: String,
226}
227
228#[cfg(test)]
229mod tests {
230 use std::error::Error;
231
232 use gn_matchmaking_state::adapters::{Gettable, Insertable, Removable, Updateable};
233
234 #[test]
235
236 fn test_redis_adapter_insert_game_server() {
237 use super::*;
238 use gn_matchmaking_state::adapters::redis::publisher::native::RedisInfoPublisher;
239 use gn_matchmaking_state::adapters::redis::RedisAdapter;
240 use gn_matchmaking_state::adapters::Insertable;
241
242 let adapter = RedisAdapter::connect("redis://0.0.0.0:6379").unwrap();
243 let publisher = RedisInfoPublisher::new(adapter.client.get_connection().unwrap());
244 let adapter = adapter.with_publisher(publisher);
245
246 let game_server = GameServer {
247 region: "eu".to_owned(),
248 game: "Test Server".to_owned(),
249 mode: "Test Mode".to_owned(),
250 server_pub: "127.0.0.1:3456".to_owned(),
251 server_priv: "127.0.0.1:3456".to_owned(),
252 healthy: true,
253 min_players: 2,
254 max_players: 2,
255 };
256 adapter.insert(game_server).unwrap();
257 }
258
259 #[test]
260 fn test_redis_adapter_all_game_server() {
261 use super::*;
262 use gn_matchmaking_state::adapters::redis::publisher::native::RedisInfoPublisher;
263 use gn_matchmaking_state::adapters::redis::RedisAdapter;
264
265 let adapter = RedisAdapter::connect("redis://0.0.0.0:6379").unwrap();
266 let publisher = RedisInfoPublisher::new(adapter.client.get_connection().unwrap());
267 let adapter = adapter.with_publisher(publisher);
268
269 let game_server = GameServer {
270 region: "eu".to_owned(),
271 game: "Test Server".to_owned(),
272 mode: "Test Mode".to_owned(),
273 server_pub: "127.0.0.1:3456".to_owned(),
274 server_priv: "127.0.0.1:3456".to_owned(),
275 healthy: true,
276 min_players: 2,
277 max_players: 2,
278 };
279 adapter.insert(game_server.clone()).unwrap();
280
281 let found_server = adapter.all().unwrap().collect::<Vec<DBGameServer>>();
282
283 for game in &found_server {
284 println!("{:?}", game);
285 }
286
287 assert!(found_server.len() > 0);
288 assert!(found_server.iter().any(|x| x.game == game_server.game));
289 }
290
291 #[test]
292 fn test_redis_adapter_remove_game_server() {
293 use super::*;
294 use gn_matchmaking_state::adapters::redis::publisher::native::RedisInfoPublisher;
295 use gn_matchmaking_state::adapters::redis::RedisAdapter;
296
297 let adapter = RedisAdapter::connect("redis://0.0.0.0:6379").unwrap();
298 let publisher = RedisInfoPublisher::new(adapter.client.get_connection().unwrap());
299 let adapter = adapter.with_publisher(publisher);
300
301 let game_server = GameServer {
302 region: "eu".to_owned(),
303 game: "Test Server".to_owned(),
304 mode: "Test Mode".to_owned(),
305 server_pub: "127.0.0.1:3456".to_owned(),
306 server_priv: "127.0.0.1:3456".to_owned(),
307 healthy: true,
308 min_players: 2,
309 max_players: 2,
310 };
311 let uuid = adapter.insert(game_server.clone()).unwrap();
312
313 adapter.remove(&uuid).unwrap();
314
315 let game: Result<DBGameServer, Box<dyn Error>> = adapter.get(&uuid);
316 assert!(game.is_err());
317 }
318
319 #[test]
320 fn test_redis_adapter_update_game_server() {
321 use super::*;
322 use gn_matchmaking_state::adapters::redis::publisher::native::RedisInfoPublisher;
323 use gn_matchmaking_state::adapters::redis::RedisAdapter;
324
325 let adapter = RedisAdapter::connect("redis://0.0.0.0:6379").unwrap();
326 let publisher = RedisInfoPublisher::new(adapter.client.get_connection().unwrap());
327 let adapter = adapter.with_publisher(publisher);
328
329 let game_server = GameServer {
330 region: "eu".to_owned(),
331 game: "Test Server".to_owned(),
332 mode: "Test Mode".to_owned(),
333 server_pub: "127.0.0.1:3456".to_owned(),
334 server_priv: "127.0.0.1:3456".to_owned(),
335 healthy: true,
336 min_players: 2,
337 max_players: 2,
338 };
339 let uuid = adapter.insert(game_server.clone()).unwrap();
340
341 let mut update = GameServerUpdater::default();
342 update.game = Some("CSS Battle (Cum Sum Sus Battle)".to_owned());
343 adapter.update(&uuid, update).unwrap();
344
345 let result: DBGameServer = adapter.get(&uuid).unwrap();
346
347 assert!(result.game == "CSS Battle (Cum Sum Sus Battle)");
348 }
349}