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
34pub 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 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 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}