1use serde::{Deserialize as SerdeDeserialize, Deserializer};
2use serde_derive::Deserialize;
3use serde_derive::Serialize;
4use std::collections::{HashMap, HashSet};
5
6fn deserialize_timestamp<'de, D>(deserializer: D) -> Result<u64, D::Error>
7where
8 D: Deserializer<'de>,
9{
10 let value: f64 = SerdeDeserialize::deserialize(deserializer)?;
11 Ok(value as u64)
12}
13
14fn default_location() -> String {
15 "unknown".to_string()
16}
17
18#[allow(dead_code)]
19pub type Query = Vec<QueryPlayer>;
20
21#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct QueryPlayer {
24 pub points: i64,
25 pub name: String,
26}
27
28#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct Master {
31 pub servers: Vec<Server>,
32}
33
34impl Master {
35 #[allow(dead_code)]
36 pub fn count_clients(&self) -> usize {
37 self.servers.iter().map(Server::count_client).sum()
38 }
39
40 #[allow(dead_code)]
41 pub fn get_clans(&self, rm: Option<Vec<&str>>) -> Vec<(String, usize)> {
42 let remove_list: HashSet<&str> = rm
43 .unwrap_or_else(|| vec!["DD-Persian", "/vDQMHSss8W"])
44 .into_iter()
45 .collect();
46
47 if self.servers.is_empty() {
48 return vec![];
49 }
50
51 let mut dat: HashMap<String, usize> = HashMap::new();
52
53 self.servers.iter().for_each(|server| {
54 if let Some(clients) = &server.info.clients {
55 clients
56 .iter()
57 .filter(|client| !client.clan.is_empty())
58 .for_each(|client| {
59 *dat.entry(client.clan.clone()).or_insert(0) += 1;
60 });
61 }
62 });
63
64 for clan in remove_list {
65 dat.remove(clan);
66 }
67
68 let mut sorted_dat: Vec<_> = dat.into_iter().collect();
69 sorted_dat.sort_by(|&(_, count1), &(_, count2)| count2.cmp(&count1));
70 sorted_dat
71 }
72}
73
74#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
75#[serde(rename_all = "camelCase")]
76pub struct Server {
77 pub addresses: Vec<String>,
78 #[serde(default = "default_location")]
79 pub location: String,
80 pub info: Info,
81}
82
83impl Server {
84 #[allow(dead_code)]
85 pub fn count_client(&self) -> usize {
86 self.info
87 .clients
88 .as_ref()
89 .map_or(0, |clients| clients.len())
90 }
91}
92
93#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
94#[serde(rename_all = "camelCase")]
95pub struct Info {
96 #[serde(rename = "max_clients")]
97 pub max_clients: i64,
98 #[serde(rename = "max_players")]
99 pub max_players: i64,
100 pub passworded: bool,
101 #[serde(rename = "game_type")]
102 pub game_type: String,
103 pub name: String,
104 pub map: Map,
105 pub version: String,
106 pub clients: Option<Vec<Client>>,
107 #[serde(rename = "requires_login")]
108 pub requires_login: Option<bool>,
109 pub community: Option<Community>,
110}
111
112#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
113#[serde(rename_all = "camelCase")]
114pub struct Map {
115 pub name: String,
116 pub sha256: Option<String>,
117 pub size: Option<i64>,
118}
119
120#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct Client {
123 pub name: String,
124 pub clan: String,
125 pub country: i32,
126 pub score: i64,
127 pub is_player: Option<bool>,
128 pub skin: Option<Skin>,
129 pub afk: Option<bool>,
130 pub team: Option<i64>,
131}
132
133#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
134#[serde(rename_all = "camelCase")]
135pub struct Skin {
136 pub name: Option<String>,
137 pub color_body: Option<i64>,
138 pub color_feet: Option<i64>,
139}
140
141#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
142#[serde(rename_all = "camelCase")]
143pub struct Community {
144 pub id: String,
145 pub icon: String,
146 pub admin: Vec<String>,
147 pub public_key: Option<String>,
148 pub signature: Option<String>,
149}
150
151#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
152#[serde(rename_all = "camelCase")]
153pub struct DDPlayer {
154 pub player: String,
155 pub points: Points,
156 #[serde(rename = "team_rank")]
157 pub team_rank: Option<Rank>,
158 pub rank: Option<Rank>,
159 #[serde(rename = "points_last_year")]
160 pub points_last_year: Option<Rank>,
161 #[serde(rename = "points_last_month")]
162 pub points_last_month: Option<Rank>,
163 #[serde(rename = "points_last_week")]
164 pub points_last_week: Option<Rank>,
165 #[serde(rename = "favorite_server")]
166 pub favorite_server: FavoriteServer,
167 #[serde(rename = "first_finish")]
168 pub first_finish: FirstFinish,
169 #[serde(rename = "last_finishes")]
170 pub last_finishes: Vec<LastFinish>,
171 #[serde(rename = "favorite_partners")]
172 pub favorite_partners: Option<Vec<FavoritePartner>>,
173 pub types: Types,
174 pub activity: Vec<Activity>,
175 #[serde(rename = "hours_played_past_365_days")]
176 pub hours_played_past_365_days: i64,
177}
178
179#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
180#[serde(rename_all = "camelCase")]
181pub struct DMap {
182 pub name: String,
183 pub website: String,
184 pub thumbnail: String,
185 #[serde(rename = "web_preview")]
186 pub web_preview: String,
187 #[serde(rename = "type")]
188 pub type_field: String,
189 pub points: i64,
190 pub difficulty: i64,
191 pub mapper: String,
192 pub release: Option<f64>,
193 #[serde(rename = "median_time")]
194 pub median_time: f64,
195 #[serde(rename = "first_finish")]
196 pub first_finish: f64,
197 #[serde(rename = "last_finish")]
198 pub last_finish: f64,
199 pub finishes: i64,
200 pub finishers: i64,
201 #[serde(rename = "biggest_team")]
202 pub biggest_team: i64,
203 pub width: i64,
204 pub height: i64,
205 pub tiles: Vec<String>,
206 #[serde(rename = "team_ranks")]
207 pub team_ranks: Vec<DTeamRank>,
208 pub ranks: Vec<DRank>,
209 #[serde(rename = "max_finishes")]
210 pub max_finishes: Vec<MaxFinish>,
211}
212
213#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
214#[serde(rename_all = "camelCase")]
215pub struct DTeamRank {
216 pub rank: i64,
217 pub players: Vec<String>,
218 pub time: f64,
219 #[serde(deserialize_with = "deserialize_timestamp")]
220 pub timestamp: u64,
221 pub country: String,
222}
223
224#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
225#[serde(rename_all = "camelCase")]
226pub struct DRank {
227 pub rank: i64,
228 pub player: String,
229 pub time: f64,
230 #[serde(deserialize_with = "deserialize_timestamp")]
231 pub timestamp: u64,
232 pub country: String,
233}
234
235#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
236#[serde(rename_all = "camelCase")]
237pub struct MaxFinish {
238 pub rank: i64,
239 pub player: String,
240 pub num: i64,
241 pub time: f64,
242 #[serde(rename = "min_timestamp")]
243 #[serde(deserialize_with = "deserialize_timestamp")]
244 pub min_timestamp: u64,
245 #[serde(rename = "max_timestamp")]
246 #[serde(deserialize_with = "deserialize_timestamp")]
247 pub max_timestamp: u64,
248}
249
250#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
251#[serde(rename_all = "camelCase")]
252pub struct Points {
253 pub total: u64,
254 pub points: Option<u64>,
255 pub rank: Option<u64>,
256}
257
258#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
259#[serde(rename_all = "camelCase")]
260pub struct Rank {
261 pub points: Option<u64>,
262 pub rank: Option<u64>,
263}
264
265#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
266#[serde(rename_all = "camelCase")]
267pub struct FavoriteServer {
268 pub server: String,
269}
270
271#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
272#[serde(rename_all = "camelCase")]
273pub struct FirstFinish {
274 #[serde(deserialize_with = "deserialize_timestamp")]
275 pub timestamp: u64,
276 pub map: String,
277 pub time: f64,
278}
279
280#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
281#[serde(rename_all = "camelCase")]
282pub struct LastFinish {
283 #[serde(deserialize_with = "deserialize_timestamp")]
284 pub timestamp: u64,
285 pub map: String,
286 pub time: f64,
287 pub country: String,
288 #[serde(rename = "type")]
289 pub type_field: Option<String>,
290}
291
292#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
293#[serde(rename_all = "camelCase")]
294pub struct FavoritePartner {
295 pub name: String,
296 pub finishes: i64,
297}
298
299#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
300#[serde(rename_all = "camelCase")]
301pub struct Types {
302 #[serde(rename = "Novice")]
303 pub novice: TypeDDType,
304 #[serde(rename = "Moderate")]
305 pub moderate: TypeDDType,
306 #[serde(rename = "Brutal")]
307 pub brutal: TypeDDType,
308 #[serde(rename = "Insane")]
309 pub insane: TypeDDType,
310 #[serde(rename = "Dummy")]
311 pub dummy: TypeDDType,
312 #[serde(rename = "DDmaX.Easy")]
313 pub ddma_x_easy: TypeDDType,
314 #[serde(rename = "DDmaX.Next")]
315 pub ddma_x_next: TypeDDType,
316 #[serde(rename = "DDmaX.Pro")]
317 pub ddma_x_pro: TypeDDType,
318 #[serde(rename = "DDmaX.Nut")]
319 pub ddma_x_nut: TypeDDType,
320 #[serde(rename = "Oldschool")]
321 pub oldschool: TypeDDType,
322 #[serde(rename = "Solo")]
323 pub solo: TypeDDType,
324 #[serde(rename = "Race")]
325 pub race: TypeDDType,
326 #[serde(rename = "Fun")]
327 pub fun: TypeDDType,
328}
329
330#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
331#[serde(rename_all = "camelCase")]
332pub struct TypeDDType {
333 pub points: Points,
334 #[serde(rename = "team_rank")]
335 pub team_rank: Option<Rank>,
336 pub rank: Option<Rank>,
337 pub maps: HashMap<String, DDMap>,
338}
339
340#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
341#[serde(rename_all = "camelCase")]
342pub struct DDMap {
343 pub points: i64,
344 #[serde(rename = "total_finishes")]
345 pub total_finishes: i64,
346 pub finishes: i64,
347 #[serde(rename = "team_rank")]
348 pub team_rank: Option<i64>,
349 pub rank: Option<i64>,
350 pub time: Option<f64>,
351 #[serde(rename = "first_finish")]
352 pub first_finish: Option<f64>,
353}
354
355#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
356#[serde(rename_all = "camelCase")]
357pub struct Activity {
358 pub date: String,
359 #[serde(rename = "hours_played")]
360 pub hours_played: i64,
361}