gn_ranking_client_rs/
lib.rs1use std::{collections::HashMap, env, fs, path::PathBuf, result};
2
3use reqwest;
4use serde::de::DeserializeOwned;
5
6pub mod models;
7
8
9pub struct RankingClient {
10 client: reqwest::Client,
11 api_key: String,
12 routes: HashMap<String, models::Route>,
13}
14
15impl RankingClient {
16
17 pub fn new(api_key: String) -> Self {
18 let routes = Self::load_default_routes();
19
20 Self {
21 client: reqwest::Client::new(),
22 api_key,
23 routes,
24 }
25 }
26
27 fn load_default_routes() -> HashMap<String, models::Route> {
28 let content = Self::substitute_env_vars(include_str!("../routes.yml"));
29 serde_yaml::from_str(&content).expect("Failed to parse routes file")
30 }
31
32 fn substitute_env_vars(content: &str) -> String {
33 let mut substituted = content.to_string();
34 for (key, value) in env::vars() {
35 let placeholder = format!("${{{}}}", key);
36 substituted = substituted.replace(&placeholder, &value);
37 }
38 substituted
39 }
40
41
42 pub fn load_route_conf(&mut self, path: &str) {
43 let routes = Self::load_routes(PathBuf::from(path));
44 self.routes = routes;
45 }
46
47 pub async fn create<'a, M, R>(&self, model: M, route_id: &str) -> Result<R, Box<dyn std::error::Error>>
48 where
49 M: serde::Serialize,
50 R: DeserializeOwned
51 {
52 let url = &self.routes.get(route_id).unwrap().path;
53
54 let response = self.client.post(url).json(&model).header("access_token", &self.api_key).send().await?.error_for_status()?;
55
56 Ok(response.json().await?)
57 }
58
59 pub async fn read<'a, F, R>(&self, filter: F, route_id: &str) -> Result<R, Box<dyn std::error::Error>>
60 where
61 F: serde::Serialize,
62 R: DeserializeOwned
63 {
64 let url = &self.routes.get(route_id).unwrap().path;
65
66 let response = self.client.get(url).query(&filter).header("access_token", &self.api_key).send().await?.error_for_status()?;
67
68 Ok(response.json().await?)
69 }
70
71 pub async fn game_init(&self, game: models::create::Game) -> Result<models::read::Game, Box<dyn std::error::Error>> {
72 Ok(self.create(game, "game_init").await?)
73 }
74
75 pub async fn match_replay_create(&self, result: models::create::ReplayData) -> Result<models::read::Game, Box<dyn std::error::Error>> {
76 Ok(self.create(result, "replay_data").await?)
77 }
78
79 pub async fn game_read(&self, filter: models::filter::Game) -> Result<Vec<models::read::Game>, Box<dyn std::error::Error>> {
80 Ok(self.read(filter, "game_read").await?)
81 }
82
83 pub async fn match_init(&self, _match: models::create::Match) -> Result<models::read::Match, Box<dyn std::error::Error>> {
84 Ok(self.create(_match, "match_init").await?)
85 }
86
87 pub async fn player_games_read(&self, filter: models::filter::PlayerGame) -> Result<Vec<models::read::PlayerGame>, Box<dyn std::error::Error>> {
88 Ok(self.read(filter, "player_games_read").await?)
89 }
90
91 pub async fn player_stars(&self, player_id: &str, game_name: &str, game_mode: &str) -> Result<i32, Box<dyn std::error::Error>> {
92 let filter = models::filter::PlayerGame {
93 player_id: Some(player_id.to_string()),
94 game_name: Some(game_name.to_string()),
95 game_mode: Some(game_mode.to_string()),
96 in_order: Some(true),
97 };
98 Ok(self.player_games_read(filter).await?.first().ok_or_else(|| "Game not found")?.game_stars)
99 }
100
101 fn load_routes(path: PathBuf) -> HashMap<String, models::Route> {
102 let content = fs::read_to_string(path).expect("Failed to read routes file");
103 let content = Self::substitute_env_vars(content.as_str());
104 serde_yaml::from_str(&content).expect("Failed to parse routes file")
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112}