egs_api/
lib.rs

1#![deny(missing_docs)]
2#![cfg_attr(test, deny(warnings))]
3
4//! # Epic Games Store API
5//!
6//! A minimal asynchronous interface to Epic Games Store
7//!
8//! # This is under heavy development expect major breaking changes
9//!
10//! ## Current functionality
11//!  - Authentication
12//!  - Listing Assets
13//!  - Get Asset metadata
14//!  - Get Asset info
15//!  - Get Ownership Token
16//!  - Get Game Token
17//!  - Get Entitlements
18//!  - Get Library Items
19//!  - Generate download links for chunks
20
21use crate::api::types::account::{AccountData, AccountInfo, UserData};
22use crate::api::types::epic_asset::EpicAsset;
23use crate::api::types::fab_asset_manifest::DownloadInfo;
24use crate::api::types::friends::Friend;
25use crate::api::{EpicAPI};
26
27use api::types::asset_info::{AssetInfo, GameToken};
28use api::types::asset_manifest::AssetManifest;
29use api::types::download_manifest::DownloadManifest;
30use api::types::entitlement::Entitlement;
31use api::types::library::Library;
32use log::{error, info, warn};
33use crate::api::error::EpicAPIError;
34
35/// Module for authenticated API communication
36pub mod api;
37
38/// Struct to manage the communication with the Epic Games Store Api
39#[derive(Default, Debug, Clone)]
40pub struct EpicGames {
41    egs: EpicAPI,
42}
43
44impl EpicGames {
45    /// Creates new object
46    pub fn new() -> Self {
47        EpicGames {
48            egs: EpicAPI::new(),
49        }
50    }
51
52    /// Check whether the user is logged in
53    pub fn is_logged_in(&self) -> bool {
54        if let Some(exp) = self.egs.user_data.expires_at {
55            let now = chrono::offset::Utc::now();
56            let td = exp - now;
57            if td.num_seconds() > 600 {
58                return true;
59            }
60        }
61        false
62    }
63
64    /// Get User details
65    pub fn user_details(&self) -> UserData {
66        self.egs.user_data.clone()
67    }
68
69    /// Update User Details
70    pub fn set_user_details(&mut self, user_details: UserData) {
71        self.egs.user_data.update(user_details);
72    }
73
74    /// Start session with auth code
75    pub async fn auth_code(
76        &mut self,
77        exchange_token: Option<String>,
78        authorization_code: Option<String>,
79    ) -> bool {
80        self.egs
81            .start_session(exchange_token, authorization_code)
82            .await
83            .unwrap_or(false)
84    }
85
86    /// Invalidate existing session
87    pub async fn logout(&mut self) -> bool {
88        self.egs.invalidate_sesion().await
89    }
90
91    /// Perform login based on previous authentication
92    pub async fn login(&mut self) -> bool {
93        if let Some(exp) = self.egs.user_data.expires_at {
94            let now = chrono::offset::Utc::now();
95            let td = exp - now;
96            if td.num_seconds() > 600 {
97                info!("Trying to re-use existing login session... ");
98                match self.egs.resume_session().await {
99                    Ok(b) => {
100                        if b {
101                            info!("Logged in");
102                            return true;
103                        }
104                        return false;
105                    }
106                    Err(e) => {
107                        warn!("{}", e)
108                    }
109                };
110            }
111        }
112        info!("Logging in...");
113        if let Some(exp) = self.egs.user_data.refresh_expires_at {
114            let now = chrono::offset::Utc::now();
115            let td = exp - now;
116            if td.num_seconds() > 600 {
117                match self.egs.start_session(None, None).await {
118                    Ok(b) => {
119                        if b {
120                            info!("Logged in");
121                            return true;
122                        }
123                        return false;
124                    }
125                    Err(e) => {
126                        error!("{}", e)
127                    }
128                }
129            }
130        }
131        false
132    }
133
134    /// Returns all assets
135    pub async fn list_assets(
136        &mut self,
137        platform: Option<String>,
138        label: Option<String>,
139    ) -> Vec<EpicAsset> {
140        self.egs
141            .assets(platform, label)
142            .await
143            .unwrap_or_else(|_| Vec::new())
144    }
145
146    /// Return asset
147    pub async fn asset_manifest(
148        &mut self,
149        platform: Option<String>,
150        label: Option<String>,
151        namespace: Option<String>,
152        item_id: Option<String>,
153        app: Option<String>,
154    ) -> Option<AssetManifest> {
155        match self
156            .egs
157            .asset_manifest(platform, label, namespace, item_id, app)
158            .await
159        {
160            Ok(a) => Some(a),
161            Err(_) => None,
162        }
163    }
164
165    /// Return Fab Asset Manifest
166    pub async fn fab_asset_manifest(
167        &self,
168        artifact_id: &str,
169        namespace: &str,
170        asset_id: &str,
171        platform: Option<&str>,
172    ) -> Result<Vec<DownloadInfo>, EpicAPIError> {
173        match self
174            .egs
175            .fab_asset_manifest(artifact_id, namespace, asset_id, platform)
176            .await
177        {
178            Ok(a) => Ok(a),
179            Err(e) => Err(e),
180        }
181    }
182
183    /// Returns info for an asset
184    pub async fn asset_info(&mut self, asset: EpicAsset) -> Option<AssetInfo> {
185        match self.egs.asset_info(asset.clone()).await {
186            Ok(mut a) => a.remove(asset.catalog_item_id.as_str()),
187            Err(_) => None,
188        }
189    }
190
191    /// Returns account details
192    pub async fn account_details(&mut self) -> Option<AccountData> {
193        match self.egs.account_details().await {
194            Ok(a) => Some(a),
195            Err(_) => None,
196        }
197    }
198
199    /// Returns account id info
200    pub async fn account_ids_details(&mut self, ids: Vec<String>) -> Option<Vec<AccountInfo>> {
201        match self.egs.account_ids_details(ids).await {
202            Ok(a) => Some(a),
203            Err(_) => None,
204        }
205    }
206
207    /// Returns account id info
208    pub async fn account_friends(&mut self, include_pending: bool) -> Option<Vec<Friend>> {
209        match self.egs.account_friends(include_pending).await {
210            Ok(a) => Some(a),
211            Err(_) => None,
212        }
213    }
214
215    /// Returns game token
216    pub async fn game_token(&mut self) -> Option<GameToken> {
217        match self.egs.game_token().await {
218            Ok(a) => Some(a),
219            Err(_) => None,
220        }
221    }
222
223    /// Returns ownership token for an Asset
224    pub async fn ownership_token(&mut self, asset: EpicAsset) -> Option<String> {
225        match self.egs.ownership_token(asset).await {
226            Ok(a) => Some(a.token),
227            Err(_) => None,
228        }
229    }
230
231    ///Returns user entitlements
232    pub async fn user_entitlements(&mut self) -> Vec<Entitlement> {
233        self.egs.user_entitlements().await.unwrap_or_else(|_| Vec::new())
234    }
235
236    /// Returns the user library
237    pub async fn library_items(&mut self, include_metadata: bool) -> Option<Library> {
238        match self.egs.library_items(include_metadata).await {
239            Ok(a) => Some(a),
240            Err(_) => None,
241        }
242    }
243
244    /// Returns the user FAB library
245    pub async fn fab_library_items(
246        &mut self,
247        account_id: String,
248    ) -> Option<api::types::fab_library::FabLibrary> {
249        match self.egs.fab_library_items(account_id).await {
250            Ok(a) => Some(a),
251            Err(_) => None,
252        }
253    }
254
255    /// Returns a DownloadManifest for a specified file manifest
256    pub async fn asset_download_manifests(&self, manifest: AssetManifest) -> Vec<DownloadManifest> {
257        self.egs.asset_download_manifests(manifest).await
258    }
259
260    /// Return a Download Manifest for specified FAB download and url
261    pub async fn fab_download_manifest(
262        &self,
263        download_info: DownloadInfo,
264        distribution_point_url: &str,
265    ) -> Result<DownloadManifest, EpicAPIError> {
266        self.egs
267            .fab_download_manifest(download_info, distribution_point_url)
268            .await
269    }
270}