1use std::borrow::Borrow;
2use crate::error_handling::Errors;
3use reqwest::header::HeaderMap;
4use serde::Deserialize;
5use serde_json::json;
6use std::time::{ Instant};
7use reqwest::{ Response, Url};
8const ENDPOINT_NA: &str = "https://sellingpartnerapi-na.amazon.com";
9const ENDPOINT_EU: &str = "https://sellingpartnerapi-eu.amazon.com";
10const ENDPOINT_FE: &str = "https://sellingpartnerapi-fe.amazon.com";
11
12pub enum CountryMarketplace {
13 Canada,
14 UnitedStates,
15 Mexico,
16 Brazil,
17 Ireland,
18 Spain,
19 UnitedKingdom,
20 France,
21 Belgium,
22 Netherlands,
23 Germany,
24 Italy,
25 Sweden,
26 SouthAfrica,
27 Poland,
28 Egypt,
29 Turkey,
30 SaudiArabia,
31 UnitedArabEmirates,
32 India,
33 Singapore,
34 Australia,
35 Japan,
36}
37pub struct ClientInformation {
38 pub refresh_token: String,
39 pub client_id: String,
40 pub client_secret: String,
41 pub country_marketplace: CountryMarketplace,
42}
43#[allow(dead_code)]
44#[derive(Deserialize)]
45struct AccessToken {
46 access_token: String,
47 expires_in: i64,
48 refresh_token: String,
49 token_type: String,
50}
51
52impl ClientInformation {
53 async fn get_access_token(&self, x: &reqwest::Client) -> Result<AccessToken, Errors> {
54 let ff = json!({
55 "refresh_token": self.refresh_token,
56 "client_id": self.client_id,
57 "client_secret":self.client_secret,
58 "grant_type": "refresh_token"});
59
60 Ok(x.request(
61 reqwest::Method::POST,
62 "https://api.amazon.com/auth/o2/token",
63 )
64 .body(ff.to_string())
65 .send()
66 .await?
67 .json::<AccessToken>()
68 .await?)
69 }
70}
71impl CountryMarketplace {
72 pub fn details(&self) -> (&'static str, &'static str) {
74 match self {
75 CountryMarketplace::Canada => ("A2EUQ1WTGCTBG2", ENDPOINT_NA),
76 CountryMarketplace::UnitedStates => ("ATVPDKIKX0DER", ENDPOINT_NA),
77 CountryMarketplace::Mexico => ("A1AM78C64UM0Y8", ENDPOINT_NA),
78 CountryMarketplace::Brazil => ("A2Q3Y263D00KWC", ENDPOINT_NA),
79 CountryMarketplace::Ireland => ("A28R8C7NBKEWEA", ENDPOINT_EU),
80 CountryMarketplace::Spain => ("A1RKKUPIHCS9HS", ENDPOINT_EU),
81 CountryMarketplace::UnitedKingdom => ("A1F83G8C2ARO7P", ENDPOINT_EU),
82 CountryMarketplace::France => ("A13V1IB3VIYZZH", ENDPOINT_EU),
83 CountryMarketplace::Belgium => ("AMEN7PMS3EDWL", ENDPOINT_EU),
84 CountryMarketplace::Netherlands => ("A1805IZSGTT6HS", ENDPOINT_EU),
85 CountryMarketplace::Germany => ("A1PA6795UKMFR9", ENDPOINT_EU),
86 CountryMarketplace::Italy => ("APJ6JRA9NG5V4", ENDPOINT_EU),
87 CountryMarketplace::Sweden => ("A2NODRKZP88ZB9", ENDPOINT_EU),
88 CountryMarketplace::SouthAfrica => ("AE08WJ6YKNBMC", ENDPOINT_EU),
89 CountryMarketplace::Poland => ("A1C3SOZRARQ6R3", ENDPOINT_EU),
90 CountryMarketplace::Egypt => ("ARBP9OOSHTCHU", ENDPOINT_EU),
91 CountryMarketplace::Turkey => ("A33AVAJ2PDY3EV", ENDPOINT_EU),
92 CountryMarketplace::SaudiArabia => ("A17E79C6D8DWNP", ENDPOINT_EU),
93 CountryMarketplace::UnitedArabEmirates => ("A2VIGQ35RCS4UG", ENDPOINT_EU),
94 CountryMarketplace::India => ("A21TJRUUN4KGV", ENDPOINT_EU),
95 CountryMarketplace::Singapore => ("A19VAU5U5O7RUS", ENDPOINT_FE),
96 CountryMarketplace::Australia => ("A39IBJ37TRP1C6", ENDPOINT_FE),
97 CountryMarketplace::Japan => ("A1VC38T7YXB528", ENDPOINT_FE),
98 }
99 }
100}
101#[macro_export] macro_rules! enum_to_string {
102 ($($type:ty)*) => {
103 stringify!($($type)*)
104 };
105}
106#[allow(dead_code)]
107pub struct Client {
108 access_token: AccessToken,
109 client_information: ClientInformation,
110 last_refresh: Instant,
111 reqwest_client: reqwest::Client,
112}
113impl Client {
114 async fn refresh_token(&mut self) {
115 match self
116 .client_information
117 .get_access_token(&self.reqwest_client).await
118 {
119 Ok(o) => self.access_token = o,
120 Err(_) => {}
121 }
122 }
123 pub async fn new(client: ClientInformation) -> Result<Self, Errors> {
124 let reqwest_client = reqwest::Client::new();
125 match client.get_access_token(&reqwest_client).await {
126 Ok(o) => Ok(Client {
127 access_token: o,
128 client_information: client,
129 last_refresh: Instant::now(),
130 reqwest_client,
131 }),
132 Err(e) => Err(e),
133 }
134 }
135 async fn check_validity(&mut self) {
136 if Instant::now().duration_since(self.last_refresh).as_secs()
137 > (self.access_token.expires_in - 10) as u64
138 {
139 self.refresh_token().await;
140 }
141 }
142 fn create_header(&mut self) -> HeaderMap {
143 let mut header_map = HeaderMap::new();
144 header_map.insert("x-amz-access-token", self.access_token.access_token.parse().unwrap());
145 header_map.insert("CONTENT_TYPE", "application/json".parse().unwrap());
146 header_map.insert("user-agent", "Amazon-SP-API-rs 0.1.0".parse().unwrap());
147 header_map
148 }
149 pub async fn make_request<I, K, V>(&mut self, path: &str, method: reqwest::Method, parameters: Option<I>) -> Result<Response, Errors>
150 where
151 I: IntoIterator + std::fmt::Debug+ Clone,
152 I::Item: Borrow<(K, V)>,
153 K: AsRef<str>,
154 V: AsRef<str>,
155 {
156 if let Some(params) = parameters {
158 Ok(self.reqwest_client.request(method, Url::parse_with_params(format!("{}{}", self.client_information.country_marketplace.details().1, path).as_str(), params)?).headers(self.create_header()).send().await?)
159 } else {
160 Ok(self.reqwest_client.request(method, Url::parse(format!("{}{}", self.client_information.country_marketplace.details().1, path).as_str())?).headers(self.create_header()).send().await?)
161
162 }
163 }
165 pub async fn make_request_w_body<I, K, V>(&mut self, path: &str, method: reqwest::Method, parameters: Option<I>, body: String) -> Result<Response, Errors>
166 where
167 I: IntoIterator + std::fmt::Debug,
168 I::Item: Borrow<(K, V)>,
169 K: AsRef<str>,
170 V: AsRef<str>,
171 {
172 if let Some(param) = parameters {
173 Ok(self.reqwest_client.request(method, Url::parse_with_params(format!("{}{}",self.client_information.country_marketplace.details().1, path).as_str(), param)?).headers(self.create_header()).body(body).send().await?)
174 } else {
175 Ok(self.reqwest_client.request(method, Url::parse(format!("{}{}",self.client_information.country_marketplace.details().1, path).as_str())?).headers(self.create_header()).body(body).send().await?)
176 }
177 }
178
179}