GptProxyRechargeServiceImpl.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. package com.cyksj.server.recharge.impl;
  2. import cn.hutool.http.HttpRequest;
  3. import cn.hutool.http.HttpResponse;
  4. import cn.hutool.json.JSONObject;
  5. import cn.hutool.json.JSONUtil;
  6. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  7. import com.cyksj.common.constant.Constant;
  8. import com.cyksj.common.exception.BusinessRuntimeException;
  9. import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
  10. import com.cyksj.mapper.*;
  11. import com.cyksj.model.entity.*;
  12. import com.cyksj.model.request.GroupsRelationRechargeReq;
  13. import com.cyksj.server.recharge.GptProxyRechargeService;
  14. import com.cyksj.server.recharge.dto.CardKeyValidationResult;
  15. import com.cyksj.server.recharge.dto.TaskResult;
  16. import com.cyksj.server.recharge.dto.TaskSubmitResult;
  17. import com.cyksj.server.recharge.dto.TokenParseResult;
  18. import com.cyksj.service.user.UserBindRelationService;
  19. import lombok.RequiredArgsConstructor;
  20. import lombok.extern.slf4j.Slf4j;
  21. import org.springframework.stereotype.Service;
  22. import org.springframework.transaction.annotation.Transactional;
  23. import java.util.List;
  24. /**
  25. * @author chan
  26. * @date 2025/7/30 18:55
  27. */
  28. @Slf4j
  29. @Service
  30. @RequiredArgsConstructor
  31. public class GptProxyRechargeServiceImpl implements GptProxyRechargeService {
  32. private static final String BASE_URL = "https://api.ow520.com/api";
  33. private final GptRechargeCardKeyMapper gptRechargeCardKeyMapper;
  34. private final GroupsRelationMapper relationMapper;
  35. private final UserBindRelationService userBindRelationService;
  36. private GroupsMapper groupsMapper;
  37. private final GoodsDonSkuMapper skuMapper;
  38. private final OrderDonMapper orderDonMapper;
  39. private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
  40. private HttpRequest createBaseRequest(String uri) {
  41. return HttpRequest.get(BASE_URL + uri)
  42. .header("accept", "application/json, text/plain, */*")
  43. .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8")
  44. .header("origin", "https://www.ow520.com")
  45. .header("referer", "https://www.ow520.com/")
  46. .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36");
  47. }
  48. public CardKeyValidationResult validateCardKey(String cardKey) {
  49. log.info("开始验证卡密: {}", cardKey);
  50. try {
  51. HttpResponse response = createBaseRequest("/card-keys/" + cardKey)
  52. .execute();
  53. String body = response.body();
  54. log.info("卡密验证响应: {}", body);
  55. JSONObject jsonResponse = JSONUtil.parseObj(body);
  56. CardKeyValidationResult result = new CardKeyValidationResult(
  57. jsonResponse.getBool("available")
  58. );
  59. //{"available":false,"error":"卡密已被使用"}
  60. log.info("卡密验证结果: {}", result);
  61. return result;
  62. } catch (Exception e) {
  63. log.error("验证卡密失败: {}", e.getMessage(), e);
  64. throw new RuntimeException("验证卡密失败: " + e.getMessage(), e);
  65. }
  66. }
  67. public TokenParseResult parseToken(String accessToken) {
  68. log.info("开始验证凭证: {}", accessToken.substring(0, Math.min(20, accessToken.length())) + "...");
  69. try {
  70. String url = BASE_URL + "/parse-token";
  71. JSONObject requestBody = new JSONObject();
  72. requestBody.put("access_token", accessToken);
  73. HttpResponse response = HttpRequest.post(url)
  74. .header("accept", "application/json, text/plain, */*")
  75. .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8")
  76. .header("content-type", "application/json")
  77. .header("origin", "https://www.ow520.com")
  78. .header("referer", "https://www.ow520.com/")
  79. .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36")
  80. .body(requestBody.toString())
  81. .execute();
  82. String body = response.body();
  83. log.info("凭证验证响应: {}", body);
  84. JSONObject jsonResponse = JSONUtil.parseObj(body);
  85. TokenParseResult result = new TokenParseResult(
  86. jsonResponse.getStr("message"),
  87. jsonResponse.getBool("success")
  88. );
  89. log.info("凭证验证结果: {}", result);
  90. return result;
  91. } catch (Exception e) {
  92. log.error("验证凭证失败: {}", e.getMessage(), e);
  93. throw new RuntimeException("验证凭证失败: " + e.getMessage(), e);
  94. }
  95. }
  96. public TaskSubmitResult submitTask(String cardKey, String accessToken, String idp) {
  97. log.info("开始提交任务 - 卡密: {}, idp: {}", cardKey, idp);
  98. try {
  99. String url = BASE_URL + "/tasks";
  100. JSONObject requestBody = new JSONObject();
  101. requestBody.put("card_key", cardKey);
  102. requestBody.put("access_token", accessToken);
  103. requestBody.put("idp", idp);
  104. HttpResponse response = HttpRequest.post(url)
  105. .header("accept", "application/json, text/plain, */*")
  106. .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8")
  107. .header("content-type", "application/json")
  108. .header("origin", "https://www.ow520.com")
  109. .header("referer", "https://www.ow520.com/")
  110. .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36")
  111. .body(requestBody.toString())
  112. .execute();
  113. String body = response.body();
  114. log.info("任务提交响应: {}", body);
  115. JSONObject jsonResponse = JSONUtil.parseObj(body);
  116. TaskSubmitResult result = new TaskSubmitResult(
  117. jsonResponse.getStr("task_id"),
  118. jsonResponse.getBool("success")
  119. );
  120. log.info("任务提交结果: {}", result);
  121. return result;
  122. } catch (Exception e) {
  123. log.error("提交任务失败: {}", e.getMessage(), e);
  124. throw new RuntimeException("提交任务失败: " + e.getMessage(), e);
  125. }
  126. }
  127. public TaskResult getTaskResult(String taskId) {
  128. log.info("开始查询任务结果: {}", taskId);
  129. try {
  130. String uri = "/tasks/" + taskId;
  131. HttpResponse response = createBaseRequest(uri)
  132. .execute();
  133. String body = response.body();
  134. log.info("任务查询响应: {}", body);
  135. JSONObject jsonResponse = JSONUtil.parseObj(body);
  136. TaskResult result = new TaskResult(
  137. jsonResponse.getStr("status"),
  138. jsonResponse.getStr("result")
  139. );
  140. log.info("任务查询结果: {}", result);
  141. String status = result.getStatus();
  142. //更新代充状态
  143. resetGroupsRelationRechargeStatus(taskId, status);
  144. return result;
  145. } catch (Exception e) {
  146. log.error("获取任务结果失败: {}", e.getMessage(), e);
  147. throw new RuntimeException("获取任务结果失败: " + e.getMessage(), e);
  148. }
  149. }
  150. @Override
  151. @Transactional(rollbackFor = Throwable.class)
  152. public String confirmRecharge(GroupsRelationRechargeReq req) {
  153. Long relationId = req.getRelationId();
  154. Long userId = req.getUserId();
  155. List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
  156. GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
  157. .in(GroupsRelation::getUserId, userIdList)
  158. .eq(GroupsRelation::getId, relationId)
  159. .eq(GroupsRelation::getStatus, GroupsRelation.Status.validity));
  160. if (relation == null) {
  161. throw BusinessRuntimeException.getInstance("车票不存在");
  162. }
  163. GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
  164. GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId());
  165. //GPT 代充
  166. if (sku.getGoodsId() != Constant.GPT_RECHARGE_GOODS_ID) {
  167. throw BusinessRuntimeException.getInstance("车票类型错误");
  168. }
  169. Integer rechargeRemainNum = relation.getRechargeRemainNum();
  170. if (rechargeRemainNum == null || rechargeRemainNum <= 0) {
  171. throw BusinessRuntimeException.getInstance("剩余可代充次数为0");
  172. }
  173. if (relation.getRechargeStatus() == GroupsRelation.RechargeStatus.auto_recharge) {
  174. throw BusinessRuntimeException.getInstance("自动充值中");
  175. }
  176. int updateRemainNum = relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
  177. .set(GroupsRelation::getRechargeRemainNum, rechargeRemainNum - 1)
  178. .eq(GroupsRelation::getId, relationId)
  179. .eq(GroupsRelation::getUserId, relation.getUserId())
  180. .eq(GroupsRelation::getRechargeRemainNum, rechargeRemainNum));
  181. if (updateRemainNum == 0) {
  182. throw BusinessRuntimeException.getInstance("代充异常,请重试");
  183. }
  184. OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
  185. .in(OrderDon::getUserId, userIdList)
  186. .eq(OrderDon::getRelationId, relation)
  187. .notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
  188. .orderByDesc(OrderDon::getId)
  189. .last("limit 1"));
  190. if (orderDon == null) {
  191. throw BusinessRuntimeException.getInstance("代充订单不存在或已退款");
  192. }
  193. String accessToken = req.getAccessToken();
  194. //验证用户token是否正确
  195. TokenParseResult tokenParseResult = parseToken(accessToken);
  196. if (!tokenParseResult.getSuccess()) {
  197. throw BusinessRuntimeException.getInstance("您输入的凭证有误,请重新输入");
  198. }
  199. String rechargeAccount = tokenParseResult.getMessage();
  200. //获取GPT代充key
  201. GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class)
  202. .eq(GptRechargeCardKey::getStatus, Boolean.FALSE)
  203. .last("order by rand() limit 1"));
  204. if (gptRechargeCardKey != null) {
  205. setRechargeRelationStatusAutoError(relation);
  206. throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通");
  207. }
  208. int update = gptRechargeCardKeyMapper.update(null, Wrappers.lambdaUpdate(GptRechargeCardKey.class)
  209. .set(GptRechargeCardKey::getStatus, Boolean.TRUE)
  210. .set(GptRechargeCardKey::getOrderId, orderDon.getId())
  211. .set(GptRechargeCardKey::getOrderNo, orderDon.getOrderNo())
  212. .eq(GptRechargeCardKey::getId, gptRechargeCardKey.getId())
  213. .eq(GptRechargeCardKey::getStatus, Boolean.FALSE));
  214. if (update == 0) {
  215. setRechargeRelationStatusAutoError(relation);
  216. throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通");
  217. }
  218. String gptCardKey = gptRechargeCardKey.getCardKey();
  219. //校验卡密是否可用
  220. validateCardKey(gptCardKey);
  221. //提交任务
  222. TaskSubmitResult result = submitTask(gptCardKey, accessToken, "auth0");
  223. if (!result.getSuccess()) {
  224. setRechargeRelationStatusAutoError(relation);
  225. throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通");
  226. }
  227. relation.setAccount(rechargeAccount);
  228. relation.setGptToken(accessToken);
  229. relation.setRechargeStatus(GroupsRelation.RechargeStatus.auto_recharge);
  230. relation.setCardKey(gptCardKey);
  231. String taskId = result.getTaskId();
  232. relation.setGptTaskId(taskId);
  233. relationMapper.updateById(relation);
  234. return taskId;
  235. }
  236. /**
  237. * 设置代充自动充值异常
  238. */
  239. public void setRechargeRelationStatusAutoError(GroupsRelation relation) {
  240. TASK_EXECUTOR.execute(()->{
  241. relation.setRechargeStatus(GroupsRelation.RechargeStatus.auto_error);
  242. relationMapper.updateById(relation);
  243. });
  244. }
  245. /**
  246. * 更新代充状态
  247. */
  248. private void resetGroupsRelationRechargeStatus(String taskId, String status) {
  249. if ("completed".equals(status) || !"processing".equals(status)) {
  250. GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
  251. .eq(GroupsRelation::getGptTaskId, taskId)
  252. .last("limit 1"));
  253. if (relation != null && relation.getRechargeStatus() == GroupsRelation.RechargeStatus.auto_recharge) {
  254. Integer rechargeRemainNum = relation.getRechargeRemainNum();
  255. GroupsRelation.RechargeStatus rechargeStatus = "completed".equals(status) ? GroupsRelation.RechargeStatus.complete : GroupsRelation.RechargeStatus.auto_error;
  256. if (rechargeStatus == GroupsRelation.RechargeStatus.auto_error) {
  257. String cardKey = relation.getCardKey();
  258. GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class)
  259. .eq(GptRechargeCardKey::getCardKey, cardKey)
  260. .last("limit 1"));
  261. if (gptRechargeCardKey != null) {
  262. gptRechargeCardKeyMapper.update(null, Wrappers.lambdaUpdate(GptRechargeCardKey.class)
  263. .set(GptRechargeCardKey::getStatus, Boolean.FALSE)
  264. .set(GptRechargeCardKey::getOrderId, null)
  265. .set(GptRechargeCardKey::getOrderNo, null)
  266. .eq(GptRechargeCardKey::getId, gptRechargeCardKey.getId())
  267. .eq(GptRechargeCardKey::getStatus, Boolean.TRUE));
  268. }
  269. }
  270. relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
  271. .set(rechargeStatus == GroupsRelation.RechargeStatus.auto_error, GroupsRelation::getRechargeRemainNum, rechargeRemainNum + 1)
  272. .set(GroupsRelation::getRechargeStatus, rechargeStatus)
  273. .eq(GroupsRelation::getId, relation.getId())
  274. .eq(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.auto_recharge));
  275. }
  276. }
  277. }
  278. }