1#![doc = include_str!("../README.md")]
2#![forbid(unsafe_code)]
3
4pub mod entry;
5pub mod error;
6pub mod leaderboard;
7pub mod player;
8pub mod prelude;
9
10use reqwest::StatusCode;
11
12use crate::{entry::LeaderboardEntry, error::Error, leaderboard::Leaderboard, player::Player};
13
14pub(crate) const API_URL: &str = "https://play.retro-mmo.com";
15
16pub type OnlineList = Vec<String>;
17pub type LeaderboardPage = Vec<LeaderboardEntry>;
18
19pub async fn get_player(username: &str) -> Result<Player, Error> {
21 let response = reqwest::get(format!("{API_URL}/users/{username}.json")).await;
22
23 if let Ok(player) = response {
24 let player = player.json::<Player>().await;
25
26 match player {
27 Ok(player) => Ok(player),
28 Err(e) => Err(Error::new(
29 StatusCode::INTERNAL_SERVER_ERROR,
30 Some(format!("Failed to parse player: {e}")),
31 )),
32 }
33 } else {
34 Err(Error::new(StatusCode::INTERNAL_SERVER_ERROR, Some("Failed to get player".to_string())))
35 }
36}
37
38pub async fn get_online_players() -> Result<OnlineList, Error> {
44 let response = reqwest::get(format!("{API_URL}/players.json")).await;
45
46 if let Ok(players) = response {
47 let players = players.json::<OnlineList>().await;
48
49 match players {
50 Ok(players) => Ok(players),
51 Err(e) => Err(Error::new(
52 StatusCode::INTERNAL_SERVER_ERROR,
53 Some(format!("Failed to parse online players: {e}")),
54 )),
55 }
56 } else {
57 Err(Error::new(
58 StatusCode::INTERNAL_SERVER_ERROR,
59 Some("Failed to get online players".to_string()),
60 ))
61 }
62}
63
64pub async fn get_online_players_full() -> Result<Vec<Player>, Error> {
71 let mut players = Vec::new();
72
73 for player in get_online_players().await? {
74 players.push(get_player(&player).await?);
75 }
76
77 Ok(players)
78}
79
80pub async fn get_registered_player_count() -> Result<u64, Error> {
82 let response = reqwest::get(format!("{API_URL}/registered-users.json")).await;
83
84 if let Ok(count) = response {
85 let count = count.json::<u64>().await;
86
87 match count {
88 Ok(count) => Ok(count),
89 Err(e) => Err(Error::new(
90 StatusCode::INTERNAL_SERVER_ERROR,
91 Some(format!("Failed to parse registered user count: {e}")),
92 )),
93 }
94 } else {
95 Err(Error::new(
96 StatusCode::INTERNAL_SERVER_ERROR,
97 Some("Failed to get registered user count".to_string()),
98 ))
99 }
100}
101
102pub async fn get_leaderboard_page(page: Option<u32>) -> Result<LeaderboardPage, Error> {
109 let response = if let Some(page) = page {
110 reqwest::get(format!("{API_URL}/leaderboards.json?page={page}")).await
111 } else {
112 reqwest::get(format!("{API_URL}/leaderboards.json")).await
113 };
114
115 if let Ok(leaderboard) = response {
116 let leaderboard = leaderboard.json::<LeaderboardPage>().await;
117
118 match leaderboard {
119 Ok(leaderboard) => Ok(leaderboard),
120 Err(e) => Err(Error::new(
121 StatusCode::INTERNAL_SERVER_ERROR,
122 Some(format!("Failed to parse leaderboard: {e}")),
123 )),
124 }
125 } else {
126 Err(Error::new(
127 StatusCode::INTERNAL_SERVER_ERROR,
128 Some("Failed to get leaderboard".to_string()),
129 ))
130 }
131}
132
133pub async fn get_top_players() -> Result<LeaderboardPage, Error> {
138 let results = get_leaderboard_page(Some(1)).await?;
139
140 Ok(results)
141}
142
143pub fn get_leaderboard() -> Leaderboard {
149 Leaderboard::new()
150}
151
152#[cfg(test)]
153mod tests {
154 use chrono::DateTime;
155
156 use super::*;
157
158 #[tokio::test]
159 async fn test_get_player() {
160 let player = get_player("Gliss").await;
161 assert!(player.is_ok());
162 }
163
164 #[tokio::test]
165 async fn test_get_player_not_found() {
166 let player = get_player("a4iujtoisdjugfoiasjuhroighasoidg").await;
167 assert!(player.is_err());
168 }
169
170 #[tokio::test]
171 async fn test_get_player_eq() {
172 let player = get_player("Gliss").await;
173
174 if let Ok(player) = player {
175 assert_eq!(player.username, "Gliss");
176 assert_eq!(
177 player.registered_at,
178 DateTime::parse_from_rfc3339("2020-11-10T05:05:02.000Z").unwrap()
179 );
180 }
181 }
182
183 #[tokio::test]
184 async fn test_get_players_online() {
185 let players = get_online_players().await;
186 assert!(players.is_ok());
187 }
188
189 #[tokio::test]
190 async fn test_registered_users() {
191 let count = get_registered_player_count().await;
192 assert!(count.is_ok());
193 assert!(count.unwrap() > 0);
194 }
195
196 #[tokio::test]
197 async fn test_leaderboard() {
198 let leaderboard = get_leaderboard_page(None).await;
199 assert!(leaderboard.is_ok());
200 assert!(!leaderboard.unwrap().is_empty());
201 }
202
203 #[tokio::test]
204 async fn test_leaderboard_page() {
205 let leaderboard = get_leaderboard_page(Some(1)).await;
206 assert!(leaderboard.is_ok());
207 assert!(!leaderboard.unwrap().is_empty());
208 }
209}