|
|
@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.http.HttpRequest;
|
|
|
import cn.hutool.http.HttpResponse;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.cyksj.common.exception.BusinessRuntimeException;
|
|
|
@@ -13,7 +14,6 @@ import com.cyksj.common.util.Jsons;
|
|
|
import com.cyksj.mapper.*;
|
|
|
import com.cyksj.model.entity.*;
|
|
|
import com.cyksj.model.response.recharge.RedeemCloudCdkQueryResponse;
|
|
|
-import com.cyksj.model.response.recharge.RedeemCloudExchangeResponse;
|
|
|
import com.cyksj.model.response.recharge.RedeemCloudTaskResultResponse;
|
|
|
import com.cyksj.redis.RedisService;
|
|
|
import com.cyksj.server.recharge.dto.TaskResult;
|
|
|
@@ -24,6 +24,9 @@ import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
import java.util.Date;
|
|
|
|
|
|
@Service
|
|
|
@@ -51,45 +54,29 @@ public class RedeemCloudRechargeServiceImpl implements RedeemCloudRechargeServic
|
|
|
|
|
|
private static final int SUCCESS_CODE = 200;
|
|
|
|
|
|
- private static final int UNUSED_STATUS = 0;
|
|
|
+ private static final int LEGACY_SUCCESS_CODE = 10000;
|
|
|
|
|
|
@Override
|
|
|
public RedeemCloudCdkQueryResponse validateCardKey(String cardKey) throws Exception {
|
|
|
String baseUrl = gptRechargeCardKeyChannelService.getCardKeyDomain(cardKey);
|
|
|
- String url = baseUrl + "/sys-cdk/query?cdkCode=" + cardKey;
|
|
|
+ String url = baseUrl + "/sys-cdk/query?cdkCode=" + encode(cardKey);
|
|
|
|
|
|
HttpResponse response = HttpRequest.get(url)
|
|
|
.setConnectionTimeout(10000)
|
|
|
.execute();
|
|
|
String body = response.body();
|
|
|
- log.info("redeemcloud验证卡密结果: {}", body);
|
|
|
+ log.info("redeemcloud validate card key response: {}", body);
|
|
|
return Jsons.parseObject(body, RedeemCloudCdkQueryResponse.class);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public String confirmRecharge(GroupsRelation relation, String gptCardKey, CmsUser cmsUser) {
|
|
|
Long relationId = relation.getId();
|
|
|
- RedeemCloudCdkQueryResponse validateResponse;
|
|
|
- try {
|
|
|
- validateResponse = validateCardKey(gptCardKey);
|
|
|
- } catch (Exception e) {
|
|
|
- if (cmsUser == null) {
|
|
|
- throw BusinessRuntimeException.getInstance("系统繁忙,请重试");
|
|
|
- }
|
|
|
- throw BusinessRuntimeException.getInstance("卡密:{0}错误", gptCardKey);
|
|
|
- }
|
|
|
- if (!isCardKeyAvailable(validateResponse)) {
|
|
|
- if (cmsUser == null) {
|
|
|
- throw BusinessRuntimeException.getInstance("系统繁忙,请重试");
|
|
|
- }
|
|
|
- throw BusinessRuntimeException.getInstance(getValidateErrorMessage(validateResponse, gptCardKey));
|
|
|
- }
|
|
|
-
|
|
|
- String accessToken = relation.getGptToken();
|
|
|
+ String rechargePayload = relation.getGptToken();
|
|
|
String rechargeAccount = relation.getAccount();
|
|
|
String taskId;
|
|
|
try {
|
|
|
- taskId = submitTask(gptCardKey, accessToken);
|
|
|
+ taskId = submitTask(gptCardKey, rechargePayload);
|
|
|
} catch (Exception e) {
|
|
|
setRechargeRelationStatusAutoError(relation);
|
|
|
if (cmsUser == null) {
|
|
|
@@ -106,7 +93,7 @@ public class RedeemCloudRechargeServiceImpl implements RedeemCloudRechargeServic
|
|
|
.set(StrUtil.isNotBlank(password), GroupsRelation::getPassword, password)
|
|
|
.set(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharging)
|
|
|
.set(GroupsRelation::getCardKey, gptCardKey)
|
|
|
- .set(GroupsRelation::getGptToken, accessToken)
|
|
|
+ .set(GroupsRelation::getGptToken, rechargePayload)
|
|
|
.set(GroupsRelation::getGptTaskId, taskId)
|
|
|
.eq(GroupsRelation::getId, relationId));
|
|
|
relation.setRechargeStatus(GroupsRelation.RechargeStatus.recharging);
|
|
|
@@ -115,70 +102,98 @@ public class RedeemCloudRechargeServiceImpl implements RedeemCloudRechargeServic
|
|
|
return taskId;
|
|
|
}
|
|
|
|
|
|
- private boolean isCardKeyAvailable(RedeemCloudCdkQueryResponse validateResponse) {
|
|
|
- return validateResponse != null
|
|
|
- && validateResponse.getCode() != null
|
|
|
- && validateResponse.getCode() == SUCCESS_CODE
|
|
|
- && validateResponse.getData() != null
|
|
|
- && validateResponse.getData().getUseStatus() != null
|
|
|
- && validateResponse.getData().getUseStatus() == UNUSED_STATUS
|
|
|
- && Boolean.TRUE.equals(validateResponse.getData().getChannelEnabled());
|
|
|
- }
|
|
|
-
|
|
|
- private String getValidateErrorMessage(RedeemCloudCdkQueryResponse validateResponse, String cardKey) {
|
|
|
- if (validateResponse == null) {
|
|
|
- return "卡密错误:" + cardKey;
|
|
|
- }
|
|
|
- if (StrUtil.isNotBlank(validateResponse.getMessage())) {
|
|
|
- return validateResponse.getMessage();
|
|
|
- }
|
|
|
- return "卡密错误:" + cardKey;
|
|
|
- }
|
|
|
-
|
|
|
private String submitTask(String cardKey, String rechargePayload) {
|
|
|
- log.info("开始提交redeemcloud任务 - 卡密: {}", cardKey);
|
|
|
+ log.info("start submit redeemcloud task - cardKey: {}", cardKey);
|
|
|
try {
|
|
|
String baseUrl = gptRechargeCardKeyChannelService.getCardKeyDomain(cardKey);
|
|
|
- String url = baseUrl + "/sys-cdk/exchange?cdkCode=" + cardKey;
|
|
|
- String requestBody = normalizeRechargePayload(rechargePayload);
|
|
|
+ String requestBody = buildExchangeBody(baseUrl, cardKey, rechargePayload);
|
|
|
+ String url = baseUrl + "/sys-cdk/exchange?cdkCode=" + encode(cardKey);
|
|
|
|
|
|
- HttpResponse response = HttpRequest.post(url)
|
|
|
+ HttpResponse response = addBrowserHeaders(HttpRequest.post(url)
|
|
|
.setConnectionTimeout(60000)
|
|
|
- .header("accept", "*/*")
|
|
|
- .header("accept-language", "zh-CN")
|
|
|
- .header("content-type", "application/json")
|
|
|
- .header("origin", "https://redeemcloud.com")
|
|
|
- .header("referer", "https://redeemcloud.com/zh")
|
|
|
- .header("sec-ch-ua", "\"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"150\", \"Microsoft Edge\";v=\"150\"")
|
|
|
- .header("sec-ch-ua-mobile", "?0")
|
|
|
- .header("sec-ch-ua-platform", "\"Windows\"")
|
|
|
- .header("sec-fetch-dest", "empty")
|
|
|
- .header("sec-fetch-mode", "cors")
|
|
|
- .header("sec-fetch-site", "same-origin")
|
|
|
- .header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0")
|
|
|
- .header("x-product-code", "GPT")
|
|
|
+ .header("content-type", "application/json"))
|
|
|
.body(requestBody)
|
|
|
.execute();
|
|
|
String body = response.body();
|
|
|
- log.info("redeemcloud任务提交响应: {}", body);
|
|
|
+ log.info("redeemcloud submit response: {}", body);
|
|
|
|
|
|
- RedeemCloudExchangeResponse exchangeResponse = Jsons.parseObject(body, RedeemCloudExchangeResponse.class);
|
|
|
- if (exchangeResponse != null && exchangeResponse.getCode() != null && exchangeResponse.getCode() == SUCCESS_CODE && StrUtil.isNotBlank(exchangeResponse.getData())) {
|
|
|
- return exchangeResponse.getData();
|
|
|
+ JSONObject jsonResponse = JSONUtil.parseObj(body);
|
|
|
+ Object data = jsonResponse.get("data");
|
|
|
+ if (isSuccessResponse(jsonResponse) && data instanceof CharSequence && StrUtil.isNotBlank(data.toString())) {
|
|
|
+ return data.toString();
|
|
|
+ }
|
|
|
+ if (data instanceof JSONObject) {
|
|
|
+ JSONObject dataObj = (JSONObject) data;
|
|
|
+ String status = dataObj.getStr("status");
|
|
|
+ if ("FAILED".equalsIgnoreCase(status)) {
|
|
|
+ throw BusinessRuntimeException.getInstance(getErrorMessage(dataObj, jsonResponse));
|
|
|
+ }
|
|
|
}
|
|
|
- String errorMessage = exchangeResponse != null && StrUtil.isNotBlank(exchangeResponse.getMessage()) ? exchangeResponse.getMessage() : "提交任务失败";
|
|
|
- throw BusinessRuntimeException.getInstance(errorMessage);
|
|
|
+ throw BusinessRuntimeException.getInstance(getErrorMessage(null, jsonResponse));
|
|
|
} catch (Exception e) {
|
|
|
- log.error("提交redeemcloud任务失败: {}", e.getMessage(), e);
|
|
|
+ log.error("submit redeemcloud task failed: {}", e.getMessage(), e);
|
|
|
throw new RuntimeException("提交任务失败: " + e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private String normalizeRechargePayload(String rechargePayload) {
|
|
|
+ private String buildExchangeBody(String baseUrl, String cardKey, String rechargePayload) throws Exception {
|
|
|
if (StrUtil.isBlank(rechargePayload) || !StrUtil.startWith(rechargePayload.trim(), "{")) {
|
|
|
- throw BusinessRuntimeException.getInstance("redeemcloud提交任务需要完整充值参数JSON");
|
|
|
+ throw BusinessRuntimeException.getInstance("redeemcloud提交任务需要完整session JSON");
|
|
|
+ }
|
|
|
+ JSONObject payload = JSONUtil.parseObj(rechargePayload);
|
|
|
+ if (isExchangeBody(payload)) {
|
|
|
+ return payload.toString();
|
|
|
+ }
|
|
|
+ return verifyAccount(baseUrl, cardKey, rechargePayload).toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isExchangeBody(JSONObject payload) {
|
|
|
+ return payload.containsKey("cdkPackageName") && payload.containsKey("payload") && payload.containsKey("idp");
|
|
|
+ }
|
|
|
+
|
|
|
+ private JSONObject verifyAccount(String baseUrl, String cardKey, String content) {
|
|
|
+ String url = baseUrl + "/account/verify?cdkCode=" + encode(cardKey) + "&content=" + encode(content);
|
|
|
+ HttpResponse response = addBrowserHeaders(HttpRequest.post(url)
|
|
|
+ .setConnectionTimeout(60000))
|
|
|
+ .execute();
|
|
|
+ String body = response.body();
|
|
|
+ log.info("redeemcloud account verify response: {}", body);
|
|
|
+
|
|
|
+ JSONObject jsonResponse = JSONUtil.parseObj(body);
|
|
|
+ Object data = jsonResponse.get("data");
|
|
|
+ if (isSuccessResponse(jsonResponse) && data instanceof JSONObject) {
|
|
|
+ return (JSONObject) data;
|
|
|
+ }
|
|
|
+ throw BusinessRuntimeException.getInstance(getErrorMessage(data instanceof JSONObject ? (JSONObject) data : null, jsonResponse));
|
|
|
+ }
|
|
|
+
|
|
|
+ private HttpRequest addBrowserHeaders(HttpRequest request) {
|
|
|
+ return request
|
|
|
+ .header("accept", "*/*")
|
|
|
+ .header("accept-language", "zh-CN")
|
|
|
+ .header("origin", "https://redeemcloud.com")
|
|
|
+ .header("referer", "https://redeemcloud.com/zh")
|
|
|
+ .header("sec-ch-ua", "\"Not;A=Brand\";v=\"8\", \"Chromium\";v=\"150\", \"Microsoft Edge\";v=\"150\"")
|
|
|
+ .header("sec-ch-ua-mobile", "?0")
|
|
|
+ .header("sec-ch-ua-platform", "\"Windows\"")
|
|
|
+ .header("sec-fetch-dest", "empty")
|
|
|
+ .header("sec-fetch-mode", "cors")
|
|
|
+ .header("sec-fetch-site", "same-origin")
|
|
|
+ .header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0")
|
|
|
+ .header("x-product-code", "GPT");
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isSuccessResponse(JSONObject jsonResponse) {
|
|
|
+ Integer code = jsonResponse.getInt("code");
|
|
|
+ return code != null && (code == SUCCESS_CODE || code == LEGACY_SUCCESS_CODE) && !Boolean.FALSE.equals(jsonResponse.getBool("flag"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String encode(String value) {
|
|
|
+ try {
|
|
|
+ return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
|
|
|
+ } catch (UnsupportedEncodingException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
}
|
|
|
- return JSONUtil.parseObj(rechargePayload).toString();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -191,20 +206,20 @@ public class RedeemCloudRechargeServiceImpl implements RedeemCloudRechargeServic
|
|
|
resetGroupsRelationRechargeStatus(relation, taskResult.getStatus(), taskResult.getError());
|
|
|
return taskResult;
|
|
|
} catch (Exception e) {
|
|
|
- log.error("查询redeemcloud任务结果失败: {}", e.getMessage(), e);
|
|
|
+ log.error("query redeemcloud task result failed: {}", e.getMessage(), e);
|
|
|
throw new RuntimeException("获取任务结果失败: " + e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private RedeemCloudTaskResultResponse queryTaskResult(String cardKey, String taskId) throws Exception {
|
|
|
String baseUrl = gptRechargeCardKeyChannelService.getCardKeyDomain(cardKey);
|
|
|
- String url = baseUrl + "/sys-cdk/exchange/result?taskId=" + taskId;
|
|
|
+ String url = baseUrl + "/sys-cdk/exchange/result?taskId=" + encode(taskId);
|
|
|
|
|
|
HttpResponse response = HttpRequest.get(url)
|
|
|
.setConnectionTimeout(10000)
|
|
|
.execute();
|
|
|
String body = response.body();
|
|
|
- log.info("redeemcloud任务查询响应: {}", body);
|
|
|
+ log.info("redeemcloud task result response: {}", body);
|
|
|
return Jsons.parseObject(body, RedeemCloudTaskResultResponse.class);
|
|
|
}
|
|
|
|
|
|
@@ -225,10 +240,6 @@ public class RedeemCloudRechargeServiceImpl implements RedeemCloudRechargeServic
|
|
|
result.setStatus("completed");
|
|
|
} else if ("FAILED".equalsIgnoreCase(status) || "ERROR".equalsIgnoreCase(status)) {
|
|
|
result.setStatus("failed");
|
|
|
- } else if (taskResultResponse.getData().getUseStatus() != null && taskResultResponse.getData().getUseStatus() != UNUSED_STATUS) {
|
|
|
- result.setStatus("completed");
|
|
|
- } else if (StrUtil.isNotBlank(taskResultResponse.getData().getEmail()) || StrUtil.isNotBlank(taskResultResponse.getData().getAccountId())) {
|
|
|
- result.setStatus("completed");
|
|
|
} else {
|
|
|
result.setStatus("recharging");
|
|
|
}
|
|
|
@@ -237,6 +248,28 @@ public class RedeemCloudRechargeServiceImpl implements RedeemCloudRechargeServic
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ private String getErrorMessage(JSONObject data, JSONObject response) {
|
|
|
+ if (data != null) {
|
|
|
+ String error = data.getStr("error");
|
|
|
+ if (StrUtil.isNotBlank(error)) {
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ String errorMessage = data.getStr("errorMessage");
|
|
|
+ if (StrUtil.isNotBlank(errorMessage)) {
|
|
|
+ return errorMessage;
|
|
|
+ }
|
|
|
+ String result = data.getStr("result");
|
|
|
+ if (StrUtil.isNotBlank(result)) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String message = response.getStr("message");
|
|
|
+ if (StrUtil.isBlank(message)) {
|
|
|
+ message = response.getStr("msg");
|
|
|
+ }
|
|
|
+ return StrUtil.isNotBlank(message) ? message : "提交任务失败";
|
|
|
+ }
|
|
|
+
|
|
|
public void setRechargeRelationStatusAutoError(GroupsRelation relation) {
|
|
|
TASK_EXECUTOR.execute(() -> relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
|
|
|
.set(GroupsRelation::getAccount, relation.getAccount())
|