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;
31pub mod login;
33
34pub mod commerce;
36
37pub mod status;
39
40pub mod presence;
42
43#[derive(Debug, Clone)]
44pub(crate) struct EpicAPI {
45 client: Client,
46 pub(crate) user_data: UserData,
47}
48
49impl Default for EpicAPI {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl EpicAPI {
56 pub fn new() -> Self {
57 let mut headers = HeaderMap::new();
58 headers.insert(
59 "User-Agent",
60 "UELauncher/17.0.1-37584233+++Portal+Release-Live Windows/10.0.19043.1.0.64bit"
61 .parse()
62 .unwrap(),
63 );
64 headers.insert(
65 "X-Epic-Correlation-ID",
66 "UE4-c176f7154c2cda1061cc43ab52598e2b-93AFB486488A22FDF70486BD1D883628-BFCD88F649E997BA203FF69F07CE578C".parse().unwrap()
67 );
68 let client = reqwest::Client::builder()
69 .default_headers(headers)
70 .cookie_store(true)
71 .build()
72 .unwrap();
73 EpicAPI {
74 client,
75 user_data: Default::default(),
76 }
77 }
78
79 fn authorized_get_client(&self, url: Url) -> RequestBuilder {
80 self.set_authorization_header(self.client.get(url))
81 }
82
83 fn authorized_post_client(&self, url: Url) -> RequestBuilder {
84 self.set_authorization_header(self.client.post(url))
85 }
86
87 fn set_authorization_header(&self, rb: RequestBuilder) -> RequestBuilder {
88 rb.header(
89 "Authorization",
90 format!(
91 "{} {}",
92 self.user_data
93 .token_type
94 .as_ref()
95 .unwrap_or(&"bearer".to_string()),
96 self.user_data
97 .access_token
98 .as_ref()
99 .unwrap_or(&"".to_string())
100 ),
101 )
102 }
103
104 pub(crate) async fn authorized_get_json<T: DeserializeOwned>(
106 &self,
107 url: &str,
108 ) -> Result<T, EpicAPIError> {
109 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
110 let response = self
111 .authorized_get_client(parsed_url)
112 .send()
113 .await
114 .map_err(|e| {
115 error!("{:?}", e);
116 EpicAPIError::NetworkError(e)
117 })?;
118 if response.status() == reqwest::StatusCode::OK {
119 response.json::<T>().await.map_err(|e| {
120 error!("{:?}", e);
121 EpicAPIError::DeserializationError(format!("{}", e))
122 })
123 } else {
124 let status = response.status();
125 let body = response.text().await.unwrap_or_default();
126 warn!("{} result: {}", status, body);
127 Err(EpicAPIError::HttpError { status, body })
128 }
129 }
130
131 pub(crate) async fn authorized_post_form_json<T: DeserializeOwned>(
133 &self,
134 url: &str,
135 form: &[(String, String)],
136 ) -> Result<T, EpicAPIError> {
137 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
138 let response = self
139 .authorized_post_client(parsed_url)
140 .form(form)
141 .send()
142 .await
143 .map_err(|e| {
144 error!("{:?}", e);
145 EpicAPIError::NetworkError(e)
146 })?;
147 if response.status() == reqwest::StatusCode::OK {
148 response.json::<T>().await.map_err(|e| {
149 error!("{:?}", e);
150 EpicAPIError::DeserializationError(format!("{}", e))
151 })
152 } else {
153 let status = response.status();
154 let body = response.text().await.unwrap_or_default();
155 warn!("{} result: {}", status, body);
156 Err(EpicAPIError::HttpError { status, body })
157 }
158 }
159
160 pub(crate) async fn authorized_post_json<T: DeserializeOwned, B: serde::Serialize>(
162 &self,
163 url: &str,
164 body: &B,
165 ) -> Result<T, EpicAPIError> {
166 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
167 let response = self
168 .authorized_post_client(parsed_url)
169 .json(body)
170 .send()
171 .await
172 .map_err(|e| {
173 error!("{:?}", e);
174 EpicAPIError::NetworkError(e)
175 })?;
176 if response.status() == reqwest::StatusCode::OK {
177 response.json::<T>().await.map_err(|e| {
178 error!("{:?}", e);
179 EpicAPIError::DeserializationError(format!("{}", e))
180 })
181 } else {
182 let status = response.status();
183 let body = response.text().await.unwrap_or_default();
184 warn!("{} result: {}", status, body);
185 Err(EpicAPIError::HttpError { status, body })
186 }
187 }
188
189 pub(crate) async fn get_bytes(&self, url: &str) -> Result<Vec<u8>, EpicAPIError> {
191 let parsed_url = Url::parse(url).map_err(|_| EpicAPIError::InvalidParams)?;
192 let response = self
193 .client
194 .get(parsed_url)
195 .send()
196 .await
197 .map_err(|e| {
198 error!("{:?}", e);
199 EpicAPIError::NetworkError(e)
200 })?;
201 if response.status() == reqwest::StatusCode::OK {
202 response.bytes().await.map(|b| b.to_vec()).map_err(|e| {
203 error!("{:?}", e);
204 EpicAPIError::DeserializationError(format!("{}", e))
205 })
206 } else {
207 let status = response.status();
208 let body = response.text().await.unwrap_or_default();
209 warn!("{} result: {}", status, body);
210 Err(EpicAPIError::HttpError { status, body })
211 }
212 }
213}