rlstats/
lib.rs

1use reqwest::{
2    blocking::{Client, ClientBuilder},
3    header::{self, HeaderMap, HeaderValue},
4    Method,
5};
6use serde::{de::DeserializeOwned, Serialize};
7
8mod model;
9
10pub use model::*;
11
12const API_URL: &str = "https://api.rocketleaguestats.com/v1";
13
14#[derive(Debug)]
15pub enum Error {
16    Invalid,
17    ResponseCode(ResponseCode),
18    ReqwestError(reqwest::Error),
19    JsonError(serde_json::Error),
20}
21
22impl From<reqwest::Error> for Error {
23    fn from(err: reqwest::Error) -> Self {
24        Error::ReqwestError(err)
25    }
26}
27
28impl From<serde_json::Error> for Error {
29    fn from(err: serde_json::Error) -> Self {
30        Error::JsonError(err)
31    }
32}
33
34/// A client for the RocketLeagueStats api.
35pub struct RlStats(Client);
36
37impl RlStats {
38    pub fn new<K>(api_key: K) -> Result<Self, Error>
39    where
40        K: AsRef<str>,
41    {
42        let user_agent = format!(
43            "{} (v {})",
44            env!("CARGO_PKG_NAME"),
45            env!("CARGO_PKG_VERSION")
46        );
47
48        let headers = [
49            (header::AUTHORIZATION, api_key.as_ref()),
50            (header::ACCEPT, "application/json"),
51            (header::USER_AGENT, &user_agent),
52        ]
53        .iter()
54        .cloned()
55        .map(|(key, value)| (key, HeaderValue::from_str(value).unwrap()))
56        .collect::<HeaderMap>();
57
58        let client = ClientBuilder::new().default_headers(headers).build()?;
59
60        Ok(RlStats(client))
61    }
62
63    pub fn get_platforms(&self) -> Result<Vec<Platform>, Error> {
64        self.request("/data/platforms", Method::GET, ())
65    }
66
67    pub fn get_seasons(&self) -> Result<Vec<Season>, Error> {
68        self.request("/data/seasons", Method::GET, ())
69    }
70
71    pub fn get_playlists(&self) -> Result<Vec<Playlist>, Error> {
72        self.request("/data/playlists", Method::GET, ())
73    }
74
75    pub fn get_tiers(&self) -> Result<Vec<Tier>, Error> {
76        self.request("/data/tiers", Method::GET, ())
77    }
78
79    pub fn get_player(&self, unique_id: &str, platform_id: i32) -> Result<Player, Error> {
80        self.request(
81            format!(
82                "/player?unique_id={}&platform_id={}",
83                unique_id, platform_id
84            ),
85            Method::GET,
86            (),
87        )
88    }
89
90    /// Searches rocketleaguestats' player database, not Rocket League's.
91    pub fn search_players(&self, display_name: &str, page: u32) -> Result<SearchResponse, Error> {
92        self.request(
93            format!(
94                "/search/players?display_name={}&page={}",
95                display_name, page
96            ),
97            Method::GET,
98            (),
99        )
100    }
101
102    /// Retrieve more player data faster than you would otherwise be able to.
103    ///
104    /// The max batch size is 10. Players that are not found will simply be
105    /// excluded from the result.
106    pub fn batch_players(&self, players: Vec<BatchPlayer>) -> Result<Vec<Player>, Error> {
107        self.request("/player/batch", Method::POST, &players)
108    }
109
110    pub fn get_ranked_leaderboard(&self, playlist_id: i32) -> Result<Vec<Player>, Error> {
111        self.request(
112            format!("/leaderboard/ranked?playlist_id={}", playlist_id),
113            Method::GET,
114            (),
115        )
116    }
117
118    pub fn get_stat_leaderboard(&self, ty: &str) -> Result<Vec<Player>, Error> {
119        self.request(format!("/leaderboard/stat?type={}", ty), Method::GET, ())
120    }
121
122    fn request<E, T, J>(&self, endpoint: E, method: Method, j: J) -> Result<T, Error>
123    where
124        E: AsRef<str>,
125        T: DeserializeOwned,
126        J: Serialize,
127    {
128        let url = format!("{}{}", API_URL, endpoint.as_ref());
129        let body = self.0.request(method, &url).json(&j).send()?.text()?;
130
131        match serde_json::from_str::<T>(&body) {
132            Ok(r) => Ok(r),
133            _ => Err(Error::ResponseCode(serde_json::from_str(&body)?)),
134        }
135    }
136}