|
|
|
@@ -5,14 +5,19 @@ import com.accompany.business.event.room.UserOutRoomEvent;
|
|
|
|
|
import com.accompany.business.message.room.UserOutRoomMessage;
|
|
|
|
|
import com.accompany.business.model.Gift;
|
|
|
|
|
import com.accompany.business.param.UserBackpackParam;
|
|
|
|
|
import com.accompany.business.service.ErBanNetEaseService;
|
|
|
|
|
import com.accompany.business.service.gift.GiftService;
|
|
|
|
|
import com.accompany.business.service.user.UserBackpackService;
|
|
|
|
|
import com.accompany.business.vo.room.RoomFreeGiftUserVo;
|
|
|
|
|
import com.accompany.common.constant.Attach;
|
|
|
|
|
import com.accompany.common.constant.Constant;
|
|
|
|
|
import com.accompany.common.redis.RedisKey;
|
|
|
|
|
import com.accompany.common.status.BusiStatus;
|
|
|
|
|
import com.accompany.common.utils.UUIDUitl;
|
|
|
|
|
import com.accompany.core.exception.ServiceException;
|
|
|
|
|
import com.accompany.core.model.Room;
|
|
|
|
|
import com.accompany.core.service.SysConfService;
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
import lombok.SneakyThrows;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
@@ -23,13 +28,19 @@ import org.springframework.beans.factory.InitializingBean;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
import org.springframework.context.ApplicationListener;
|
|
|
|
|
import org.springframework.context.annotation.Lazy;
|
|
|
|
|
import org.springframework.core.task.TaskExecutor;
|
|
|
|
|
import org.springframework.scheduling.annotation.Async;
|
|
|
|
|
import org.springframework.scheduling.support.CronSequenceGenerator;
|
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
@Component
|
|
|
|
@@ -46,8 +57,15 @@ public class RoomFreeGiftService implements InitializingBean, ApplicationListene
|
|
|
|
|
@Lazy
|
|
|
|
|
@Autowired
|
|
|
|
|
private UserBackpackService userBackpackService;
|
|
|
|
|
@Autowired
|
|
|
|
|
private RoomQueryService roomQueryService;
|
|
|
|
|
@Autowired
|
|
|
|
|
private TaskExecutor bizExecutor;
|
|
|
|
|
@Autowired
|
|
|
|
|
private ErBanNetEaseService erBanNetEaseService;
|
|
|
|
|
|
|
|
|
|
private RMap<String, Long> userInfoMap;
|
|
|
|
|
private RMap<String, Long> timestampMap;
|
|
|
|
|
|
|
|
|
|
public long getUserCurStage(Long uid){
|
|
|
|
|
String curStageKey = getCurStageKey(uid);
|
|
|
|
@@ -58,7 +76,7 @@ public class RoomFreeGiftService implements InitializingBean, ApplicationListene
|
|
|
|
|
RoomFreeGiftUserVo vo = new RoomFreeGiftUserVo();
|
|
|
|
|
|
|
|
|
|
RoomFreeGiftConfigDto config = getConfig();
|
|
|
|
|
if (null == config){
|
|
|
|
|
if (null == config || null == config.getGiftId()){
|
|
|
|
|
return vo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -81,54 +99,56 @@ public class RoomFreeGiftService implements InitializingBean, ApplicationListene
|
|
|
|
|
vo.setGoldPrice(freeGift.getGoldPrice());
|
|
|
|
|
vo.setResetTime(resetTime);
|
|
|
|
|
|
|
|
|
|
String countdownKey = getCountdownKey(uid);
|
|
|
|
|
long totalRemainSecond = userInfoMap.getOrDefault(countdownKey, 0L);
|
|
|
|
|
|
|
|
|
|
String lastTimestampKey = getLastTimestampKey(uid);
|
|
|
|
|
Long inRoomTimestamp = userInfoMap.get(lastTimestampKey);
|
|
|
|
|
// todo 考虑跨周期
|
|
|
|
|
if (null == inRoomTimestamp){
|
|
|
|
|
inRoomTimestamp = now.getTime();
|
|
|
|
|
}
|
|
|
|
|
long thisStageCountdown = (now.getTime() - inRoomTimestamp) / 1000;
|
|
|
|
|
userInfoMap.fastPutAsync(lastTimestampKey, inRoomTimestamp);
|
|
|
|
|
|
|
|
|
|
computeStage(uid, totalRemainSecond + thisStageCountdown, config, freeGift, vo);
|
|
|
|
|
|
|
|
|
|
return vo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void computeStage(Long uid, long remainSecond, RoomFreeGiftConfigDto config, Gift freeGift, RoomFreeGiftUserVo vo) {
|
|
|
|
|
long computeStage = 0L;
|
|
|
|
|
remainSecond -= config.getFirstStageSecond();
|
|
|
|
|
if (remainSecond >= 0L){
|
|
|
|
|
computeStage ++;
|
|
|
|
|
long otherStage = remainSecond / config.getOtherStageSecond();
|
|
|
|
|
long otherStageSecond = remainSecond %= config.getOtherStageSecond();
|
|
|
|
|
if (otherStage > 0L){
|
|
|
|
|
computeStage += Long.min(otherStage, config.getMaxStage()-1L);
|
|
|
|
|
}
|
|
|
|
|
if (otherStageSecond > 0L){
|
|
|
|
|
remainSecond = config.getOtherStageSecond() - otherStageSecond;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
remainSecond = Math.abs(remainSecond);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String curStageKey = getCurStageKey(uid);
|
|
|
|
|
long curStage = userInfoMap.getOrDefault(curStageKey, 0L);
|
|
|
|
|
if (curStage < computeStage){
|
|
|
|
|
long freeGiftNum = computeStage - curStage;
|
|
|
|
|
addGiftToBackpack(uid, freeGift, freeGiftNum);
|
|
|
|
|
|
|
|
|
|
curStage = computeStage;
|
|
|
|
|
userInfoMap.fastPut(curStageKey, curStage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (null != vo){
|
|
|
|
|
if (curStage >= config.getMaxStage()){
|
|
|
|
|
vo.setCurStage(curStage);
|
|
|
|
|
vo.setCurStageSecond(remainSecond);
|
|
|
|
|
vo.setCurStageSecond(0L);
|
|
|
|
|
return vo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long nowTimestamp = now.getTime();
|
|
|
|
|
String finishTimestampKey = getFinishTimestampKey(uid);
|
|
|
|
|
String lastTimestampKey = getLastTimestampKey(uid);
|
|
|
|
|
Long inRoomTimestamp = timestampMap.get(lastTimestampKey);
|
|
|
|
|
//该周期第一次来
|
|
|
|
|
if (null == inRoomTimestamp){
|
|
|
|
|
inRoomTimestamp = nowTimestamp;
|
|
|
|
|
timestampMap.fastPut(lastTimestampKey, inRoomTimestamp);
|
|
|
|
|
timestampMap.fastPut(finishTimestampKey, inRoomTimestamp + config.getFirstStageSecond() * 1000);
|
|
|
|
|
|
|
|
|
|
vo.setCurStage(curStage);
|
|
|
|
|
vo.setCurStageSecond(config.getFirstStageSecond());
|
|
|
|
|
return vo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long finishTimestamp = timestampMap.get(finishTimestampKey);
|
|
|
|
|
if (nowTimestamp >= finishTimestamp){
|
|
|
|
|
inRoomTimestamp = nowTimestamp;
|
|
|
|
|
curStage = userInfoMap.addAndGet(curStageKey, 1L);
|
|
|
|
|
if (curStage >= config.getMaxStage()){
|
|
|
|
|
timestampMap.fastRemove(lastTimestampKey);
|
|
|
|
|
timestampMap.fastRemove(finishTimestampKey);
|
|
|
|
|
} else {
|
|
|
|
|
timestampMap.fastPut(lastTimestampKey, inRoomTimestamp);
|
|
|
|
|
timestampMap.fastPut(finishTimestampKey, inRoomTimestamp + config.getOtherStageSecond() * 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addGiftToBackpack(uid, freeGift, 1);
|
|
|
|
|
|
|
|
|
|
vo.setCurStage(curStage);
|
|
|
|
|
vo.setCurStageSecond(config.getOtherStageSecond());
|
|
|
|
|
return vo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String countdownKey = getCountdownKey(uid);
|
|
|
|
|
long thisStageCountdown = (nowTimestamp - inRoomTimestamp) / 1000;
|
|
|
|
|
userInfoMap.fastPut(countdownKey, thisStageCountdown);
|
|
|
|
|
|
|
|
|
|
vo.setCurStage(curStage);
|
|
|
|
|
vo.setCurStageSecond(curStage == 0L? config.getFirstStageSecond(): config.getOtherStageSecond() - thisStageCountdown);
|
|
|
|
|
|
|
|
|
|
return vo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void addGiftToBackpack(Long uid, Gift freeGift, long freeGiftNum) {
|
|
|
|
@@ -140,6 +160,7 @@ public class RoomFreeGiftService implements InitializingBean, ApplicationListene
|
|
|
|
|
userBackpackParam.setGiftSeq(freeGift.getSeqNo());
|
|
|
|
|
userBackpackService.saveOrUpdateUserBackpack(userBackpackParam);
|
|
|
|
|
// todo 记录和日志
|
|
|
|
|
log.info("[房间免费礼物] {} 获得 {} {}", uid, freeGiftNum, freeGift);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Async
|
|
|
|
@@ -151,27 +172,77 @@ public class RoomFreeGiftService implements InitializingBean, ApplicationListene
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Long roomUid = userOutRoomMessage.getRoomUid();
|
|
|
|
|
//当前离开房间用户uid
|
|
|
|
|
RoomFreeGiftConfigDto config = getConfig();
|
|
|
|
|
if (null == config || null == config.getGiftId()){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Gift freeGift = giftService.getValidGiftById(config.getGiftId());
|
|
|
|
|
if (null == freeGift){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Long uid = userOutRoomMessage.getUid();
|
|
|
|
|
Long outTimestamp = userOutRoomMessage.getOutTimestamp();
|
|
|
|
|
Long remainMillisecond = userOutRoomMessage.getRemainMillisecond();
|
|
|
|
|
Long remainSecond = remainMillisecond / 1000;
|
|
|
|
|
String countdownKey = getCountdownKey(uid);
|
|
|
|
|
long totalRemainSecond = userInfoMap.addAndGet(countdownKey, remainSecond);
|
|
|
|
|
log.info("[房间免费礼物] {} 在 {} 离开房间 {} ,增加 {} 秒, 累计 {} 秒",uid, outTimestamp, roomUid, remainSecond, totalRemainSecond);
|
|
|
|
|
String curStageKey = getCurStageKey(uid);
|
|
|
|
|
long curStage = userInfoMap.getOrDefault(curStageKey, 0L);
|
|
|
|
|
if (curStage >= config.getMaxStage()){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//清理
|
|
|
|
|
String lastTimestampKey = getLastTimestampKey(uid);
|
|
|
|
|
userInfoMap.fastRemove(lastTimestampKey);
|
|
|
|
|
Long lastTimestamp = timestampMap.get(lastTimestampKey);
|
|
|
|
|
String finishTimestampKey = getFinishTimestampKey(uid);
|
|
|
|
|
Long finishTimestamp = timestampMap.get(finishTimestampKey);
|
|
|
|
|
if (null == lastTimestamp || null == finishTimestamp){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// todo 根据curStage和computeStage结算
|
|
|
|
|
Long roomUid = userOutRoomMessage.getRoomUid();
|
|
|
|
|
Long outTimestamp = userOutRoomMessage.getOutTimestamp();
|
|
|
|
|
|
|
|
|
|
if (outTimestamp >= finishTimestamp){
|
|
|
|
|
curStage = userInfoMap.addAndGet(curStageKey, 1L);
|
|
|
|
|
if (curStage >= config.getMaxStage()){
|
|
|
|
|
timestampMap.fastRemove(lastTimestampKey);
|
|
|
|
|
timestampMap.fastRemove(finishTimestampKey);
|
|
|
|
|
} else {
|
|
|
|
|
long inRoomTimestamp = Math.max(outTimestamp, lastTimestamp);
|
|
|
|
|
if (inRoomTimestamp > lastTimestamp){
|
|
|
|
|
timestampMap.fastPut(lastTimestampKey, inRoomTimestamp);
|
|
|
|
|
}
|
|
|
|
|
timestampMap.fastPut(finishTimestampKey, inRoomTimestamp + config.getOtherStageSecond() * 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addGiftToBackpack(uid, freeGift, 1);
|
|
|
|
|
|
|
|
|
|
log.info("[房间免费礼物] {} 在 {} 离开房间 {} ,已上升到阶段 {}", uid, outTimestamp, roomUid, curStage);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String countdownKey = getCountdownKey(uid);
|
|
|
|
|
long thisStageCountdown = (Math.max(outTimestamp,lastTimestamp) - lastTimestamp) / 1000;
|
|
|
|
|
userInfoMap.fastPut(countdownKey, thisStageCountdown);
|
|
|
|
|
|
|
|
|
|
log.info("[房间免费礼物] {} 在 {} 离开房间 {} ,当前阶段 {} 已累计倒计时 {} 秒", uid, outTimestamp, roomUid, curStage, thisStageCountdown);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void resetFreeGift(){
|
|
|
|
|
userBackpackService.clearRoomFreeGift();
|
|
|
|
|
userInfoMap.clear();
|
|
|
|
|
//只清楚finish时间在重置时间前的记录
|
|
|
|
|
long nowTimestamp = System.currentTimeMillis();
|
|
|
|
|
List<Long> needClearUid = timestampMap.entrySet().stream().filter(entry-> entry.getKey().endsWith("finish_timestamp") && entry.getValue() < nowTimestamp)
|
|
|
|
|
.map(entry-> Long.parseLong(entry.getKey().split("_")[0])).collect(Collectors.toList());
|
|
|
|
|
if (!CollectionUtils.isEmpty(needClearUid)){
|
|
|
|
|
List<String> keys = new ArrayList<>();
|
|
|
|
|
for (Long uid: needClearUid){
|
|
|
|
|
keys.add(getLastTimestampKey(uid));
|
|
|
|
|
keys.add(getFinishTimestampKey(uid));
|
|
|
|
|
}
|
|
|
|
|
String[] keyArray = keys.toArray(new String[keys.size()]);
|
|
|
|
|
timestampMap.fastRemove(keyArray);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RoomFreeGiftConfigDto getConfig(){
|
|
|
|
@@ -199,9 +270,51 @@ public class RoomFreeGiftService implements InitializingBean, ApplicationListene
|
|
|
|
|
return String.format("%d_%s", uid, "last_timestamp");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String getFinishTimestampKey(Long uid){
|
|
|
|
|
return String.format("%d_%s", uid, "finish_timestamp");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void afterPropertiesSet() throws Exception {
|
|
|
|
|
userInfoMap = redissonClient.getMap(RedisKey.room_free_gift_user_info.getKey(), LongCodec.INSTANCE);
|
|
|
|
|
timestampMap = redissonClient.getMap(RedisKey.room_free_gift_user_timestamp.getKey(), LongCodec.INSTANCE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void sendRefreshChatRoomMsg() {
|
|
|
|
|
RoomFreeGiftConfigDto config = getConfig();
|
|
|
|
|
if (null == config || null == config.getGiftId()){
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Attach attach = new Attach();
|
|
|
|
|
attach.setFirst(Constant.DefMsgType.roomFreeGift);
|
|
|
|
|
attach.setSecond(Constant.DefMsgType.roomFreeGiftRest);
|
|
|
|
|
sendMessageToAllValidRooms(JSON.toJSONString(attach));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 发送所有有效房间消息
|
|
|
|
|
*
|
|
|
|
|
* @param msg
|
|
|
|
|
*/
|
|
|
|
|
public long sendMessageToAllValidRooms(final String msg) {
|
|
|
|
|
int BATCH_SIZE = 1000;
|
|
|
|
|
long count = this.roomQueryService.countValidRooms();
|
|
|
|
|
long times = count % BATCH_SIZE == 0 ? (count / BATCH_SIZE) : (count / BATCH_SIZE) + 1;
|
|
|
|
|
for (int i = 0; i < times; i++) {
|
|
|
|
|
Integer index = i * BATCH_SIZE;
|
|
|
|
|
List<Room> validRooms = this.roomQueryService.listValidRooms(index, BATCH_SIZE);
|
|
|
|
|
for (Room room : validRooms) {
|
|
|
|
|
bizExecutor.execute(() -> {
|
|
|
|
|
try {
|
|
|
|
|
this.erBanNetEaseService.sendChatRoomMsg(room.getRoomId(), UUIDUitl.get(), room.getUid().toString(), Constant.DefineProtocol.CUSTOM_MESS_DEFINE, msg, null);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("批量发送房间消息失败[room={}, message={}]", JSON.toJSONString(room), msg, e);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log.info("发送所有有效房间消息,房间数:{}", count);
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|