package com.cyksj.service.recharge.impl; import cn.hutool.core.date.DateTime; 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.JSONUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.task.GlobalThreadPoolTaskExecutor; 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; import com.cyksj.service.chatgpt.GptUserRechargeRecordService; import com.cyksj.service.recharge.GptRechargeCardKeyChannelService; import com.cyksj.service.recharge.RedeemCloudRechargeService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.Date; @Service @RequiredArgsConstructor @Slf4j public class RedeemCloudRechargeServiceImpl implements RedeemCloudRechargeService { private final GptRechargeCardKeyChannelService gptRechargeCardKeyChannelService; private final GroupsRelationMapper relationMapper; private final GroupsMapper groupsMapper; private final GoodsDonSkuMapper skuMapper; private final RedisService redisService; private final OrderDonMapper orderDonMapper; private final GptRechargeCardKeyMapper gptRechargeCardKeyMapper; private final GptUserRechargeRecordService gptUserRechargeRecordService; private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance(); private static final int SUCCESS_CODE = 200; private static final int UNUSED_STATUS = 0; @Override public RedeemCloudCdkQueryResponse validateCardKey(String cardKey) throws Exception { String baseUrl = gptRechargeCardKeyChannelService.getCardKeyDomain(cardKey); String url = baseUrl + "/sys-cdk/query?cdkCode=" + cardKey; HttpResponse response = HttpRequest.get(url) .setConnectionTimeout(10000) .execute(); String body = response.body(); log.info("redeemcloud验证卡密结果: {}", 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 rechargeAccount = relation.getAccount(); String taskId; try { taskId = submitTask(gptCardKey, accessToken); } catch (Exception e) { setRechargeRelationStatusAutoError(relation); if (cmsUser == null) { throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通"); } throw BusinessRuntimeException.getInstance("充值失败,{0}", e.getMessage()); } String operator = cmsUser != null ? cmsUser.getNickname() : null; String password = relation.getPassword(); relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(GroupsRelation::getAccount, rechargeAccount) .set(GroupsRelation::getOperator, operator) .set(StrUtil.isNotBlank(password), GroupsRelation::getPassword, password) .set(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharging) .set(GroupsRelation::getCardKey, gptCardKey) .set(GroupsRelation::getGptToken, accessToken) .set(GroupsRelation::getGptTaskId, taskId) .eq(GroupsRelation::getId, relationId)); relation.setRechargeStatus(GroupsRelation.RechargeStatus.recharging); relation.setCardKey(gptCardKey); relation.setOperator(operator); 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); try { String baseUrl = gptRechargeCardKeyChannelService.getCardKeyDomain(cardKey); String url = baseUrl + "/sys-cdk/exchange?cdkCode=" + cardKey; String requestBody = normalizeRechargePayload(rechargePayload); HttpResponse response = 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") .body(requestBody) .execute(); String body = response.body(); log.info("redeemcloud任务提交响应: {}", 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(); } String errorMessage = exchangeResponse != null && StrUtil.isNotBlank(exchangeResponse.getMessage()) ? exchangeResponse.getMessage() : "提交任务失败"; throw BusinessRuntimeException.getInstance(errorMessage); } catch (Exception e) { log.error("提交redeemcloud任务失败: {}", e.getMessage(), e); throw new RuntimeException("提交任务失败: " + e.getMessage(), e); } } private String normalizeRechargePayload(String rechargePayload) { if (StrUtil.isBlank(rechargePayload) || !StrUtil.startWith(rechargePayload.trim(), "{")) { throw BusinessRuntimeException.getInstance("redeemcloud提交任务需要完整充值参数JSON"); } return JSONUtil.parseObj(rechargePayload).toString(); } @Override public TaskResult getTaskResult(GroupsRelation relation) { String cardKey = relation.getCardKey(); String taskId = relation.getGptTaskId(); try { RedeemCloudTaskResultResponse taskResultResponse = queryTaskResult(cardKey, taskId); TaskResult taskResult = convertTaskResult(taskResultResponse); resetGroupsRelationRechargeStatus(relation, taskResult.getStatus(), taskResult.getError()); return taskResult; } catch (Exception e) { log.error("查询redeemcloud任务结果失败: {}", 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; HttpResponse response = HttpRequest.get(url) .setConnectionTimeout(10000) .execute(); String body = response.body(); log.info("redeemcloud任务查询响应: {}", body); return Jsons.parseObject(body, RedeemCloudTaskResultResponse.class); } private TaskResult convertTaskResult(RedeemCloudTaskResultResponse taskResultResponse) { TaskResult result = new TaskResult(); if (taskResultResponse == null || taskResultResponse.getCode() == null || taskResultResponse.getCode() != SUCCESS_CODE) { result.setStatus("failed"); result.setError(taskResultResponse != null ? taskResultResponse.getMessage() : "任务查询失败"); return result; } if (taskResultResponse.getData() == null) { result.setStatus("recharging"); result.setResult(taskResultResponse.getMessage()); return result; } String status = taskResultResponse.getData().getStatus(); if ("COMPLETED".equalsIgnoreCase(status)) { 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"); } result.setResult(status); result.setError(taskResultResponse.getData().getErrorMessage()); return result; } public void setRechargeRelationStatusAutoError(GroupsRelation relation) { TASK_EXECUTOR.execute(() -> relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(GroupsRelation::getAccount, relation.getAccount()) .set(GroupsRelation::getGptToken, relation.getGptToken()) .set(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharge_error) .eq(GroupsRelation::getId, relation.getId()))); } private void resetGroupsRelationRechargeStatus(GroupsRelation relation, String status, String result) { if (!"completed".equals(status) && !"failed".equals(status) && !"unknown".equals(status)) { return; } relation = relationMapper.selectById(relation.getId()); if (relation == null || relation.getRechargeStatus() != GroupsRelation.RechargeStatus.recharging) { return; } String taskId = relation.getGptTaskId(); Integer rechargeRemainNum = relation.getRechargeRemainNum(); GroupsRelation.RechargeStatus rechargeStatus = "completed".equals(status) ? GroupsRelation.RechargeStatus.complete : GroupsRelation.RechargeStatus.recharge_error; String cardKey = relation.getCardKey(); GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class) .eq(GptRechargeCardKey::getCardKey, cardKey) .last("limit 1")); if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error && gptRechargeCardKey != null) { gptRechargeCardKeyMapper.update(null, Wrappers.lambdaUpdate(GptRechargeCardKey.class) .set(GptRechargeCardKey::getStatus, Boolean.FALSE) .set(GptRechargeCardKey::getOrderId, null) .set(GptRechargeCardKey::getOrderNo, null) .eq(GptRechargeCardKey::getId, gptRechargeCardKey.getId()) .eq(GptRechargeCardKey::getStatus, Boolean.TRUE)); } if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error && !redisService.setNx(RedisService.key.GPT_RECHARGE_RECOVER_KEY.getName() + taskId, taskId, RedisService.key.GPT_RECHARGE_RECOVER_KEY.getTimeout())) { return; } Date startTime = relation.getStartTime(); DateTime expiryTime = null; if (rechargeStatus == GroupsRelation.RechargeStatus.complete && startTime == null) { GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId()); if (groupsTrips != null) { startTime = DateTime.now(); GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId()); if (sku.getDays() != null && sku.getDays() > 0) { expiryTime = DateUtil.offsetDay(startTime, sku.getDays()); } else { expiryTime = DateUtil.offsetMonth(startTime, sku.getMonths()); } } } String rechargeErrorInfo = rechargeStatus == GroupsRelation.RechargeStatus.recharge_error ? result : null; int update = relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(rechargeStatus == GroupsRelation.RechargeStatus.recharge_error, GroupsRelation::getRechargeRemainNum, rechargeRemainNum + 1) .set(GroupsRelation::getRechargeStatus, rechargeStatus) .set(expiryTime != null, GroupsRelation::getStartTime, startTime) .set(expiryTime != null, GroupsRelation::getExpiryTime, expiryTime) .set(StrUtil.isNotEmpty(rechargeErrorInfo), GroupsRelation::getRechargeErrorInfo, rechargeErrorInfo) .eq(GroupsRelation::getId, relation.getId()) .le(GroupsRelation::getRechargeRemainNum, relation.getRechargeNum()) .eq(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharging)); if (update == 0) { return; } if (rechargeStatus == GroupsRelation.RechargeStatus.complete) { String remark = StrUtil.isNotBlank(relation.getOperator()) ? "后台自动代充" : "自动代充"; gptUserRechargeRecordService.recordGptUserRechargeNum(relation.getCardKey(), relation.getUserId(), relation.getId(), relation.getAccount(), -1, relation.getOperator(), remark); if (gptRechargeCardKey != null) { Long orderId = gptRechargeCardKey.getOrderId(); OrderDon orderDon = orderDonMapper.selectById(orderId); if (orderDon != null && orderDon.getStatus() == OrderDon.Status.hasPayment) { orderDon.setStatus(OrderDon.Status.complete); orderDonMapper.updateById(orderDon); } } } } }