gn_ranking_client_rs/
lib.rs

1use 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}