1use crate::api::error::EpicAPIError;
2use crate::api::types::uplay::{
3 UplayClaimResult, UplayCodesResult, UplayGraphQLResponse, UplayRedeemResult,
4};
5use crate::api::EpicAPI;
6use log::error;
7
8const UPLAY_CODES_QUERY: &str = r#"
9query partnerIntegrationQuery($accountId: String!) {
10 PartnerIntegration {
11 accountUplayCodes(accountId: $accountId) {
12 epicAccountId
13 gameId
14 uplayAccountId
15 regionCode
16 redeemedOnUplay
17 redemptionTimestamp
18 }
19 }
20}
21"#;
22
23const UPLAY_CLAIM_QUERY: &str = r#"
24mutation claimUplayCode($accountId: String!, $uplayAccountId: String!, $gameId: String!) {
25 PartnerIntegration {
26 claimUplayCode(
27 accountId: $accountId
28 uplayAccountId: $uplayAccountId
29 gameId: $gameId
30 ) {
31 data {
32 assignmentTimestam
33 epicAccountId
34 epicEntitlement {
35 entitlementId
36 catalogItemId
37 entitlementName
38 country
39 }
40 gameId
41 redeemedOnUplay
42 redemptionTimestamp
43 regionCode
44 uplayAccountId
45 }
46 success
47 }
48 }
49}
50"#;
51
52const UPLAY_REDEEM_QUERY: &str = r#"
53mutation redeemAllPendingCodes($accountId: String!, $uplayAccountId: String!) {
54 PartnerIntegration {
55 redeemAllPendingCodes(accountId: $accountId, uplayAccountId: $uplayAccountId) {
56 data {
57 epicAccountId
58 uplayAccountId
59 redeemedOnUplay
60 redemptionTimestamp
61 }
62 success
63 }
64 }
65}
66"#;
67
68const STORE_GQL_URL: &str = "https://launcher.store.epicgames.com/graphql";
69const STORE_USER_AGENT: &str = "EpicGamesLauncher/14.0.8-22004686+++Portal+Release-Live";
70
71impl EpicAPI {
72 pub async fn store_get_uplay_codes(
74 &self,
75 ) -> Result<UplayGraphQLResponse<UplayCodesResult>, EpicAPIError> {
76 let user_id = self
77 .user_data
78 .account_id
79 .as_deref()
80 .ok_or(EpicAPIError::InvalidCredentials)?;
81 let body = serde_json::json!({
82 "query": UPLAY_CODES_QUERY,
83 "variables": { "accountId": user_id },
84 });
85 self.store_gql_request(&body).await
86 }
87
88 pub async fn store_claim_uplay_code(
90 &self,
91 uplay_account_id: &str,
92 game_id: &str,
93 ) -> Result<UplayGraphQLResponse<UplayClaimResult>, EpicAPIError> {
94 let user_id = self
95 .user_data
96 .account_id
97 .as_deref()
98 .ok_or(EpicAPIError::InvalidCredentials)?;
99 let body = serde_json::json!({
100 "query": UPLAY_CLAIM_QUERY,
101 "variables": {
102 "accountId": user_id,
103 "uplayAccountId": uplay_account_id,
104 "gameId": game_id,
105 },
106 });
107 self.store_gql_request(&body).await
108 }
109
110 pub async fn store_redeem_uplay_codes(
112 &self,
113 uplay_account_id: &str,
114 ) -> Result<UplayGraphQLResponse<UplayRedeemResult>, EpicAPIError> {
115 let user_id = self
116 .user_data
117 .account_id
118 .as_deref()
119 .ok_or(EpicAPIError::InvalidCredentials)?;
120 let body = serde_json::json!({
121 "query": UPLAY_REDEEM_QUERY,
122 "variables": {
123 "accountId": user_id,
124 "uplayAccountId": uplay_account_id,
125 },
126 });
127 self.store_gql_request(&body).await
128 }
129
130 async fn store_gql_request<T: serde::de::DeserializeOwned>(
132 &self,
133 body: &serde_json::Value,
134 ) -> Result<T, EpicAPIError> {
135 let parsed_url =
136 url::Url::parse(STORE_GQL_URL).map_err(|_| EpicAPIError::InvalidParams)?;
137 let response = self
138 .set_authorization_header(self.client.post(parsed_url))
139 .header("User-Agent", STORE_USER_AGENT)
140 .json(body)
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 log::warn!("{} result: {}", status, body);
156 Err(EpicAPIError::HttpError { status, body })
157 }
158 }
159}