1 | use url::Url; |
2 | use ureq::Error; |
3 | use serde::{Serialize, Deserialize}; |
4 | use std::{time::Duration, thread}; |
5 | |
6 | use crate::Client; |
7 | |
8 | pub trait BaseApi<'a> |
9 | where |
10 | Self::Model: Serialize + for<'de> Deserialize<'de> |
11 | { |
12 | type Model; |
13 | |
14 | fn path(&self) -> &str; |
15 | fn params(&self) -> Vec<(&str, String)>; |
16 | fn client(&self) -> &'a Client; |
17 | |
18 | fn call(&self) -> Result<Self::Model, ureq::Error> { |
19 | let client = self.client(); |
20 | let url = Url::parse_with_params( |
21 | format!( |
22 | "http {}://api.weatherapi.com/v1/ {}.json" , |
23 | if client.https { "s" } else { "" }, |
24 | self.path() |
25 | ).as_str(), |
26 | &self.params() |
27 | )?; |
28 | |
29 | for _ in 1..2 { |
30 | match client.agent.request_url("GET" , &url).call() { |
31 | Err(Error::Status(503, r)) | Err(Error::Status(429, r)) => { |
32 | let retry: Option<u64> = r.header("retry-after" ) |
33 | .and_then(|h| h.parse().ok()); |
34 | let retry = retry.unwrap_or(5); |
35 | thread::sleep(Duration::from_secs(retry)); |
36 | } |
37 | result => return Ok(result?.into_json()?), |
38 | }; |
39 | } |
40 | |
41 | // Ran out of retries; try one last time and return whatever result we get. |
42 | Ok(client.agent.request_url("GET" , &url).call()?.into_json()?) |
43 | } |
44 | } |
45 | |