1use crate::api::EpicAPI;
2use crate::api::error::EpicAPIError;
3use crate::api::types::uplay::{
4 UplayClaimResult, UplayCodesResult, UplayGraphQLResponse, UplayRedeemResult,
5};
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 = url::Url::parse(STORE_GQL_URL).map_err(|_| EpicAPIError::InvalidParams)?;
136 let response = self
137 .set_authorization_header(self.client.post(parsed_url))
138 .header("User-Agent", STORE_USER_AGENT)
139 .json(body)
140 .send()
141 .await
142 .map_err(|e| {
143 error!("{:?}", e);
144 EpicAPIError::NetworkError(e)
145 })?;
146 if response.status() == reqwest::StatusCode::OK {
147 response.json::<T>().await.map_err(|e| {
148 error!("{:?}", e);
149 EpicAPIError::DeserializationError(format!("{}", e))
150 })
151 } else {
152 let status = response.status();
153 let body = response.text().await.unwrap_or_default();
154 log::warn!("{} result: {}", status, body);
155 Err(EpicAPIError::HttpError { status, body })
156 }
157 }
158}