nadeo_api_rs/
client.rs

1use log::debug;
2use reqwest::header::{HeaderValue, AUTHORIZATION, CONTENT_LENGTH};
3pub use reqwest::{Error as RqError, RequestBuilder, Response};
4pub use serde_json::Value;
5use tokio::sync::{SemaphorePermit, TryLockError};
6
7use crate::{auth::*, urls::*};
8
9pub enum MonthlyCampaignType {
10    Royal,
11    TOTD,
12}
13
14/// Run a rate-limited request
15pub async fn run_req<'a>(
16    (req, permit): (RequestBuilder, SemaphorePermit<'a>),
17) -> Result<Value, RqError> {
18    let start = std::time::Instant::now();
19    // let r = req.send().await?.json().await?;
20    let (client, req) = req.build_split();
21    let req = req?;
22    let url = req.url().to_string();
23    let resp = client.execute(req).await?;
24    let resp = resp.error_for_status()?;
25    let r = resp.json().await?;
26    debug!(
27        "Request took: {:.3} s ( URL = {} )",
28        start.elapsed().as_secs_f64(),
29        url
30    );
31    drop(permit);
32    Ok(r)
33}
34
35pub trait NadeoApiClient {
36    async fn get_client(&self) -> &reqwest::Client;
37
38    async fn rate_limit(&self) -> SemaphorePermit;
39
40    async fn get_file_size(&self, url: &str) -> Result<u64, RqError> {
41        let resp = self.get_client().await.head(url).send().await?;
42        Ok(resp
43            .headers()
44            .get(CONTENT_LENGTH)
45            .map_or(0, |v| v.to_str().unwrap_or("0").parse().unwrap_or(1)))
46    }
47
48    fn get_auth_token(&self, audience: NadeoAudience) -> Result<String, TryLockError>;
49
50    async fn aget_auth_token(&self, audience: NadeoAudience) -> String;
51
52    fn get_auth_header(&self, audience: NadeoAudience) -> Result<String, TryLockError> {
53        Ok(format!("nadeo_v1 t={}", &self.get_auth_token(audience)?))
54    }
55
56    async fn aget_auth_header(&self, audience: NadeoAudience) -> String {
57        format!("nadeo_v1 t={}", &self.aget_auth_token(audience).await)
58    }
59
60    async fn get_auth_header_value(&self, audience: NadeoAudience) -> HeaderValue {
61        let mut hv = HeaderValue::from_str(&self.aget_auth_header(audience).await).unwrap();
62        hv.set_sensitive(true);
63        hv
64    }
65
66    async fn oauth_get<'a>(
67        &self,
68        path: &str,
69        token: &OAuthToken,
70        _permit: &SemaphorePermit<'a>,
71    ) -> RequestBuilder {
72        let rb = self
73            .get_client()
74            .await
75            .get(&format!("{}{}", OAUTH_URL, path))
76            .header(AUTHORIZATION, token.get_authz_header());
77        rb
78    }
79
80    async fn core_get(&self, path: &str) -> (RequestBuilder, SemaphorePermit) {
81        (
82            self.get_client()
83                .await
84                .get(&format!("{}{}", CORE_URL, path))
85                .header(AUTHORIZATION, self.get_auth_header_value(Core).await),
86            self.rate_limit().await,
87        )
88    }
89
90    async fn run_core_get(&self, path: &str) -> Result<Value, RqError> {
91        run_req(self.core_get(path).await).await
92    }
93
94    async fn core_post_bytes(&self, path: &str, body: &[u8]) -> (RequestBuilder, SemaphorePermit) {
95        (
96            self.get_client()
97                .await
98                .post(&format!("{}{}", CORE_URL, path))
99                .header(AUTHORIZATION, self.get_auth_header_value(Core).await)
100                .body(body.to_vec()),
101            self.rate_limit().await,
102        )
103    }
104    async fn run_core_post_bytes(&self, path: &str, body: &[u8]) -> Result<Value, RqError> {
105        run_req(self.core_post_bytes(path, body).await).await
106    }
107
108    async fn core_post(&self, path: &str, body: &Value) -> (RequestBuilder, SemaphorePermit) {
109        (
110            self.get_client()
111                .await
112                .post(&format!("{}{}", CORE_URL, path))
113                .header(AUTHORIZATION, self.get_auth_header_value(Core).await)
114                .json(body),
115            self.rate_limit().await,
116        )
117    }
118    async fn run_core_post(&self, path: &str, body: &Value) -> Result<Value, RqError> {
119        run_req(self.core_post(path, body).await).await
120    }
121
122    async fn live_get(&self, path: &str) -> (RequestBuilder, SemaphorePermit) {
123        (
124            self.get_client()
125                .await
126                .get(&format!("{}{}", LIVE_URL, path))
127                .header(AUTHORIZATION, self.get_auth_header_value(Live).await),
128            self.rate_limit().await,
129        )
130    }
131    async fn run_live_get(&self, path: &str) -> Result<Value, RqError> {
132        run_req(self.live_get(path).await).await
133    }
134
135    async fn live_post_bytes(&self, path: &str, body: &[u8]) -> (RequestBuilder, SemaphorePermit) {
136        (
137            self.get_client()
138                .await
139                .post(&format!("{}{}", LIVE_URL, path))
140                .header(AUTHORIZATION, self.get_auth_header_value(Live).await)
141                .body(body.to_vec()),
142            self.rate_limit().await,
143        )
144    }
145    async fn run_live_post_bytes(&self, path: &str, body: &[u8]) -> Result<Value, RqError> {
146        run_req(self.live_post_bytes(path, body).await).await
147    }
148
149    async fn live_post(&self, path: &str, body: &Value) -> (RequestBuilder, SemaphorePermit) {
150        (
151            self.get_client()
152                .await
153                .post(&format!("{}{}", LIVE_URL, path))
154                .header(AUTHORIZATION, self.get_auth_header_value(Live).await)
155                .json(body),
156            self.rate_limit().await,
157        )
158    }
159    async fn run_live_post(&self, path: &str, body: &Value) -> Result<Value, RqError> {
160        run_req(self.live_post(path, body).await).await
161    }
162
163    async fn meet_get(&self, path: &str) -> (RequestBuilder, SemaphorePermit) {
164        (
165            self.get_client()
166                .await
167                .get(&format!("{}{}", MEET_URL, path))
168                .header(AUTHORIZATION, self.get_auth_header_value(Live).await),
169            self.rate_limit().await,
170        )
171    }
172    async fn run_meet_get(&self, path: &str) -> Result<Value, RqError> {
173        run_req(self.meet_get(path).await).await
174    }
175
176    async fn meet_post_bytes(&self, path: &str, body: &[u8]) -> (RequestBuilder, SemaphorePermit) {
177        (
178            self.get_client()
179                .await
180                .post(&format!("{}{}", MEET_URL, path))
181                .header(AUTHORIZATION, self.get_auth_header_value(Live).await)
182                .body(body.to_vec()),
183            self.rate_limit().await,
184        )
185    }
186    async fn run_meet_post_bytes(&self, path: &str, body: &[u8]) -> Result<Value, RqError> {
187        run_req(self.meet_post_bytes(path, body).await).await
188    }
189
190    async fn meet_post(&self, path: &str, body: &Value) -> (RequestBuilder, SemaphorePermit) {
191        (
192            self.get_client()
193                .await
194                .post(&format!("{}{}", MEET_URL, path))
195                .header(AUTHORIZATION, self.get_auth_header_value(Live).await)
196                .json(body),
197            self.rate_limit().await,
198        )
199    }
200    async fn run_meet_post(&self, path: &str, body: &Value) -> Result<Value, RqError> {
201        run_req(self.meet_post(path, body).await).await
202    }
203}