#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]
use chrono;
use reqwest::header;
use log::{error,info,warn};
use api::types::asset_info::{AssetInfo, GameToken};
use api::types::asset_manifest::{AssetManifest, Manifest};
use api::types::download_manifest::DownloadManifest;
use api::types::library::Library;
use api::types::entitlement::Entitlement;
use crate::api::types::epic_asset::EpicAsset;
use crate::api::{EpicAPI, EpicAPIError, UserData};
pub mod api;
#[derive(Default, Debug, Clone)]
pub struct EpicGames {
egs: EpicAPI,
}
impl EpicGames {
pub fn new() -> Self {
EpicGames {
egs: EpicAPI::new(),
}
}
pub fn is_logged_in(&self) -> bool {
match self.egs.user_data.expires_at {
None => {}
Some(exp) => {
let now = chrono::offset::Utc::now();
let td = exp - now;
if td.num_seconds() > 600 {
return true;
}
}
}
return false;
}
pub fn user_details(&self) -> UserData {
self.egs.user_data.clone()
}
pub fn set_user_details(&mut self, user_details: UserData) {
self.egs.user_data.update(user_details);
}
pub async fn auth_sid(&self, sid: &str) -> Option<String> {
let mut headers = header::HeaderMap::new();
headers.insert("X-Epic-Event-Action", "login".parse().unwrap());
headers.insert("X-Epic-Event-Category", "login".parse().unwrap());
headers.insert("X-Epic-Strategy-Flags", "".parse().unwrap());
headers.insert("X-Requested-With", "XMLHttpRequest".parse().unwrap());
headers.insert(
"User-Agent",
"EpicGamesLauncher/11.0.1-14907503+++Portal+Release-Live "
.parse()
.unwrap(),
);
let url = format!("https://www.epicgames.com/id/api/set-sid?sid={}", sid);
let client = reqwest::Client::builder()
.cookie_store(true)
.default_headers(headers)
.build()
.unwrap();
match client.get(&url).send().await {
Ok(_resp) => {}
_ => {}
}
let mut xsrf_token: String = "".to_string();
match client
.get("https://www.epicgames.com/id/api/csrf")
.send()
.await
{
Ok(resp) => {
for cookie in resp.cookies() {
if cookie.name().to_lowercase() == "xsrf-token" {
xsrf_token = cookie.value().to_string();
}
}
}
_ => {}
}
match client
.post("https://www.epicgames.com/id/api/exchange/generate")
.header("X-XSRF-TOKEN", xsrf_token)
.send()
.await
{
Ok(resp) => {
if resp.status() == reqwest::StatusCode::OK {
let echo_json: serde_json::Value = resp.json().await.unwrap();
match echo_json["code"].as_str() {
Some(t) => Some(t.to_string()),
None => None,
}
} else {
None
}
}
_ => None,
}
}
pub async fn auth_code(&mut self, code: String) -> bool {
match self.egs.start_session(Some(code)).await {
Ok(b) => {
return b;
}
Err(_) => {
return false;
}
}
}
pub async fn login(&mut self) -> bool {
match self.egs.user_data.expires_at {
None => {}
Some(exp) => {
let now = chrono::offset::Utc::now();
let td = exp - now;
if td.num_seconds() > 600 {
info!("Trying to re-use existing login session... ");
match self.egs.resume_session().await {
Ok(b) => {
if b {
info!("Logged in");
return true;
}
return false;
}
Err(e) => {
warn!("{}", e)
}
};
}
}
}
info!("Logging in...");
match self.egs.user_data.refresh_expires_at {
None => {}
Some(exp) => {
let now = chrono::offset::Utc::now();
let td = exp - now;
if td.num_seconds() > 600 {
match self.egs.start_session(None).await {
Ok(b) => {
if b {
info!("Logged in");
return true;
}
return false;
}
Err(e) => {
error!("{}", e)
}
}
}
}
}
false
}
pub async fn list_assets(&mut self) -> Vec<EpicAsset> {
match self.egs.get_assets(None, None).await {
Ok(b) => b,
Err(_) => Vec::new(),
}
}
pub async fn get_asset_manifest(
&mut self,
platform: Option<String>,
label: Option<String>,
namespace: Option<String>,
item_id: Option<String>,
app: Option<String>,
) -> Option<AssetManifest> {
match self
.egs
.get_asset_manifest(platform, label, namespace, item_id, app)
.await
{
Ok(a) => Some(a),
Err(_) => None,
}
}
pub async fn get_asset_info(&mut self, asset: EpicAsset) -> Option<AssetInfo> {
match self.egs.get_asset_info(asset.clone()).await {
Ok(mut a) => a.remove(asset.catalog_item_id.as_str()),
Err(_) => None,
}
}
pub async fn get_game_token(&mut self) -> Option<GameToken> {
match self.egs.get_game_token().await {
Ok(a) => Some(a),
Err(_) => None,
}
}
pub async fn get_ownership_token(&mut self, asset: EpicAsset) -> Option<String> {
match self.egs.get_ownership_token(asset).await {
Ok(a) => Some(a.token),
Err(_) => None,
}
}
pub async fn get_user_entitlements(&mut self) -> Vec<Entitlement> {
match self.egs.get_user_entitlements().await {
Ok(a) => a,
Err(_) => Vec::new(),
}
}
pub async fn get_library_items(&mut self, include_metadata: bool) -> Option<Library> {
match self.egs.get_library_items(include_metadata).await {
Ok(a) => Some(a),
Err(_) => None,
}
}
pub async fn get_asset_download_manifest(
&self,
manifest: Manifest,
) -> Result<DownloadManifest, EpicAPIError> {
match self.egs.get_asset_download_manifest(manifest).await {
Ok(manifest) => Ok(manifest),
Err(e) => Err(e),
}
}
}