rarbg_api/
token.rs

1extern crate reqwest;
2
3use std::collections::HashMap;
4use std::time::SystemTime;
5
6use crate::ENDPOINT;
7use crate::USER_AGENT;
8
9use reqwest::{Client, Response};
10use serde::{Deserialize, Serialize};
11
12#[derive(Clone, Serialize, Deserialize, Debug)]
13pub struct Token {
14    value: String,
15    created_at: SystemTime,
16}
17
18impl Token {
19    /// Return the value of the token obtained from the API.
20    ///
21    /// # Example
22    ///
23    /// ```no_run
24    /// use rarbg_api::token::Token;
25    ///
26    /// #[tokio::main]
27    /// async fn main() {
28    ///     let token = Token::new("RustExample").await;
29    ///     let value = token.value();
30    /// }
31    /// ```
32    pub fn value(&self) -> &str {
33        self.value.as_str()
34    }
35
36    /// Returns the time when the token was created.
37    ///
38    /// # Example
39    ///
40    /// ```no_run
41    /// use rarbg_api::token::Token;
42    ///
43    /// #[tokio::main]
44    /// async fn main() {
45    ///     let token = Token::new("RustExample").await;
46    ///     let time_of_creation = token.created_at();
47    /// }
48    /// ```
49    pub fn created_at(&self) -> &SystemTime {
50        &self.created_at
51    }
52
53    /// Create a Token with the value obtained from the API.
54    /// This token can be use to make requests to the API.
55    ///
56    /// # Panics
57    ///
58    /// Panics if a token cannot be retrieve from the API.
59    ///
60    /// # Example
61    ///
62    /// ```no_run
63    /// use rarbg_api::token::Token;
64    ///
65    /// #[tokio::main]
66    /// async fn main() {
67    ///     let token = Token::new("RustExample").await;
68    /// }
69    /// ```
70    pub async fn new(app_id: &str) -> Self {
71        let response = Token::get(app_id).await;
72        let content = Token::parse(response).await;
73        let value = content.get("token");
74        match value {
75            Some(token) => Token {
76                value: token.clone(),
77                created_at: SystemTime::now(),
78            },
79            None => panic!("Failed to retrieve a token from RARBG API."),
80        }
81    }
82
83    async fn get(app_id: &str) -> Response {
84        let client: Client = Client::builder().user_agent(USER_AGENT).build().unwrap();
85        let response = client
86            .get(ENDPOINT)
87            .query(&[("get_token", "get_token")])
88            .query(&[("app_id", app_id)])
89            .send()
90            .await;
91        match response {
92            Ok(response) => response,
93            Err(reason) => panic!("{}", reason),
94        }
95    }
96
97    async fn parse(response: Response) -> HashMap<String, String> {
98        match response.json().await {
99            Ok(json) => json,
100            Err(reason) => panic!("{}", reason),
101        }
102    }
103
104    /// Verifies that the token is still valid to use it with the API.
105    /// Officially, a token is valid for 15 minutes but we keep this token valid for 10 minutes.
106    ///
107    /// # Example
108    ///
109    /// ```no_run
110    /// use rarbg_api::token::Token;
111    ///
112    /// #[tokio::main]
113    /// async fn main() {
114    ///     let token = Token::new("RustExample").await;
115    ///     assert!(token.is_valid(), "Token should be valid !");
116    /// }
117    /// ```
118    pub fn is_valid(&self) -> bool {
119        let sys_time = SystemTime::now();
120        let difference = sys_time.duration_since(self.created_at);
121        match difference {
122            Ok(duration) => {
123                duration.as_secs() as f64 + f64::from(duration.subsec_nanos()) * 1e-9 < 600.0
124            } // < 10 min
125            Err(_) => false,
126        }
127    }
128}