|
|
|
@@ -1,11 +1,13 @@
|
|
|
|
|
package com.tailbet.job;
|
|
|
|
|
|
|
|
|
|
import com.tailbet.model.RoundTask;
|
|
|
|
|
import com.tailbet.model.entity.GameRound;
|
|
|
|
|
import com.tailbet.model.entity.RedPacket;
|
|
|
|
|
import com.tailbet.model.entity.User;
|
|
|
|
|
import com.tailbet.mapper.DrawRecordMapper;
|
|
|
|
|
import com.tailbet.mapper.DigitWhiteMapper;
|
|
|
|
|
import com.tailbet.mapper.GameRoundMapper;
|
|
|
|
|
import com.tailbet.mapper.PendingTaskMapper;
|
|
|
|
|
import com.tailbet.mapper.RedPacketMapper;
|
|
|
|
|
import com.tailbet.mapper.RedPacketRecvMapper;
|
|
|
|
|
import com.tailbet.mapper.SysConfigMapper;
|
|
|
|
@@ -14,6 +16,8 @@ import com.tailbet.model.entity.DigitWhite;
|
|
|
|
|
import com.tailbet.model.entity.DrawRecord;
|
|
|
|
|
import com.tailbet.model.entity.RedPacketRecv;
|
|
|
|
|
import com.tailbet.model.entity.SysConfig;
|
|
|
|
|
import com.tailbet.model.entity.PendingTask;
|
|
|
|
|
import com.tailbet.model.PendingTaskInfo;
|
|
|
|
|
import com.tailbet.openim.OpenIMClient;
|
|
|
|
|
import com.tailbet.service.IGameService;
|
|
|
|
|
import com.tailbet.service.IRedPacketService;
|
|
|
|
@@ -46,6 +50,7 @@ public class GameJob {
|
|
|
|
|
private final SysConfigMapper sysConfigMapper;
|
|
|
|
|
private final UserMapper userMapper;
|
|
|
|
|
private final DigitWhiteMapper digitWhiteMapper;
|
|
|
|
|
private final PendingTaskMapper pendingTaskMapper;
|
|
|
|
|
private final IGameService gameService;
|
|
|
|
|
private final IRedPacketService redPacketService;
|
|
|
|
|
private final IFakeUserService fakeUserService;
|
|
|
|
@@ -58,24 +63,106 @@ public class GameJob {
|
|
|
|
|
private final Map<String, String> configCache = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
// 延迟任务队列
|
|
|
|
|
private final Map<String, PendingTask> pendingTasks = new ConcurrentHashMap<>();
|
|
|
|
|
private final Map<String, PendingTaskInfo> pendingTasks = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
// 任务ID生成器
|
|
|
|
|
// 任务ID生成器 (格式: {type}_{groupId}_{自增序号})
|
|
|
|
|
private java.util.concurrent.atomic.AtomicLong taskIdGenerator = new java.util.concurrent.atomic.AtomicLong(1);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 启动时加载配置缓存
|
|
|
|
|
* 启动时加载配置缓存并恢复内存状态
|
|
|
|
|
*/
|
|
|
|
|
@jakarta.annotation.PostConstruct
|
|
|
|
|
public void loadConfig() {
|
|
|
|
|
try {
|
|
|
|
|
// 加载配置缓存
|
|
|
|
|
List<SysConfig> configs = sysConfigMapper.selectList(null);
|
|
|
|
|
for (SysConfig config : configs) {
|
|
|
|
|
configCache.put(config.getCfgKey(), config.getCfgValue());
|
|
|
|
|
}
|
|
|
|
|
log.info("配置缓存加载完成,共 {} 条配置", configs.size());
|
|
|
|
|
|
|
|
|
|
// 恢复进行中的局状态
|
|
|
|
|
recoverRoundTasks();
|
|
|
|
|
|
|
|
|
|
// 恢复延迟任务队列
|
|
|
|
|
recoverPendingTasks();
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("配置缓存加载失败: {}", e.getMessage());
|
|
|
|
|
log.error("启动初始化失败: {}", e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 从数据库恢复进行中的局状态
|
|
|
|
|
*/
|
|
|
|
|
private void recoverRoundTasks() {
|
|
|
|
|
try {
|
|
|
|
|
List<GameRound> ongoingRounds = gameRoundMapper.selectList(
|
|
|
|
|
new LambdaQueryWrapper<GameRound>()
|
|
|
|
|
.eq(GameRound::getStatus, 0));
|
|
|
|
|
|
|
|
|
|
if (ongoingRounds.isEmpty()) {
|
|
|
|
|
log.info("无进行中的局,无需恢复");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int bettingInterval = getConfigInt("betting_interval", 60);
|
|
|
|
|
|
|
|
|
|
for (GameRound round : ongoingRounds) {
|
|
|
|
|
RoundTask task = new RoundTask();
|
|
|
|
|
task.setRoundId(round.getId());
|
|
|
|
|
task.setGroupId(round.getGroupId());
|
|
|
|
|
|
|
|
|
|
// 优先使用数据库中的endBetTime,否则根据startTime计算
|
|
|
|
|
if (round.getEndBetTime() != null) {
|
|
|
|
|
task.setEndBetTime(round.getEndBetTime());
|
|
|
|
|
} else if (round.getStartTime() != null) {
|
|
|
|
|
task.setEndBetTime(round.getStartTime().plusSeconds(bettingInterval));
|
|
|
|
|
} else {
|
|
|
|
|
// 兜底:使用配置的下注时长
|
|
|
|
|
task.setEndBetTime(LocalDateTime.now().plusSeconds(bettingInterval));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
roundTasks.put(round.getId(), task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.info("局状态恢复完成,共恢复 {} 个进行中的局", ongoingRounds.size());
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("恢复局状态失败: {}", e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 从数据库恢复延迟任务队列
|
|
|
|
|
*/
|
|
|
|
|
private void recoverPendingTasks() {
|
|
|
|
|
try {
|
|
|
|
|
List<PendingTask> dbTasks = pendingTaskMapper.selectList(
|
|
|
|
|
new LambdaQueryWrapper<PendingTask>()
|
|
|
|
|
.gt(PendingTask::getExecuteTime, LocalDateTime.now()));
|
|
|
|
|
|
|
|
|
|
if (dbTasks == null || dbTasks.isEmpty()) {
|
|
|
|
|
log.info("无待执行的延迟任务,无需恢复");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (PendingTask dbTask : dbTasks) {
|
|
|
|
|
if (dbTask.getExecuteTime() == null || !dbTask.getExecuteTime().isAfter(LocalDateTime.now())) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
PendingTaskInfo info = new PendingTaskInfo();
|
|
|
|
|
info.setTaskId(dbTask.getTaskId());
|
|
|
|
|
info.setType(dbTask.getType());
|
|
|
|
|
info.setRoundId(dbTask.getRoundId());
|
|
|
|
|
info.setGroupId(dbTask.getGroupId());
|
|
|
|
|
info.setDigit(dbTask.getDigit());
|
|
|
|
|
info.setExecuteTime(dbTask.getExecuteTime());
|
|
|
|
|
pendingTasks.put(info.getTaskId(), info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.info("延迟任务恢复完成,共恢复 {} 个待执行任务", pendingTasks.size());
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("恢复延迟任务失败: {}", e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -186,7 +273,7 @@ public class GameJob {
|
|
|
|
|
for (GameRound round : ongoingRounds) {
|
|
|
|
|
// 检查是否超过接注时间
|
|
|
|
|
RoundTask task = roundTasks.get(round.getId());
|
|
|
|
|
if (task != null && task.endBetTime.isBefore(LocalDateTime.now())) {
|
|
|
|
|
if (task != null && task.getEndBetTime().isBefore(LocalDateTime.now())) {
|
|
|
|
|
// 自动结束接注
|
|
|
|
|
try {
|
|
|
|
|
gameService.endBet(round.getGroupId(), 0L); // 0L表示系统自动触发
|
|
|
|
@@ -212,14 +299,17 @@ public class GameJob {
|
|
|
|
|
* 安排开始发红包
|
|
|
|
|
*/
|
|
|
|
|
public String scheduleStartRp(Long roundId, Long groupId, int delaySeconds) {
|
|
|
|
|
String taskId = "start_rp_" + taskIdGenerator.getAndIncrement();
|
|
|
|
|
PendingTask task = new PendingTask();
|
|
|
|
|
String taskId = "start_rp_" + groupId + "_" + taskIdGenerator.getAndIncrement();
|
|
|
|
|
PendingTaskInfo task = new PendingTaskInfo();
|
|
|
|
|
task.setTaskId(taskId);
|
|
|
|
|
task.setType("start_rp");
|
|
|
|
|
task.setRoundId(roundId);
|
|
|
|
|
task.setGroupId(groupId);
|
|
|
|
|
task.setExecuteTime(LocalDateTime.now().plusSeconds(delaySeconds));
|
|
|
|
|
LocalDateTime executeTime = LocalDateTime.now().plusSeconds(delaySeconds);
|
|
|
|
|
task.setExecuteTime(executeTime);
|
|
|
|
|
pendingTasks.put(taskId, task);
|
|
|
|
|
// 持久化到数据库
|
|
|
|
|
saveTaskToDb(taskId, "start_rp", roundId, groupId, null, executeTime);
|
|
|
|
|
log.info("安排{}秒后开始发红包: roundId={}", delaySeconds, roundId);
|
|
|
|
|
return taskId;
|
|
|
|
|
}
|
|
|
|
@@ -228,15 +318,18 @@ public class GameJob {
|
|
|
|
|
* 安排自动结算
|
|
|
|
|
*/
|
|
|
|
|
public String scheduleSettle(Long roundId, Long groupId, int digit, int delaySeconds) {
|
|
|
|
|
String taskId = "settle_" + taskIdGenerator.getAndIncrement();
|
|
|
|
|
PendingTask task = new PendingTask();
|
|
|
|
|
String taskId = "settle_" + groupId + "_" + taskIdGenerator.getAndIncrement();
|
|
|
|
|
PendingTaskInfo task = new PendingTaskInfo();
|
|
|
|
|
task.setTaskId(taskId);
|
|
|
|
|
task.setType("settle");
|
|
|
|
|
task.setRoundId(roundId);
|
|
|
|
|
task.setGroupId(groupId);
|
|
|
|
|
task.setDigit(digit);
|
|
|
|
|
task.setExecuteTime(LocalDateTime.now().plusSeconds(delaySeconds));
|
|
|
|
|
LocalDateTime executeTime = LocalDateTime.now().plusSeconds(delaySeconds);
|
|
|
|
|
task.setExecuteTime(executeTime);
|
|
|
|
|
pendingTasks.put(taskId, task);
|
|
|
|
|
// 持久化到数据库
|
|
|
|
|
saveTaskToDb(taskId, "settle", roundId, groupId, digit, executeTime);
|
|
|
|
|
log.info("安排{}秒后结算: taskId={}, roundId={}, digit={}", delaySeconds, taskId, roundId, digit);
|
|
|
|
|
return taskId;
|
|
|
|
|
}
|
|
|
|
@@ -245,13 +338,16 @@ public class GameJob {
|
|
|
|
|
* 安排自动下一期
|
|
|
|
|
*/
|
|
|
|
|
public String scheduleAutoNextTask(Long groupId, int delaySeconds) {
|
|
|
|
|
String taskId = "auto_next_" + taskIdGenerator.getAndIncrement();
|
|
|
|
|
PendingTask task = new PendingTask();
|
|
|
|
|
String taskId = "auto_next_" + groupId + "_" + taskIdGenerator.getAndIncrement();
|
|
|
|
|
PendingTaskInfo task = new PendingTaskInfo();
|
|
|
|
|
task.setTaskId(taskId);
|
|
|
|
|
task.setType("auto_next");
|
|
|
|
|
task.setGroupId(groupId);
|
|
|
|
|
task.setExecuteTime(LocalDateTime.now().plusSeconds(delaySeconds));
|
|
|
|
|
LocalDateTime executeTime = LocalDateTime.now().plusSeconds(delaySeconds);
|
|
|
|
|
task.setExecuteTime(executeTime);
|
|
|
|
|
pendingTasks.put(taskId, task);
|
|
|
|
|
// 持久化到数据库
|
|
|
|
|
saveTaskToDb(taskId, "auto_next", null, groupId, null, executeTime);
|
|
|
|
|
log.info("安排{}秒后自动开始下一期: groupId={}", delaySeconds, groupId);
|
|
|
|
|
return taskId;
|
|
|
|
|
}
|
|
|
|
@@ -260,26 +356,60 @@ public class GameJob {
|
|
|
|
|
* 安排机器人发包
|
|
|
|
|
*/
|
|
|
|
|
public String scheduleBotSendRp(Long roundId, Long groupId, int delaySeconds) {
|
|
|
|
|
String taskId = "bot_send_rp_" + taskIdGenerator.getAndIncrement();
|
|
|
|
|
PendingTask task = new PendingTask();
|
|
|
|
|
String taskId = "bot_send_rp_" + groupId + "_" + taskIdGenerator.getAndIncrement();
|
|
|
|
|
PendingTaskInfo task = new PendingTaskInfo();
|
|
|
|
|
task.setTaskId(taskId);
|
|
|
|
|
task.setType("bot_send_rp");
|
|
|
|
|
task.setRoundId(roundId);
|
|
|
|
|
task.setGroupId(groupId);
|
|
|
|
|
task.setExecuteTime(LocalDateTime.now().plusSeconds(delaySeconds));
|
|
|
|
|
LocalDateTime executeTime = LocalDateTime.now().plusSeconds(delaySeconds);
|
|
|
|
|
task.setExecuteTime(executeTime);
|
|
|
|
|
pendingTasks.put(taskId, task);
|
|
|
|
|
// 持久化到数据库
|
|
|
|
|
saveTaskToDb(taskId, "bot_send_rp", roundId, groupId, null, executeTime);
|
|
|
|
|
log.info("安排{}秒后机器人发包: roundId={}", delaySeconds, roundId);
|
|
|
|
|
return taskId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 保存任务到数据库
|
|
|
|
|
*/
|
|
|
|
|
private void saveTaskToDb(String taskId, String type, Long roundId, Long groupId, Integer digit, LocalDateTime executeTime) {
|
|
|
|
|
try {
|
|
|
|
|
PendingTask dbTask = new PendingTask();
|
|
|
|
|
dbTask.setTaskId(taskId);
|
|
|
|
|
dbTask.setType(type);
|
|
|
|
|
dbTask.setRoundId(roundId);
|
|
|
|
|
dbTask.setGroupId(groupId);
|
|
|
|
|
dbTask.setDigit(digit);
|
|
|
|
|
dbTask.setExecuteTime(executeTime);
|
|
|
|
|
dbTask.setCreateTime(LocalDateTime.now());
|
|
|
|
|
pendingTaskMapper.insert(dbTask);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("保存任务到数据库失败: taskId={}, error={}", taskId, e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 从数据库删除任务
|
|
|
|
|
*/
|
|
|
|
|
private void deleteTaskFromDb(String taskId) {
|
|
|
|
|
try {
|
|
|
|
|
pendingTaskMapper.delete(new LambdaQueryWrapper<PendingTask>()
|
|
|
|
|
.eq(PendingTask::getTaskId, taskId));
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("从数据库删除任务失败: taskId={}, error={}", taskId, e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 开始游戏后安排定时器
|
|
|
|
|
*/
|
|
|
|
|
public void onGameStart(Long roundId, Long groupId, int intervalSeconds) {
|
|
|
|
|
RoundTask task = new RoundTask();
|
|
|
|
|
task.roundId = roundId;
|
|
|
|
|
task.groupId = groupId;
|
|
|
|
|
task.endBetTime = LocalDateTime.now().plusSeconds(intervalSeconds);
|
|
|
|
|
task.setRoundId(roundId);
|
|
|
|
|
task.setGroupId(groupId);
|
|
|
|
|
task.setEndBetTime(LocalDateTime.now().plusSeconds(intervalSeconds));
|
|
|
|
|
roundTasks.put(roundId, task);
|
|
|
|
|
|
|
|
|
|
// 广播开始下注
|
|
|
|
@@ -475,75 +605,6 @@ public class GameJob {
|
|
|
|
|
return sb.toString().trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 局任务信息
|
|
|
|
|
*/
|
|
|
|
|
private static class RoundTask {
|
|
|
|
|
Long roundId;
|
|
|
|
|
Long groupId;
|
|
|
|
|
LocalDateTime endBetTime;
|
|
|
|
|
LocalDateTime startRpTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 延迟任务信息
|
|
|
|
|
*/
|
|
|
|
|
private static class PendingTask {
|
|
|
|
|
private String taskId;
|
|
|
|
|
private String type;
|
|
|
|
|
private Long roundId;
|
|
|
|
|
private Long groupId;
|
|
|
|
|
private Integer digit;
|
|
|
|
|
private LocalDateTime executeTime;
|
|
|
|
|
|
|
|
|
|
public String getTaskId() {
|
|
|
|
|
return taskId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setTaskId(String taskId) {
|
|
|
|
|
this.taskId = taskId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getType() {
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setType(String type) {
|
|
|
|
|
this.type = type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Long getRoundId() {
|
|
|
|
|
return roundId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setRoundId(Long roundId) {
|
|
|
|
|
this.roundId = roundId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Long getGroupId() {
|
|
|
|
|
return groupId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setGroupId(Long groupId) {
|
|
|
|
|
this.groupId = groupId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Integer getDigit() {
|
|
|
|
|
return digit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setDigit(Integer digit) {
|
|
|
|
|
this.digit = digit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public LocalDateTime getExecuteTime() {
|
|
|
|
|
return executeTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setExecuteTime(LocalDateTime executeTime) {
|
|
|
|
|
this.executeTime = executeTime;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理延迟任务队列(每秒执行)
|
|
|
|
@@ -552,9 +613,14 @@ public class GameJob {
|
|
|
|
|
public void processPendingTasks() {
|
|
|
|
|
LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
pendingTasks.entrySet().removeIf(entry -> {
|
|
|
|
|
PendingTask task = entry.getValue();
|
|
|
|
|
PendingTaskInfo task = entry.getValue();
|
|
|
|
|
if (task.getExecuteTime() == null) {
|
|
|
|
|
deleteTaskFromDb(task.getTaskId());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (task.getExecuteTime().isBefore(now) || task.getExecuteTime().isEqual(now)) {
|
|
|
|
|
executeTask(task);
|
|
|
|
|
deleteTaskFromDb(task.getTaskId());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
@@ -564,7 +630,7 @@ public class GameJob {
|
|
|
|
|
/**
|
|
|
|
|
* 执行延迟任务
|
|
|
|
|
*/
|
|
|
|
|
private void executeTask(PendingTask task) {
|
|
|
|
|
private void executeTask(PendingTaskInfo task) {
|
|
|
|
|
try {
|
|
|
|
|
switch (task.getType()) {
|
|
|
|
|
case "settle":
|
|
|
|
|