Explorar o código

Merge remote-tracking branch 'origin/package' into package

zhangxianyu hai 1 mes
pai
achega
df82732c5f

+ 1 - 1
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/GameBackApplication.java

@@ -18,7 +18,7 @@ public class GameBackApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(GameBackApplication.class, args);
-        System.out.println("腾讯广告新增监测链接注册回传(监测链接接口优化-02) (´・・)ノ(._.`)  \n" +
+        System.out.println("腾讯广告新增监测链接注册回传(监测链接callBackUrl匹配优化) (´・・)ノ(._.`)  \n" +
                 " ______  __     __     \n" +
                 "/_____/\\/__/\\ /__/\\    \n" +
                 "\\:::__\\/\\ \\::\\\\:.\\ \\   \n" +

+ 13 - 4
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/TencentMiniGameLogController.java

@@ -8,10 +8,8 @@ import com.zanxiang.game.back.serve.pojo.dto.OrderReportDTO;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameOrderVO;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameUserVO;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniOrderSplitLogVO;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameOrderService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameOrderSplitLogService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameRoleRegisterService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameUserService;
+import com.zanxiang.game.back.serve.service.*;
+import com.zanxiang.module.util.DateUtil;
 import com.zanxiang.module.util.exception.BaseException;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
@@ -39,6 +37,9 @@ public class TencentMiniGameLogController {
     @Autowired
     private IGameTencentMiniGameOrderSplitLogService gameTencentMiniGameOrderSplitLogService;
 
+    @Autowired
+    private IGameTencentMiniGameCallbackService gameTencentMiniGameCallbackService;
+
     @Autowired
     private IGameTencentMiniGameRoleRegisterService gameTencentMiniGameRoleRegisterService;
 
@@ -116,4 +117,12 @@ public class TencentMiniGameLogController {
         return ResultVO.ok(gameTencentMiniGameRoleRegisterService.doReport(ids));
     }
 
+    @PreAuthorize(permissionKey = "gameBack:tencentMiniGame:userUpdateCallBackUrl")
+    @GetMapping("/user/update/back/url")
+    @ApiOperation(value = "玩家信息更新回传地址")
+    public ResultVO<Boolean> userUpdateCallBackUrl(@RequestParam Long gameId, @RequestParam long startTime) {
+        gameTencentMiniGameCallbackService.delayUpdateMiniGameUserCallBackUrl(gameId, DateUtil.secondToLocalDateTime(startTime));
+        return ResultVO.ok();
+    }
+
 }

+ 1 - 2
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentMiniGameCallbackService.java

@@ -1,7 +1,6 @@
 package com.zanxiang.game.back.serve.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.zanxiang.game.back.serve.pojo.dto.GameTencentCallbackDTO;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameCallback;
 
 import java.time.LocalDateTime;
@@ -9,7 +8,7 @@ import java.util.Map;
 
 public interface IGameTencentMiniGameCallbackService extends IService<GameTencentMiniGameCallback> {
 
-    boolean callback(GameTencentCallbackDTO dto);
+    void delayUpdateMiniGameUserCallBackUrl(Long gameId, LocalDateTime startTime);
 
     boolean callback(Map<String, Object> paramMap);
 

+ 99 - 27
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentMiniGameCallbackServiceImpl.java

@@ -2,32 +2,46 @@ package com.zanxiang.game.back.serve.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import com.zanxiang.erp.base.ErpServer;
 import com.zanxiang.erp.base.rpc.IDingTalkMsgRpc;
 import com.zanxiang.game.back.serve.dao.mapper.GameTencentMiniGameCallbackMapper;
-import com.zanxiang.game.back.serve.pojo.dto.GameTencentCallbackDTO;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameCallback;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameRoleRegister;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameUser;
+import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.pojo.enums.BackTypeEnum;
 import com.zanxiang.game.back.serve.service.IGameTencentMiniGameCallbackService;
+import com.zanxiang.game.back.serve.service.IGameTencentMiniGameRoleRegisterService;
+import com.zanxiang.game.back.serve.service.IGameTencentMiniGameUserService;
 import com.zanxiang.game.module.base.ServerInfo;
 import com.zanxiang.game.module.base.pojo.vo.AgentRpcVO;
 import com.zanxiang.game.module.base.rpc.IAgentRpc;
 import com.zanxiang.module.util.DateUtil;
 import com.zanxiang.module.util.JsonUtil;
 import com.zanxiang.module.util.URIUtil;
-import com.zanxiang.module.util.bean.BeanUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.apache.kafka.clients.producer.KafkaProducer;
 import org.apache.kafka.clients.producer.ProducerRecord;
 import org.apache.logging.log4j.util.Strings;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Service
@@ -46,31 +60,22 @@ public class GameTencentMiniGameCallbackServiceImpl extends ServiceImpl<GameTenc
     @Autowired
     private KafkaProducer<String, String> kafkaProducer;
 
-    @Override
-    public boolean callback(GameTencentCallbackDTO dto) {
-        AgentRpcVO agent = agentRpc.getByTencentAccountId(dto.getAccountId()).getData();
-        if (agent == null) {
-            log.error("腾讯检测链接数据找不到渠道:{}", JsonUtil.toString(dto));
-        }
-        GameTencentMiniGameCallback callback = BeanUtil.copy(dto, GameTencentMiniGameCallback.class);
-        if (agent != null) {
-            callback.setAgentKey(agent.getAgentKey());
-            callback.setGameId(agent.getGameId());
-            callback.setWechatAppId(agent.getAppId());
-        } else {
-            callback.setAgentKey("-");
-            callback.setGameId(-1L);
-        }
-        callback.setDay(dto.getClickTime() == null || dto.getClickTime() < 1000 ? LocalDate.now() : DateUtil.secondToLocalDate(dto.getClickTime()));
-        save(callback);
-        //信息发送到卡夫卡
-        try {
-            kafkaProducer.send(new ProducerRecord<>(tencentCallbackTopic, dto.getAccountId().toString(), JsonUtil.toString(callback)));
-        } catch (Exception e) {
-            log.error(e.getMessage(), e);
-        }
-        return true;
-    }
+    @Lazy
+    @Autowired
+    private IGameTencentMiniGameUserService gameTencentMiniGameUserService;
+
+    @Lazy
+    @Autowired
+    private IGameTencentMiniGameRoleRegisterService gameTencentMiniGameRoleRegisterService;
+
+    private static final ThreadPoolExecutor THREAD_POOL_CALL_BACK_URL_UPDATE = new ThreadPoolExecutor(
+            10,
+            10,
+            0,
+            TimeUnit.MINUTES,
+            new LinkedBlockingQueue<>(),
+            new ThreadFactoryBuilder()
+                    .setNameFormat("sync-ipDataAssay-%d").build());
 
     @Override
     public boolean callback(Map<String, Object> paramMap) {
@@ -151,4 +156,71 @@ public class GameTencentMiniGameCallbackServiceImpl extends ServiceImpl<GameTenc
         }
         return null;
     }
+
+    @Override
+    public void delayUpdateMiniGameUserCallBackUrl(Long gameId, LocalDateTime startTime) {
+        //时间范围
+        LocalDateTime minCreateTime = startTime == null ? LocalDateTime.now().minusHours(1) : startTime;
+        //查询5分钟之内, callBackUrl未匹配上的数据
+        List<GameTencentMiniGameUser> miniGameUserList = gameTencentMiniGameUserService.list(
+                new LambdaQueryWrapper<GameTencentMiniGameUser>()
+                        .eq(GameTencentMiniGameUser::getGameId, gameId)
+                        .isNull(GameTencentMiniGameUser::getCallBackUrl)
+                        .gt(GameTencentMiniGameUser::getCreateTime, minCreateTime)
+                        .eq(GameTencentMiniGameUser::getBackType, BackTypeEnum.BACK_API.getBackType()));
+        if (CollectionUtils.isEmpty(miniGameUserList)) {
+            return;
+        }
+        //数据处理
+        List<CompletableFuture<?>> futures = miniGameUserList.stream().map(user -> CompletableFuture.runAsync(() -> {
+            try {
+                this.miniGameUserUpdate(user);
+            } catch (Exception e) {
+                log.error("定时器-腾讯小游戏村注册检测异常, id : {}, e : {}", user.getId(), e.getMessage(), e);
+            }
+        }, THREAD_POOL_CALL_BACK_URL_UPDATE)).collect(Collectors.toList());
+        try {
+            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get();
+        } catch (Exception e) {
+            log.error("定时器-腾讯小游戏村注册检测等待所有队列消息消费完成时出现异常: {}", e.getMessage());
+        }
+    }
+
+    private void miniGameUserUpdate(GameTencentMiniGameUser miniGameUser) {
+        //匹配回传URL
+        String callBackUrl = this.getCallBackUrl(miniGameUser.getGameId(),
+                miniGameUser.getWechatOpenid(), miniGameUser.getClickId(), miniGameUser.getRegisterTime(), false);
+        if (Strings.isBlank(callBackUrl)) {
+            return;
+        }
+        //设置回传地址
+        miniGameUser.setCallBackUrl(callBackUrl);
+        //数据修正
+        gameTencentMiniGameUserService.updateById(miniGameUser);
+        //判断是否已经执行回传异常
+        if (Objects.equals(miniGameUser.getBackStatus(), BackStatusEnum.FAILED.getBackStatus())) {
+            //已执行的重新补回传
+            gameTencentMiniGameUserService.userBack(miniGameUser);
+        }
+        //查询相关创角回传是否存在
+        List<GameTencentMiniGameRoleRegister> miniGameRoleRegisterList = gameTencentMiniGameRoleRegisterService.list(
+                new LambdaQueryWrapper<GameTencentMiniGameRoleRegister>()
+                        .eq(GameTencentMiniGameRoleRegister::getGameId, miniGameUser.getGameId())
+                        .eq(GameTencentMiniGameRoleRegister::getWechatAppId, miniGameUser.getWechatAppId())
+                        .eq(GameTencentMiniGameRoleRegister::getWechatOpenid, miniGameUser.getWechatOpenid())
+                        .eq(GameTencentMiniGameRoleRegister::getAdAccountId, miniGameUser.getAdAccountId())
+                        .eq(GameTencentMiniGameRoleRegister::getBackStatus, BackStatusEnum.FAILED.getBackStatus())
+                        .eq(GameTencentMiniGameRoleRegister::getBackType, BackTypeEnum.BACK_API.getBackType()));
+        if (CollectionUtils.isEmpty(miniGameRoleRegisterList)) {
+            return;
+        }
+        //注册回传补充
+        miniGameRoleRegisterList.forEach(miniGameRole -> {
+            try {
+                gameTencentMiniGameRoleRegisterService.roleRegisterBack(miniGameRole);
+            } catch (Exception e) {
+                log.error("定时器-腾讯小游戏村创角补回传异常, id : {}, e : {}", miniGameRole.getId(), e.getMessage(), e);
+            }
+        });
+    }
 }

+ 75 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/task/GameTencentMiniGameTask.java

@@ -0,0 +1,75 @@
+package com.zanxiang.game.back.serve.task;
+
+import com.zanxiang.game.back.serve.service.IGameTencentMiniGameCallbackService;
+import com.zanxiang.game.module.base.ServerInfo;
+import com.zanxiang.game.module.base.pojo.dto.GameDTO;
+import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
+import com.zanxiang.game.module.base.rpc.IGameRpc;
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-10
+ * @description : 腾讯小游戏玩家定时器
+ */
+@Slf4j
+@Component
+public class GameTencentMiniGameTask {
+
+    private static final String CALL_BACK_URL_LOCK_KEY = "game-back:CALLBACK_URL_LOCK";
+
+    @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
+    private IGameRpc gameRpc;
+
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+
+    @Autowired
+    private IGameTencentMiniGameCallbackService gameTencentMiniGameCallbackService;
+
+    /**
+     * 每10分钟执行, 补充玩家信息中的 callBackUrl, 因为腾讯回调存在延迟的情况
+     */
+    @Scheduled(cron = "0 0/10 * * * ?")
+    public void updateMiniGameUserCallBackUrl() {
+        //上锁
+        if (!distributedLockComponent.doLock(CALL_BACK_URL_LOCK_KEY, 0L, 5L, TimeUnit.MINUTES)) {
+            return;
+        }
+        GameDTO gameDTO = gameRpc.getAllGameList().getData();
+        List<GameDTO.GameBean> gameBeanList = Optional.ofNullable(gameDTO)
+                .map(GameDTO::getAllGameList)
+                .orElse(null);
+        if (CollectionUtils.isEmpty(gameBeanList)) {
+            return;
+        }
+        List<Long> gameIdList = gameBeanList.stream()
+                .filter(gameBean -> gameBean.getId() >= 35
+                        && Objects.equals(gameBean.getCategory(), GameCategoryEnum.CATEGORY_WX_APPLET.getId()))
+                .map(GameDTO.GameBean::getId)
+                .collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(gameIdList)) {
+            return;
+        }
+        gameIdList.forEach(gameId -> {
+            try {
+                gameTencentMiniGameCallbackService.delayUpdateMiniGameUserCallBackUrl(gameId, LocalDateTime.now());
+            } catch (Exception e) {
+                log.error("定时器-腾讯小游戏注册callBackUrl定时任务执行异常, gameId L {}, e : {}", gameId, e.getMessage());
+            }
+        });
+    }
+}