r6tracker/
client.rs

1use crate::{
2    types::{
3        sessions_data::SessionsData,
4        user_data::UserData,
5        ApiResponse,
6        OverwolfPlayer,
7        OverwolfResponse,
8        Platform,
9    },
10    Error,
11};
12use serde::de::DeserializeOwned;
13use url::Url;
14
15/// R6tracker Client
16#[derive(Debug, Clone)]
17pub struct Client {
18    /// The inner http client
19    pub client: reqwest::Client,
20}
21
22impl Client {
23    /// Make a new client
24    pub fn new() -> Self {
25        Client {
26            client: reqwest::Client::new(),
27        }
28    }
29
30    /// Get a url and return it as an [`ApiResponse`].
31    async fn get_api_response<T>(&self, url: &str) -> Result<ApiResponse<T>, Error>
32    where
33        T: DeserializeOwned,
34    {
35        Ok(self.client.get(url).send().await?.json().await?)
36    }
37
38    /// Get a url and return an [`OverwolfResponse`]
39    async fn get_overwolf_response<T>(&self, url: &str) -> Result<OverwolfResponse<T>, Error>
40    where
41        T: DeserializeOwned,
42    {
43        Ok(self
44            .client
45            .get(url)
46            .send()
47            .await?
48            .error_for_status()?
49            .json()
50            .await?)
51    }
52
53    /// Get an r6tracker profile
54    pub async fn get_profile(
55        &self,
56        name: &str,
57        platform: Platform,
58    ) -> Result<ApiResponse<UserData>, Error> {
59        if name.is_empty() {
60            return Err(Error::EmptyUsername);
61        }
62
63        let platform = platform.as_u32();
64        let url = format!("https://r6.tracker.network/api/v1/standard/profile/{platform}/{name}/");
65
66        self.get_api_response(&url).await
67    }
68
69    /// Get the sessions for a user
70    pub async fn get_sessions(
71        &self,
72        name: &str,
73        platform: Platform,
74    ) -> Result<ApiResponse<SessionsData>, Error> {
75        if name.is_empty() {
76            return Err(Error::EmptyUsername);
77        }
78
79        let platform = platform.as_u32();
80        let url = format!(
81            "https://r6.tracker.network/api/v1/standard/profile/{platform}/{name}/sessions?"
82        );
83
84        self.get_api_response(&url).await
85    }
86
87    /// Get player info using the Overwolf API.
88    pub async fn get_overwolf_player(
89        &self,
90        name: &str,
91    ) -> Result<OverwolfResponse<OverwolfPlayer>, Error> {
92        if name.is_empty() {
93            return Err(Error::EmptyUsername);
94        }
95
96        let url = Url::parse_with_params(
97            "https://r6.tracker.network/api/v0/overwolf/player",
98            &[("name", name)],
99        )?;
100
101        self.get_overwolf_response(url.as_str()).await
102    }
103
104    // TODO: Investigate https://r6.tracker.network/api/v0/overwolf/operators
105}
106
107impl Default for Client {
108    fn default() -> Self {
109        Client::new()
110    }
111}
112
113#[cfg(test)]
114mod test {
115    use super::*;
116
117    const VALID_USER: &str = "smack.jjfozzil";
118    const INVALID_USER: &str = "aaaaabbaaaa";
119
120    // TODO: Fix this
121    #[ignore]
122    #[tokio::test]
123    async fn it_works() {
124        let client = Client::new();
125
126        let profile = client
127            .get_profile(VALID_USER, Platform::Pc)
128            .await
129            .expect("failed to get profile")
130            .into_result();
131        dbg!(profile.unwrap());
132
133        let sessions = client.get_sessions(VALID_USER, Platform::Pc).await.unwrap();
134        dbg!(sessions.take_valid().unwrap());
135    }
136
137    // TODO: Fix this
138    #[ignore]
139    #[tokio::test]
140    async fn it_works_overwolf() {
141        let client = Client::new();
142
143        let profile = client
144            .get_overwolf_player(VALID_USER)
145            .await
146            .expect("failed to get overwolf player");
147        let profile_data = profile.take_valid().expect("missing profile data");
148        dbg!(&profile_data);
149    }
150
151    #[tokio::test]
152    async fn empty_user() {
153        let client = Client::new();
154
155        let profile_err = client.get_profile("", Platform::Pc).await.unwrap_err();
156        assert!(matches!(profile_err, Error::EmptyUsername));
157
158        let sessions_err = client.get_sessions("", Platform::Pc).await.unwrap_err();
159        assert!(matches!(sessions_err, Error::EmptyUsername));
160    }
161
162    // TODO: Fix this
163    #[ignore]
164    #[tokio::test]
165    async fn invalid_user() {
166        let client = Client::new();
167
168        let profile_err = client
169            .get_profile(INVALID_USER, Platform::Pc)
170            .await
171            .unwrap()
172            .take_invalid()
173            .unwrap();
174        dbg!(profile_err);
175
176        // This errors unpredictably when the user does not exist
177        /*
178        let sessions_data = client
179            .get_sessions(INVALID_USER, Platform::Pc)
180            .await
181            .unwrap()
182            .take_valid()
183            .unwrap();
184        assert!(sessions_data.items.is_empty());
185        dbg!(sessions_data);
186        */
187    }
188}