1use url::Url;
2use ureq::Error;
3use serde::{Serialize, Deserialize};
4use std::{time::Duration, thread};
5
6use crate::Client;
7
8pub trait BaseApi<'a>
9where
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