1use log::{error, warn};
2use reqwest::header::HeaderMap;
3use reqwest::{Client, RequestBuilder};
4use serde::de::DeserializeOwned;
5use types::account::UserData;
6use url::Url;
7
8use crate::api::error::EpicAPIError;
9
10pub mod types;
12
13pub mod utils;
15
16#[allow(dead_code)]
18pub(crate) mod binary_rw;
19
20pub mod error;
22
23pub mod fab;
25
26pub mod account;
28
29pub mod egs;
31#[allow(dead_code)]
32pub mod cloud_save;
34pub mod login;
36
37pub mod commerce;
39
40pub mod status;
42
43pub mod presence;
45
46pub mod store;
48
49pub mod cosmos;
51
52#[derive(Debug, Clone)]
53pub(crate) struct EpicAPI {
54 client: Client,
55 pub(crate) user_data: UserData,
56}
57
58impl Default for EpicAPI {
59 fn default() -> Self {
60 Self::new()
61 }
62}
63
64impl EpicAPI {
65 pub fn new() -> Self {
66 let mut headers = HeaderMap::new();
67 headers.insert(
68 "User-Agent",
69 "UELauncher/17.0.1-37584233+++Portal+Release-Live Windows/10.0.19043.1.0.64bit"
70 .parse()
71 .unwrap(),
72 );
73 headers.insert(
74 "X-Epic-Correlation-ID",
75 "UE4-c176f7154c2cda1061cc43ab52598e2b-93AFB486488A22FDF70486BD1D883628-BFCD88F649E997BA203FF69F07CE578C".parse().unwrap()
76 );
77 let client = reqwest::Client::builder()
78 .default_headers(headers)
79 .cookie_store(true)
80 .build()
81 .unwrap();
82 EpicAPI {
83 client,
84 user_data: Default::default(),
85 }
86 }
87
88 fn authorized_get_client(&self, url: Url) -> RequestBuilder {
89 self.set_authorization_header(self.client.get(url))
90 }
91
92 fn authorized_post_client(&self, url: Url) -> RequestBuilder {
93 self.set_authorization_header(self.client.post(url))
94 }
95
96 fn set_authorization_header(&self, rb: RequestBuilder) -> RequestBuilder {
97 rb.header(
98 "Authorization",
99 format!(
100 "{} {}",
101 self.user_data
102 .token_type
103 .as_ref()
104 .unwrap_or(&"bearer".to_string()),
105 self.user_data
106 .access_token
107 .as_ref()
108 .unwrap_or(&"".to_string())
109 ),
110 )
111 }
112
113 pub(crate) async fn authorized_get_json<T: DeserializeOwned>(
115 &self,
116 url: &str,
117 ) -> Result<T, EpicAPIError> {
118 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
119 let response = self
120 .authorized_get_client(parsed_url)
121 .send()
122 .await
123 .map_err(|e| {
124 error!("{:?}", e);
125 EpicAPIError::NetworkError(e)
126 })?;
127 if response.status() == reqwest::StatusCode::OK {
128 response.json::<T>().await.map_err(|e| {
129 error!("{:?}", e);
130 EpicAPIError::DeserializationError(format!("{}", e))
131 })
132 } else {
133 let status = response.status();
134 let body = response.text().await.unwrap_or_default();
135 warn!("{} result: {}", status, body);
136 Err(EpicAPIError::HttpError { status, body })
137 }
138 }
139
140 pub(crate) async fn authorized_post_form_json<T: DeserializeOwned>(
142 &self,
143 url: &str,
144 form: &[(String, String)],
145 ) -> Result<T, EpicAPIError> {
146 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
147 let response = self
148 .authorized_post_client(parsed_url)
149 .form(form)
150 .send()
151 .await
152 .map_err(|e| {
153 error!("{:?}", e);
154 EpicAPIError::NetworkError(e)
155 })?;
156 if response.status() == reqwest::StatusCode::OK {
157 response.json::<T>().await.map_err(|e| {
158 error!("{:?}", e);
159 EpicAPIError::DeserializationError(format!("{}", e))
160 })
161 } else {
162 let status = response.status();
163 let body = response.text().await.unwrap_or_default();
164 warn!("{} result: {}", status, body);
165 Err(EpicAPIError::HttpError { status, body })
166 }
167 }
168
169 pub(crate) async fn authorized_post_json<T: DeserializeOwned, B: serde::Serialize>(
171 &self,
172 url: &str,
173 body: &B,
174 ) -> Result<T, EpicAPIError> {
175 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
176 let response = self
177 .authorized_post_client(parsed_url)
178 .json(body)
179 .send()
180 .await
181 .map_err(|e| {
182 error!("{:?}", e);
183 EpicAPIError::NetworkError(e)
184 })?;
185 if response.status() == reqwest::StatusCode::OK {
186 response.json::<T>().await.map_err(|e| {
187 error!("{:?}", e);
188 EpicAPIError::DeserializationError(format!("{}", e))
189 })
190 } else {
191 let status = response.status();
192 let body = response.text().await.unwrap_or_default();
193 warn!("{} result: {}", status, body);
194 Err(EpicAPIError::HttpError { status, body })
195 }
196 }
197
198 pub(crate) async fn get_bytes(&self, url: &str) -> Result<Vec<u8>, EpicAPIError> {
200 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
201 let response = self
202 .client
203 .get(parsed_url)
204 .send()
205 .await
206 .map_err(|e| {
207 error!("{:?}", e);
208 EpicAPIError::NetworkError(e)
209 })?;
210 if response.status() == reqwest::StatusCode::OK {
211 response.bytes().await.map(|b| b.to_vec()).map_err(|e| {
212 error!("{:?}", e);
213 EpicAPIError::DeserializationError(format!("{}", e))
214 })
215 } else {
216 let status = response.status();
217 let body = response.text().await.unwrap_or_default();
218 warn!("{} result: {}", status, body);
219 Err(EpicAPIError::HttpError { status, body })
220 }
221 }
222
223 pub(crate) async fn get_json<T: DeserializeOwned>(
225 &self,
226 url: &str,
227 ) -> Result<T, EpicAPIError> {
228 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
229 let response = self.client.get(parsed_url).send().await.map_err(|e| {
230 error!("{:?}", e);
231 EpicAPIError::NetworkError(e)
232 })?;
233 if response.status() == reqwest::StatusCode::OK {
234 response.json::<T>().await.map_err(|e| {
235 error!("{:?}", e);
236 EpicAPIError::DeserializationError(format!("{}", e))
237 })
238 } else {
239 let status = response.status();
240 let body = response.text().await.unwrap_or_default();
241 warn!("{} result: {}", status, body);
242 Err(EpicAPIError::HttpError { status, body })
243 }
244 }
245
246 #[allow(dead_code)]
247 pub(crate) async fn authorized_delete(&self, url: &str) -> Result<(), EpicAPIError> {
249 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
250 let response = self
251 .set_authorization_header(self.client.delete(parsed_url))
252 .send()
253 .await
254 .map_err(|e| {
255 error!("{:?}", e);
256 EpicAPIError::NetworkError(e)
257 })?;
258 if response.status() == reqwest::StatusCode::OK
259 || response.status() == reqwest::StatusCode::NO_CONTENT
260 {
261 Ok(())
262 } else {
263 let status = response.status();
264 let body = response.text().await.unwrap_or_default();
265 warn!("{} result: {}", status, body);
266 Err(EpicAPIError::HttpError { status, body })
267 }
268 }
269}