|
|
@@ -4,6 +4,7 @@ import cn.hutool.core.date.DateTime;
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
+import cn.hutool.http.HttpException;
|
|
|
import cn.hutool.http.HttpResponse;
|
|
|
import cn.hutool.http.HttpUtil;
|
|
|
import cn.hutool.http.Method;
|
|
|
@@ -16,18 +17,17 @@ import com.cyksj.mapper.*;
|
|
|
import com.cyksj.model.entity.*;
|
|
|
import com.cyksj.model.manage.views.GroupsRelationView;
|
|
|
import com.cyksj.model.request.ClaudeCodeApiKeysReq;
|
|
|
-import com.cyksj.model.request.ClaudeCodeApiKeysStatusReq;
|
|
|
import com.cyksj.model.request.ClaudeCodeDelReq;
|
|
|
import com.cyksj.model.response.ClaudeCodePointsHistoryResp;
|
|
|
import com.cyksj.model.response.claudecode.ClaudeCodeResp;
|
|
|
import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
|
|
|
import com.cyksj.model.views.ClaudeCodeUserInfoView;
|
|
|
-import com.cyksj.model.views.ClaudeCodeUserPackageView;
|
|
|
import com.cyksj.service.claude.ClaudeCodeService;
|
|
|
import com.cyksj.service.user.UserBindRelationService;
|
|
|
import com.ejlchina.searcher.BeanSearcher;
|
|
|
import com.ejlchina.searcher.param.Operator;
|
|
|
import com.ejlchina.searcher.util.MapUtils;
|
|
|
+import com.github.rholder.retry.*;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.dao.DuplicateKeyException;
|
|
|
@@ -37,6 +37,8 @@ import java.util.Date;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.concurrent.ExecutionException;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
/**
|
|
|
* 项目名: yhlxj11111111
|
|
|
@@ -66,6 +68,9 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
|
|
|
public static final String CLAUDE_CODE_API_ADMIN_KEY = "claudecodeyhlxjclaude";
|
|
|
|
|
|
+ //连接超时时间 毫秒
|
|
|
+ public static final int CONNECT_MILLISECONDS = 10000;
|
|
|
+
|
|
|
@Override
|
|
|
public void generateOrUpdateClaudeCodeUserInfo(Long orderId, Long relationId, Long userId, GoodsDonSku sku, Integer orderType) {
|
|
|
List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
|
|
|
@@ -84,31 +89,31 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
Integer codePoints = sku.getCodePoints();
|
|
|
Integer codeCreditRecovery = sku.getCodeCreditRecovery();
|
|
|
Long skuId = sku.getId();
|
|
|
- try {
|
|
|
- Boolean isUpgrade = false;
|
|
|
- Date renewExpiryTime = null;
|
|
|
- //若是续费升级 记录此时续费升级的过期时间
|
|
|
- if (thisRelationCodePoints != null && thisRelationCodePoints <= codePoints && !ObjectUtil.equal(thisCodeOriSkuId, skuId)) {
|
|
|
- saveClaudeCodeRenewExpiryRecord(orderId, relationUserId, relationId, expiryTime, skuId);
|
|
|
- if (sku.getDays() != null) {
|
|
|
- renewExpiryTime = DateUtil.offsetDay(DateTime.now(), sku.getDays());
|
|
|
- } else {
|
|
|
- renewExpiryTime = DateUtil.offsetMonth(DateTime.now(), sku.getMonths());
|
|
|
- }
|
|
|
- isUpgrade = true;
|
|
|
+ Boolean isUpgrade = false;
|
|
|
+ Date renewExpiryTime = null;
|
|
|
+ //若是续费升级 记录此时续费升级的过期时间
|
|
|
+ if (thisRelationCodePoints != null && thisRelationCodePoints <= codePoints && !ObjectUtil.equal(thisCodeOriSkuId, skuId)) {
|
|
|
+ saveClaudeCodeRenewExpiryRecord(orderId, relationUserId, relationId, expiryTime, skuId);
|
|
|
+ if (sku.getDays() != null) {
|
|
|
+ renewExpiryTime = DateUtil.offsetDay(DateTime.now(), sku.getDays());
|
|
|
+ } else {
|
|
|
+ renewExpiryTime = DateUtil.offsetMonth(DateTime.now(), sku.getMonths());
|
|
|
}
|
|
|
- relationMapper.updateById(relation);
|
|
|
- //清缓存
|
|
|
- if (orderType == 2) {
|
|
|
- invalidateUserCache(relationUserId);
|
|
|
- }
|
|
|
- generateOrUpdateClaudeCodeUser(relationUserId, relationId, codePoints, codeCreditRecovery, expiryTime, isUpgrade, orderId, skuId, renewExpiryTime, sku.getSpecVal());
|
|
|
+ isUpgrade = true;
|
|
|
+ }
|
|
|
+ generateOrUpdateClaudeCodeUser(relationUserId, relationId, codePoints, codeCreditRecovery, expiryTime, isUpgrade, orderId, skuId, renewExpiryTime, sku.getSpecVal());
|
|
|
+ try {
|
|
|
//生成claude code或更新用户套餐
|
|
|
ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(relation.getUserId(), sku.getSpecVal(), codePoints, codeCreditRecovery, expiryTime);
|
|
|
if (!Constant.SUCCESS.equals(codeUserPackage.getMessage())) {
|
|
|
log.info("更新 claude code 用户:{}套餐数据失败", userId);
|
|
|
//重试更新code userInfo数据
|
|
|
setClaudeCodeUserRetryUpdateInfo(relationId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //清缓存
|
|
|
+ if (orderType == 2) {
|
|
|
+ invalidateUserCache(relationUserId);
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
log.error("生成或更新claude code用户:{}套餐skuId:{} 失败,error_info:{}", userId, skuId, StringUtil.getErrorText(e));
|
|
|
@@ -165,27 +170,6 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
throw new BusinessRuntimeException("您还没有claudecode账号");
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void updateApiKeysStatus(ClaudeCodeApiKeysStatusReq req) throws Exception {
|
|
|
- Long userId = req.getUserId();
|
|
|
- Integer keyId = req.getId();
|
|
|
- String status = req.getStatus();
|
|
|
- String keyValue = req.getKeyValue();
|
|
|
- if (checkClaudeCodeUser(userId)) {
|
|
|
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
- Assert.notNull(claudeCodeUserId, "您的claude code账号已过期");
|
|
|
- String apiKeyUrl = String.format(CLAUDE_CODE_API_PREFIX + "api/keys/%s/%s", claudeCodeUserId, keyId);
|
|
|
- Map<String, Object> parmas = new HashMap<>();
|
|
|
- parmas.put("status", status);
|
|
|
- String responseBody = executeClaudeCodePostApi(apiKeyUrl, parmas.toString());
|
|
|
- ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
- if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
|
|
|
- //更新用户apikey缓存
|
|
|
- updateUserApiKeysCache(keyValue);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public void deleteApiKeysById(ClaudeCodeDelReq delReq) throws Exception {
|
|
|
Long userId = delReq.getUserId();
|
|
|
@@ -193,7 +177,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
if (checkClaudeCodeUser(userId)) {
|
|
|
Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
String url = String.format(CLAUDE_CODE_API_PREFIX + "api/keys/%s/%s", claudeCodeUserId, keyId);
|
|
|
- HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).execute();
|
|
|
+ HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).setConnectionTimeout(CONNECT_MILLISECONDS).execute();
|
|
|
String responseBody = execute.body();
|
|
|
ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
|
|
|
@@ -202,17 +186,6 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 更新api key缓存
|
|
|
- * @param keyValue
|
|
|
- */
|
|
|
- private void updateUserApiKeysCache(String keyValue) {
|
|
|
- String url = CLAUDE_CODE_API_PREFIX + "api/cache/invalidate/apikey";
|
|
|
- Map<String, Object> parmas = new HashMap<>();
|
|
|
- parmas.put("api_key", keyValue);
|
|
|
- executeClaudeCodePostApi(url,parmas.toString());
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public List<ClaudeCodeUserApiKeysView> getUserApiKeys(long userId) throws Exception {
|
|
|
Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
@@ -225,20 +198,6 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public ClaudeCodeUserPackageView getUserPackage(long userId) throws Exception {
|
|
|
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
- if (claudeCodeUserId != null) {
|
|
|
- String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", claudeCodeUserId);
|
|
|
- String responseBody = executeClaudeCodeGetApi(url);
|
|
|
- ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
- if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
|
|
|
- return Jsons.parseObject(responseBody, ClaudeCodeUserPackageView.class);
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public ClaudeCodePointsHistoryResp getUserPointsDetail(Long userId, String type, Integer page, Integer limit) throws Exception {
|
|
|
Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
@@ -252,18 +211,6 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public ClaudeCodeResp getUserPointsStatisticsData(Long userId, Integer days) throws Exception {
|
|
|
- Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
- if (claudeCodeUserId != null) {
|
|
|
- String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/usage/stats?days=%s", claudeCodeUserId, days);
|
|
|
- String responseBody = executeClaudeCodeGetApi(url);
|
|
|
- ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
- return claudeCodeResp;
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public ClaudeCodeResp getUserDashboard(Long userId) throws Exception {
|
|
|
Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
@@ -312,7 +259,11 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
@Override
|
|
|
public void invalidateUserCache(Long userId) {
|
|
|
String url = String.format(CLAUDE_CODE_API_PREFIX + "api/cache/invalidate/user/%s", userId);
|
|
|
- executeClaudeCodeGetApi(url);
|
|
|
+ try {
|
|
|
+ executeClaudeCodePostApi(url, null);
|
|
|
+ } catch (Exception e) {
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -417,24 +368,23 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
* claude code GET请求
|
|
|
*/
|
|
|
public String executeClaudeCodeGetApi(String url) {
|
|
|
- HttpResponse execute = HttpUtil.createGet(url)
|
|
|
- .header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY)
|
|
|
- .setConnectionTimeout(3000)
|
|
|
- .setReadTimeout(3000)
|
|
|
- .execute();
|
|
|
- return execute.body();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * claude code GET请求
|
|
|
- */
|
|
|
- public String executeClaudeCodeDeleteApi(String url) {
|
|
|
- HttpResponse execute = HttpUtil.createPost(url)
|
|
|
- .header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY)
|
|
|
- .setConnectionTimeout(3000)
|
|
|
- .setReadTimeout(3000)
|
|
|
- .execute();
|
|
|
- return execute.body();
|
|
|
+ Retryer<String> build = getApiRetryer(1, 3);
|
|
|
+ try {
|
|
|
+ return build.call(() -> {
|
|
|
+ try {
|
|
|
+ HttpResponse execute = HttpUtil.createGet(url)
|
|
|
+ .header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY)
|
|
|
+ .setConnectionTimeout(CONNECT_MILLISECONDS)
|
|
|
+ .execute();
|
|
|
+ return execute.body();
|
|
|
+ } catch (HttpException e) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (ExecutionException | RetryException e) {
|
|
|
+ log.info("重试调用claude code GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
|
|
|
+ throw BusinessRuntimeException.getInstance("接口请求失败");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -442,13 +392,24 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
* claude code Post请求
|
|
|
*/
|
|
|
public String executeClaudeCodePostApi(String url, String body) {
|
|
|
- HttpResponse execute = HttpUtil.createPost(url)
|
|
|
- .header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY)
|
|
|
- .setConnectionTimeout(3000)
|
|
|
- .setReadTimeout(3000)
|
|
|
- .body(body)
|
|
|
- .execute();
|
|
|
- return execute.body();
|
|
|
+ Retryer<String> build = getApiRetryer(1, 3);
|
|
|
+ try {
|
|
|
+ return build.call(() -> {
|
|
|
+ try {
|
|
|
+ HttpResponse execute = HttpUtil.createPost(url)
|
|
|
+ .header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY)
|
|
|
+ .setConnectionTimeout(CONNECT_MILLISECONDS)
|
|
|
+ .body(body)
|
|
|
+ .execute();
|
|
|
+ return execute.body();
|
|
|
+ } catch (Exception e) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (ExecutionException | RetryException e) {
|
|
|
+ log.info("重试调用claude code POST请求 url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
|
|
|
+ throw BusinessRuntimeException.getInstance("接口请求失败");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -475,4 +436,18 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public Retryer getApiRetryer(Integer sleepSecond, Integer attemptNum) {
|
|
|
+ Retryer<String> build = RetryerBuilder.<String>newBuilder()
|
|
|
+ .retryIfException()
|
|
|
+ //运行时异常重试
|
|
|
+ .retryIfRuntimeException()
|
|
|
+ //false重试
|
|
|
+ .retryIfResult(res -> res == null)
|
|
|
+ //1s 间隔
|
|
|
+ .withWaitStrategy(WaitStrategies.fixedWait(sleepSecond, TimeUnit.SECONDS))
|
|
|
+ //停止策略 : 尝试请求3次
|
|
|
+ .withStopStrategy(StopStrategies.stopAfterAttempt(attemptNum)).build();
|
|
|
+ return build;
|
|
|
+ }
|
|
|
+
|
|
|
}
|