|
@@ -0,0 +1,648 @@
|
|
|
+package com.zanxiang.game.module.sdk.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
+import com.zanxiang.game.module.base.pojo.enums.BanStatusEnum;
|
|
|
+import com.zanxiang.game.module.base.pojo.enums.DeleteEnum;
|
|
|
+import com.zanxiang.game.module.mybatis.entity.*;
|
|
|
+import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
|
|
|
+import com.zanxiang.game.module.sdk.enums.CpPushDataEnum;
|
|
|
+import com.zanxiang.game.module.sdk.enums.DeviceTypeEnum;
|
|
|
+import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
|
|
|
+import com.zanxiang.game.module.sdk.pojo.dto.PlatformOrderDTO;
|
|
|
+import com.zanxiang.game.module.sdk.pojo.param.*;
|
|
|
+import com.zanxiang.game.module.sdk.pojo.vo.CpPushResultVO;
|
|
|
+import com.zanxiang.game.module.sdk.pojo.vo.CpPushUserVO;
|
|
|
+import com.zanxiang.game.module.sdk.service.*;
|
|
|
+import com.zanxiang.game.module.sdk.util.RegisterUtil;
|
|
|
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
|
|
|
+import com.zanxiang.module.util.JsonUtil;
|
|
|
+import com.zanxiang.module.util.bean.BeanUtil;
|
|
|
+import com.zanxiang.module.util.exception.BaseException;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.logging.log4j.util.Strings;
|
|
|
+import org.json.JSONObject;
|
|
|
+import org.redisson.api.RLock;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.TransactionDefinition;
|
|
|
+import org.springframework.transaction.TransactionStatus;
|
|
|
+import reactor.util.function.Tuple2;
|
|
|
+import reactor.util.function.Tuple3;
|
|
|
+import reactor.util.function.Tuples;
|
|
|
+
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.Base64;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author : lingfeng
|
|
|
+ * @time : 2024-06-20
|
|
|
+ * @description : CP推送数据
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class CpPushDataServiceImpl implements ICpPushDataService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameExtService gameExtService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IUserService userService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IAgentService agentService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameService gameService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ICallBackService callBackService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IUserAgentLogService userAgentLogService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IKafkaService kafkaService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameUserService gameUserService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IUserShareService userShareService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameUserRoleService gameUserRoleService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IGameServerService gameServerService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IOrderService orderService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TransactionDefinition transactionDefinition;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ICpPushErrorLogService cpPushErrorLogService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DataSourceTransactionManager dataSourceTransactionManager;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IDistributedLockComponent distributedLockComponent;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public CpPushResultVO pushOrder(String gameAppId, CpPushOrderParam param) {
|
|
|
+ //查询游戏
|
|
|
+ Game game = this.getGameByGameAppId(gameAppId);
|
|
|
+ //查询订单信息
|
|
|
+ Order order = orderService.getOne(new LambdaQueryWrapper<Order>()
|
|
|
+ .eq(Order::getGameId, game.getId())
|
|
|
+ .eq(Order::getCpOrderId, param.getOrderId()));
|
|
|
+ // 手动开启事务
|
|
|
+ TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
|
|
|
+ try {
|
|
|
+ if (order == null) {
|
|
|
+ order = this.createOrder(game, param);
|
|
|
+ } else {
|
|
|
+ order.setStatus(param.getStatus());
|
|
|
+ order.setPayTime(param.getPayTime());
|
|
|
+ order.setUpdateTime(LocalDateTime.now());
|
|
|
+ }
|
|
|
+ //订单更新或者保存
|
|
|
+ orderService.saveOrUpdate(order);
|
|
|
+ // 提交事务
|
|
|
+ dataSourceTransactionManager.commit(transactionStatus);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 回滚事务
|
|
|
+ dataSourceTransactionManager.rollback(transactionStatus);
|
|
|
+ //保存错误日志
|
|
|
+ cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ORDER, param, e.getMessage());
|
|
|
+ //抛出异常
|
|
|
+ throw new BaseException(e.getMessage());
|
|
|
+ }
|
|
|
+ //订单回传
|
|
|
+ callBackService.orderCallBack(BeanUtil.copy(order, PlatformOrderDTO.class));
|
|
|
+ //判断订单行为
|
|
|
+ if (Objects.equals(param.getStatus(), 2)) {
|
|
|
+ //支付
|
|
|
+ kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ORDER_PAY, JsonUtil.toString(BeanUtil.copy(order, PlatformOrderDTO.class)));
|
|
|
+ } else {
|
|
|
+ //下单
|
|
|
+ kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ORDER_PAY, JsonUtil.toString(order));
|
|
|
+ }
|
|
|
+ //日志更新
|
|
|
+ cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ORDER, param);
|
|
|
+ //构造返回
|
|
|
+ return CpPushResultVO.builder().result(Boolean.TRUE).build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private Order createOrder(Game game, CpPushOrderParam param) {
|
|
|
+ String lockKey = RedisKeyConstant.ORDER_CREATE_LOCK + param.getOpenId() + "_" + param.getOrderId();
|
|
|
+ if (!distributedLockComponent.doLock(lockKey, 0L, 1L, TimeUnit.MINUTES)) {
|
|
|
+ log.error("[订单推送]正在创建中, param : {}", JsonUtil.toString(param));
|
|
|
+ throw new BaseException("接口调用订单正在创建中");
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ //查询玩家信息
|
|
|
+ User user = userService.getOne(new LambdaQueryWrapper<User>()
|
|
|
+ .eq(User::getOpenId, param.getOpenId())
|
|
|
+ .eq(User::getGameId, game.getId()));
|
|
|
+ if (user == null) {
|
|
|
+ throw new BaseException("[订单推送]玩家信息不存在");
|
|
|
+ }
|
|
|
+ //玩家信息
|
|
|
+ GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
|
|
|
+ .eq(GameUser::getUserId, user.getId()));
|
|
|
+ if (gameUser == null) {
|
|
|
+ throw new BaseException("[订单推送]游戏玩家信息不存在");
|
|
|
+ }
|
|
|
+ //角色信息
|
|
|
+ GameUserRole gameUserRole = gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
|
|
|
+ .eq(GameUserRole::getGameId, game.getId())
|
|
|
+ .eq(GameUserRole::getUserId, user.getId())
|
|
|
+ .eq(GameUserRole::getRoleId, param.getRoleId()));
|
|
|
+ if (gameUserRole == null) {
|
|
|
+ throw new BaseException("[订单推送]角色信息不存在");
|
|
|
+ }
|
|
|
+ //构造订单
|
|
|
+ return this.transform(game, param, user, gameUser, gameUserRole);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[订单推送]订单创建出现异常, game : {}, param : {}, e : {}", JsonUtil.toString(game), JsonUtil.toString(param), e.getMessage(), e);
|
|
|
+ throw new BaseException("[订单推送]订单创建出现异常!");
|
|
|
+ } finally {
|
|
|
+ RLock rLock = distributedLockComponent.getLock(lockKey);
|
|
|
+ if (rLock != null) {
|
|
|
+ distributedLockComponent.unlock(lockKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Order transform(Game game, CpPushOrderParam param, User user, GameUser gameUser, GameUserRole gameUserRole) {
|
|
|
+ return Order.builder()
|
|
|
+ .orderId(orderService.getOrderNum(user.getId()))
|
|
|
+ .cpOrderId(param.getOrderId())
|
|
|
+ .agentId(user.getAgentId())
|
|
|
+ .cpId(game.getCpId())
|
|
|
+ .userId(user.getId())
|
|
|
+ .mgUserId(gameUser.getId())
|
|
|
+ .regTime(user.getCreateTime())
|
|
|
+ .gameId(game.getId())
|
|
|
+ .roleId(gameUserRole.getRoleId())
|
|
|
+ .roleName(gameUserRole.getRoleName())
|
|
|
+ .roleLevel(gameUserRole.getRoleLevel())
|
|
|
+ .roleVipLevel(gameUserRole.getRoleVipLevel())
|
|
|
+ .serverId(gameUserRole.getServerId())
|
|
|
+ .serverName(gameUserRole.getServerName())
|
|
|
+ .amount(param.getAmount())
|
|
|
+ .realAmount(param.getStatus() == 2 ? param.getAmount() : null)
|
|
|
+ .productId(param.getProductId())
|
|
|
+ .productName(param.getProductName())
|
|
|
+ .deviceSystem(user.getDeviceSystem())
|
|
|
+ .payWayId(0L)
|
|
|
+ .payDeviceId(0L)
|
|
|
+ .gamePayWayId(0L)
|
|
|
+ .ext(param.getExtension())
|
|
|
+ .status(param.getStatus())
|
|
|
+ .payTime(param.getPayTime())
|
|
|
+ .createTime(param.getCreateTime())
|
|
|
+ .updateTime(LocalDateTime.now())
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public CpPushResultVO pushActive(String gameAppId, CpPushActiveParam param) {
|
|
|
+ //查询游戏
|
|
|
+ Game game = this.getGameByGameAppId(gameAppId);
|
|
|
+ try {
|
|
|
+ //查询玩家信息
|
|
|
+ User user = userService.getOne(new LambdaQueryWrapper<User>()
|
|
|
+ .eq(User::getOpenId, param.getOpenId())
|
|
|
+ .eq(User::getGameId, game.getId()));
|
|
|
+ if (user == null) {
|
|
|
+ throw new BaseException("[活跃推送]角色信息不存在");
|
|
|
+ }
|
|
|
+ //查询角色信息
|
|
|
+ GameUserRole gameUserRole = gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
|
|
|
+ .eq(GameUserRole::getUserId, user.getId())
|
|
|
+ .eq(GameUserRole::getGameId, game.getId())
|
|
|
+ .eq(GameUserRole::getServerId, param.getServerId())
|
|
|
+ .eq(GameUserRole::getRoleId, param.getRoleId())
|
|
|
+ .orderByDesc(GameUserRole::getCreateTime)
|
|
|
+ .last("limit 1"));
|
|
|
+ if (gameUserRole == null) {
|
|
|
+ throw new BaseException("[活跃推送]角色信息不存在");
|
|
|
+ }
|
|
|
+ //角色活跃信息上报到卡夫卡
|
|
|
+ kafkaService.roleActiveTrack(gameUserRole, param.getActiveType());
|
|
|
+ } catch (Exception e) {
|
|
|
+ //保存错误日志
|
|
|
+ cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ACTIVE, param, e.getMessage());
|
|
|
+ //抛出异常
|
|
|
+ throw new BaseException(e.getMessage());
|
|
|
+ }
|
|
|
+ //日志更新
|
|
|
+ cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ACTIVE, param);
|
|
|
+ //构造返回
|
|
|
+ return CpPushResultVO.builder().result(Boolean.TRUE).build();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public CpPushResultVO pushServer(String gameAppId, CpPushServerParam param) {
|
|
|
+ //查询游戏
|
|
|
+ Game game = this.getGameByGameAppId(gameAppId);
|
|
|
+ boolean result;
|
|
|
+ // 手动开启事务
|
|
|
+ TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
|
|
|
+ try {
|
|
|
+ //查询区服id
|
|
|
+ GameServer gameServer = gameServerService.getOne(new LambdaQueryWrapper<GameServer>()
|
|
|
+ .eq(GameServer::getGameId, game.getSuperGameId())
|
|
|
+ .eq(GameServer::getServerId, param.getServerId())
|
|
|
+ );
|
|
|
+ GameServer transform = this.transform(game.getSuperGameId(), param);
|
|
|
+ if (gameServer == null) {
|
|
|
+ gameServer = transform;
|
|
|
+ } else {
|
|
|
+ gameServer.setGameId(transform.getGameId());
|
|
|
+ gameServer.setServerId(transform.getServerId());
|
|
|
+ gameServer.setServerName(transform.getServerName());
|
|
|
+ gameServer.setNickName(transform.getNickName());
|
|
|
+ gameServer.setStartTime(transform.getStartTime());
|
|
|
+ gameServer.setUpdateTime(LocalDateTime.now());
|
|
|
+ }
|
|
|
+ //区服添加或者更新
|
|
|
+ result = gameServerService.saveOrUpdate(gameServer);
|
|
|
+ //提交事务
|
|
|
+ dataSourceTransactionManager.commit(transactionStatus);
|
|
|
+ } catch (Exception e) {
|
|
|
+ //回滚事务
|
|
|
+ dataSourceTransactionManager.rollback(transactionStatus);
|
|
|
+ //保存错误日志
|
|
|
+ cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_SERVER, param, e.getMessage());
|
|
|
+ //抛出异常
|
|
|
+ throw new BaseException(e.getMessage());
|
|
|
+ }
|
|
|
+ //日志更新
|
|
|
+ cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_SERVER, param);
|
|
|
+ //构造返回
|
|
|
+ return CpPushResultVO.builder().result(result).build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private GameServer transform(Long superGameId, CpPushServerParam param) {
|
|
|
+ return GameServer.builder()
|
|
|
+ .gameId(superGameId)
|
|
|
+ .serverId(param.getServerId())
|
|
|
+ .serverName(param.getServerName())
|
|
|
+ .nickName(param.getNickName())
|
|
|
+ .startTime(param.getStartTime())
|
|
|
+ .isDelete(DeleteEnum.NO.getCode())
|
|
|
+ .createBy(0L)
|
|
|
+ .createTime(LocalDateTime.now())
|
|
|
+ .isSourceServer(Boolean.TRUE)
|
|
|
+ .isMerge(Boolean.FALSE)
|
|
|
+ .updateBy(0L)
|
|
|
+ .updateTime(LocalDateTime.now())
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public CpPushResultVO pushRole(String gameAppId, CpPushRoleParam param) {
|
|
|
+ //查询游戏
|
|
|
+ Game game = this.getGameByGameAppId(gameAppId);
|
|
|
+ boolean result;
|
|
|
+ // 手动开启事务
|
|
|
+ TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
|
|
|
+ try {
|
|
|
+ //查询玩家信息
|
|
|
+ User user = userService.getOne(new LambdaQueryWrapper<User>()
|
|
|
+ .eq(User::getGameId, game.getId())
|
|
|
+ .eq(User::getOpenId, param.getOpenId()));
|
|
|
+ if (user == null) {
|
|
|
+ throw new BaseException("[角色推送]玩家信息不存在");
|
|
|
+ }
|
|
|
+ //查询玩家角色信息
|
|
|
+ GameUserRole gameUserRole = gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
|
|
|
+ .eq(GameUserRole::getUserId, user.getId())
|
|
|
+ .eq(GameUserRole::getGameId, user.getGameId())
|
|
|
+ .eq(GameUserRole::getRoleId, param.getRoleId()));
|
|
|
+ if (gameUserRole == null) {
|
|
|
+ result = this.gameRoleCreate(param, user);
|
|
|
+ } else {
|
|
|
+ result = this.gameRoleUpdate(param, gameUserRole, user);
|
|
|
+ }
|
|
|
+ // 提交事务
|
|
|
+ dataSourceTransactionManager.commit(transactionStatus);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 回滚事务
|
|
|
+ dataSourceTransactionManager.rollback(transactionStatus);
|
|
|
+ //保存错误日志
|
|
|
+ cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ROLE, param, e.getMessage());
|
|
|
+ //抛出异常
|
|
|
+ throw new BaseException(e.getMessage());
|
|
|
+ }
|
|
|
+ //日志更新
|
|
|
+ cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ROLE, param);
|
|
|
+ //构造返回
|
|
|
+ return CpPushResultVO.builder().result(result).build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean gameRoleCreate(CpPushRoleParam param, User user) {
|
|
|
+ GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
|
|
|
+ .select(GameUser::getId)
|
|
|
+ .eq(GameUser::getGameId, user.getGameId())
|
|
|
+ .eq(GameUser::getUserId, user.getId()));
|
|
|
+ if (gameUser == null) {
|
|
|
+ throw new BaseException("[角色推送]游戏玩家信息不存在");
|
|
|
+ }
|
|
|
+ //上锁
|
|
|
+ if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_CREATE_LOCK + user.getGameId() + "_" + param.getRoleId(),
|
|
|
+ 0L, 1L, TimeUnit.MINUTES)) {
|
|
|
+ log.error("[角色推送]角色正在创建中, param : {}, user : {}", JsonUtil.toString(param), JsonUtil.toString(user));
|
|
|
+ return Boolean.TRUE;
|
|
|
+ }
|
|
|
+ //创建角色
|
|
|
+ GameUserRole userRole = this.transform(param, gameUser, user);
|
|
|
+ boolean result = gameUserRoleService.save(userRole);
|
|
|
+ //更新用户创角数
|
|
|
+ userService.update(new LambdaUpdateWrapper<User>()
|
|
|
+ .setSql("role_count=role_count+" + 1)
|
|
|
+ .set(User::getUpdateTime, LocalDateTime.now())
|
|
|
+ .eq(User::getId, user.getId()));
|
|
|
+ //更新玩家创角数
|
|
|
+ gameUserService.update(new LambdaUpdateWrapper<GameUser>()
|
|
|
+ .setSql("role_count=role_count+" + 1)
|
|
|
+ .set(GameUser::getUpdateTime, LocalDateTime.now())
|
|
|
+ .eq(GameUser::getId, gameUser.getId()));
|
|
|
+ //用户创角回传
|
|
|
+ callBackService.roleCallBack(userRole);
|
|
|
+ //用户创角埋点数据发送到卡夫卡
|
|
|
+ kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ROLE_CREATE, JsonUtil.toString(userRole));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean gameRoleUpdate(CpPushRoleParam param, GameUserRole gameUserRole, User user) {
|
|
|
+ //更新频率限制, 20秒更新一次, 避免游戏实时战力高频上报
|
|
|
+ if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_LEVEL_UP + user.getGameId() + "_" + param.getRoleId(),
|
|
|
+ 0L, 20L, TimeUnit.SECONDS)) {
|
|
|
+ return Boolean.TRUE;
|
|
|
+ }
|
|
|
+ //玩家角色信息更新
|
|
|
+ if (param.getExtra() != null && Strings.isNotBlank(JsonUtil.toString(param.getExtra()))) {
|
|
|
+ gameUserRole.setExtra(JsonUtil.toString(param.getExtra()));
|
|
|
+ }
|
|
|
+ if (gameUserRole.getServerId() == null) {
|
|
|
+ gameUserRole.setServerId(param.getServerId());
|
|
|
+ }
|
|
|
+ if (param.getRolePower() != null) {
|
|
|
+ gameUserRole.setRolePower(param.getRolePower());
|
|
|
+ }
|
|
|
+ if (param.getRoleVipLevel() != null) {
|
|
|
+ gameUserRole.setRoleVipLevel(param.getRoleVipLevel());
|
|
|
+ }
|
|
|
+ gameUserRole.setRoleName(param.getRoleName());
|
|
|
+ gameUserRole.setRoleLevel(param.getRoleLevel());
|
|
|
+ gameUserRole.setServerName(param.getServerName());
|
|
|
+ gameUserRole.setUpdateTime(LocalDateTime.now());
|
|
|
+ boolean result = gameUserRoleService.updateById(gameUserRole);
|
|
|
+ //角色更新数据埋点发送到卡夫卡
|
|
|
+ kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ROLE_UPDATE, JsonUtil.toString(gameUserRole));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private GameUserRole transform(CpPushRoleParam param, GameUser gameUser, User user) {
|
|
|
+ String extraJson = JsonUtil.toString(param.getExtra());
|
|
|
+ return GameUserRole.builder()
|
|
|
+ .userId(user.getId())
|
|
|
+ .gameUserId(gameUser.getId())
|
|
|
+ .gameId(user.getGameId())
|
|
|
+ .serverId(param.getServerId())
|
|
|
+ .serverName(param.getServerName())
|
|
|
+ .roleId(param.getRoleId())
|
|
|
+ .roleName(param.getRoleName())
|
|
|
+ .roleLevel(param.getRoleLevel())
|
|
|
+ .roleVipLevel(param.getRoleVipLevel())
|
|
|
+ .rolePower(param.getRolePower())
|
|
|
+ .os(user.getDeviceSystem())
|
|
|
+ .regTime(user.getCreateTime())
|
|
|
+ .createTime(param.getCreateTime())
|
|
|
+ .updateTime(LocalDateTime.now())
|
|
|
+ .lastLoginTime(LocalDateTime.now())
|
|
|
+ .extra(param.getExtra() == null || Strings.isBlank(extraJson) ? null : extraJson)
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public CpPushUserVO pushUser(String gameAppId, CpPushUserParam param) {
|
|
|
+ //查询游戏
|
|
|
+ Game game = this.getGameByGameAppId(gameAppId);
|
|
|
+ //结果信息
|
|
|
+ CpPushUserVO cpPushUserVO;
|
|
|
+ // 手动开启事务
|
|
|
+ TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
|
|
|
+ try {
|
|
|
+ //中间数据
|
|
|
+ UserData userData = UserData.builder().gameId(game.getId()).channel(param.getChannel()).ip(param.getIp()).ua(param.getUa()).build();
|
|
|
+ //根据openId查询用户
|
|
|
+ User user = userService.getOne(new LambdaQueryWrapper<User>()
|
|
|
+ .eq(User::getGameId, game.getId())
|
|
|
+ .eq(User::getOpenId, param.getOpenId()));
|
|
|
+ //玩家信息不存在
|
|
|
+ if (user == null) {
|
|
|
+ cpPushUserVO = this.createUser(game, userData, param);
|
|
|
+ } else {
|
|
|
+ //玩家信息更新
|
|
|
+ Map<String, String> channelMap = this.updateUser(user, param, game, userData);
|
|
|
+ cpPushUserVO = CpPushUserVO.builder().userId(user.getId())
|
|
|
+ .sdkUser(!Objects.equals(user.getAgentId(), Agent.DEFAULT_AGENT))
|
|
|
+ .channel(JsonUtil.toString(channelMap))
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+ // 提交事务
|
|
|
+ dataSourceTransactionManager.commit(transactionStatus);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 回滚事务
|
|
|
+ dataSourceTransactionManager.rollback(transactionStatus);
|
|
|
+ //保存错误日志
|
|
|
+ cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_USER, param, e.getMessage());
|
|
|
+ //抛出异常
|
|
|
+ throw new BaseException(e.getMessage());
|
|
|
+ }
|
|
|
+ //日志更新
|
|
|
+ cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_USER, param);
|
|
|
+ //返回结果
|
|
|
+ return cpPushUserVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ private CpPushUserVO createUser(Game game, UserData userData, CpPushUserParam param) {
|
|
|
+ //游戏id
|
|
|
+ Long gameId = game.getId();
|
|
|
+ //线程锁Key
|
|
|
+ String lockKey = RedisKeyConstant.USER_CREATE + gameId + "_" + param.getOpenId();
|
|
|
+ //上锁
|
|
|
+ if (!distributedLockComponent.doLock(lockKey, 0L, 3L, TimeUnit.MINUTES)) {
|
|
|
+ log.error("[用户推送]用户正在创建中, param : {}, game : {}", JsonUtil.toString(param), JsonUtil.toString(game));
|
|
|
+ throw new BaseException("[用户推送]用户正在创建中");
|
|
|
+ }
|
|
|
+ //玩家信息
|
|
|
+ User user;
|
|
|
+ //渠道map
|
|
|
+ Map<String, String> channelMap = null;
|
|
|
+ try {
|
|
|
+ //判断是否分享玩家
|
|
|
+ if (Strings.isNotBlank(param.getShareOpenId())) {
|
|
|
+ User shareUser = userService.getOne(new LambdaQueryWrapper<User>()
|
|
|
+ .eq(User::getGameId, gameId)
|
|
|
+ .eq(User::getOpenId, param.getShareOpenId())
|
|
|
+ .last("limit 1"));
|
|
|
+ user = this.transform(gameId, shareUser, param);
|
|
|
+ } else {
|
|
|
+ Tuple3<Long, Map<String, String>, String> tuple3 = this.getUserAgentChannel(game, userData);
|
|
|
+ user = this.transform(gameId, tuple3, param);
|
|
|
+ channelMap = tuple3.getT2();
|
|
|
+ }
|
|
|
+ userService.save(user);
|
|
|
+ gameUserService.createGameUser(user);
|
|
|
+ userAgentLogService.regAgentLog(user);
|
|
|
+ //非分享用户, 回传注册
|
|
|
+ if (Strings.isBlank(param.getShareOpenId())) {
|
|
|
+ callBackService.userCallBack(user, channelMap);
|
|
|
+ } else {
|
|
|
+ //记录分享信息, 用户不回传
|
|
|
+ userShareService.createShareLog(user, userData);
|
|
|
+ }
|
|
|
+ //注册信息埋点数据发送到卡夫卡
|
|
|
+ kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_REG, JsonUtil.toString(user));
|
|
|
+ //返回构造数据
|
|
|
+ return CpPushUserVO.builder().userId(user.getId())
|
|
|
+ .sdkUser(!Objects.equals(user.getAgentId(), Agent.DEFAULT_AGENT))
|
|
|
+ .channel(JsonUtil.toString(channelMap))
|
|
|
+ .build();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[用户推送]用户创建出现异常, gameId : {}, param : {}, e : {}", gameId, JsonUtil.toString(param), e.getMessage(), e);
|
|
|
+ throw new BaseException("[用户推送]用户创建出现异常");
|
|
|
+ } finally {
|
|
|
+ RLock rLock = distributedLockComponent.getLock(lockKey);
|
|
|
+ if (rLock != null) {
|
|
|
+ distributedLockComponent.unlock(lockKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, String> updateUser(User user, CpPushUserParam param, Game game, UserData userData) {
|
|
|
+ //活跃间隔时长
|
|
|
+ long inactiveDay = 15L;
|
|
|
+ //判定不活跃时长是否达到限制
|
|
|
+ if (param.getActiveTime().plusDays(inactiveDay).isAfter(LocalDateTime.now())) {
|
|
|
+ return Collections.emptyMap();
|
|
|
+ }
|
|
|
+ //渠道id, 链接参数
|
|
|
+ Tuple3<Long, Map<String, String>, String> tuple3 = this.getUserAgentChannel(game, userData);
|
|
|
+ //查询渠道
|
|
|
+ Agent agent = agentService.getById(tuple3.getT1());
|
|
|
+ if (agent == null) {
|
|
|
+ return Collections.emptyMap();
|
|
|
+ }
|
|
|
+ //更新用户信息
|
|
|
+ user.setAgentId(agent.getId());
|
|
|
+ user.setChannel(userData.getChannel());
|
|
|
+ user.setUpdateTime(LocalDateTime.now());
|
|
|
+ userService.updateById(user);
|
|
|
+ //添加渠道变更记录
|
|
|
+ userAgentLogService.agentUpdateLog(user, agent.getId(), userData.getChannel());
|
|
|
+ //回传用户信息
|
|
|
+ callBackService.userCallBack(user, tuple3.getT2());
|
|
|
+ //渠道变更信息埋点数据发送到卡夫卡
|
|
|
+ kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_AGENT_UPDATE, JsonUtil.toString(user));
|
|
|
+ //返回更新的渠道信息
|
|
|
+ return tuple3.getT2();
|
|
|
+ }
|
|
|
+
|
|
|
+ private Tuple3<Long, Map<String, String>, String> getUserAgentChannel(Game game, UserData userData) {
|
|
|
+ //解析渠道信息
|
|
|
+ String channel = new String(Base64.getDecoder().decode(userData.getChannel()));
|
|
|
+ //没有携带渠道标识, 无法解析渠道信息, 判定为自然量
|
|
|
+ if (!channel.contains("agentKey") || !channel.contains("state")) {
|
|
|
+ return Tuples.of(0L, Collections.emptyMap(), channel);
|
|
|
+ }
|
|
|
+ Tuple2<Boolean, Boolean> jsonAndEmpty = this.isJsonAndEmpty(channel);
|
|
|
+ //channel渠道信息非json格式, 或者是空json
|
|
|
+ if (!jsonAndEmpty.getT1() || jsonAndEmpty.getT2()) {
|
|
|
+ //返回自然量渠道
|
|
|
+ return Tuples.of(0L, Collections.emptyMap(), channel);
|
|
|
+ }
|
|
|
+ //渠道id, 链接参数, 分享人id
|
|
|
+ Tuple3<Long, Map<String, String>, String> tuple3 = agentService.getUserAgentId(game, userData);
|
|
|
+ //返回渠道id, 渠道参数
|
|
|
+ return Tuples.of(tuple3.getT1(), tuple3.getT2(), channel);
|
|
|
+ }
|
|
|
+
|
|
|
+ private User transform(Long gameId, User shareUser, CpPushUserParam param) {
|
|
|
+ return User.builder()
|
|
|
+ .openId(param.getOpenId())
|
|
|
+ .regAgentId(shareUser.getRegAgentId())
|
|
|
+ .agentId(shareUser.getAgentId())
|
|
|
+ .channel(shareUser.getChannel())
|
|
|
+ .gameId(gameId)
|
|
|
+ .username(param.getOpenId())
|
|
|
+ .nickname(RegisterUtil.randomNickName(param.getOpenId()))
|
|
|
+ .deviceType(DeviceTypeEnum.DEVICE_TYPE_MINI_APP.getDeviceType())
|
|
|
+ .status(BanStatusEnum.NORMAL_STATUS.getStatus())
|
|
|
+ .authentication(0)
|
|
|
+ .createTime(param.getRegTime())
|
|
|
+ .updateTime(LocalDateTime.now())
|
|
|
+ .deviceSystem(param.getOs())
|
|
|
+ .ip(param.getIp())
|
|
|
+ .shareUserId(shareUser.getId())
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private User transform(Long gameId, Tuple3<Long, Map<String, String>, String> tuple3, CpPushUserParam param) {
|
|
|
+ return User.builder()
|
|
|
+ .openId(param.getOpenId())
|
|
|
+ .regAgentId(tuple3.getT1())
|
|
|
+ .agentId(tuple3.getT1())
|
|
|
+ .channel(tuple3.getT2().isEmpty() ? tuple3.getT3() : JsonUtil.toString(tuple3.getT2()))
|
|
|
+ .gameId(gameId)
|
|
|
+ .username(param.getOpenId())
|
|
|
+ .nickname(RegisterUtil.randomNickName(param.getOpenId()))
|
|
|
+ .deviceType(DeviceTypeEnum.DEVICE_TYPE_MINI_APP.getDeviceType())
|
|
|
+ .status(BanStatusEnum.NORMAL_STATUS.getStatus())
|
|
|
+ .authentication(0)
|
|
|
+ .createTime(param.getRegTime())
|
|
|
+ .updateTime(LocalDateTime.now())
|
|
|
+ .deviceSystem(param.getOs())
|
|
|
+ .ip(param.getIp())
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private Tuple2<Boolean, Boolean> isJsonAndEmpty(String str) {
|
|
|
+ try {
|
|
|
+ JSONObject jsonObject = new JSONObject(str);
|
|
|
+ return Tuples.of(Boolean.TRUE, jsonObject.keySet().isEmpty());
|
|
|
+ } catch (Exception e) {
|
|
|
+ return Tuples.of(Boolean.FALSE, Boolean.FALSE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Game getGameByGameAppId(String gameAppId) {
|
|
|
+ //游戏拓展信息
|
|
|
+ GameExt gameExt = gameExtService.getByGameAppId(gameAppId);
|
|
|
+ if (gameExt == null) {
|
|
|
+ log.error("参数错误, 游戏拓展信息配置不存在, gameAppId : {}", gameAppId);
|
|
|
+ throw new BaseException("参数错误, 游戏拓展信息配置不存在");
|
|
|
+ }
|
|
|
+ //查询游戏
|
|
|
+ Game game = gameService.getById(gameExt.getGameId());
|
|
|
+ if (game == null) {
|
|
|
+ log.error("参数错误, 游戏配置不存在, gameAppId : {}", gameAppId);
|
|
|
+ throw new BaseException("参数错误, 游戏配置不存在");
|
|
|
+ }
|
|
|
+ return game;
|
|
|
+ }
|
|
|
+}
|