幸运25-大R和后台赠送
This commit is contained in:
@@ -1451,7 +1451,7 @@ public enum RedisKey {
|
|||||||
lucky_25_robot_push_msg,
|
lucky_25_robot_push_msg,
|
||||||
lucky_25_status, // 礼物消息的状态
|
lucky_25_status, // 礼物消息的状态
|
||||||
lock_lucky_25_message, // 消费送礼物消息锁
|
lock_lucky_25_message, // 消费送礼物消息锁
|
||||||
lucky_25_user_10w_stat, // 消费送礼物消息锁
|
lucky_25_high_recharge_pool,
|
||||||
;
|
;
|
||||||
|
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
|
@@ -24,6 +24,7 @@ public enum Lucky25PoolTypeEnum {
|
|||||||
BLACK_POOL(3, "黑名单奖池"),
|
BLACK_POOL(3, "黑名单奖池"),
|
||||||
HIGH_POOL(4, "保底奖池"),
|
HIGH_POOL(4, "保底奖池"),
|
||||||
LOW_POOL(5, "衰减奖池"),
|
LOW_POOL(5, "衰减奖池"),
|
||||||
|
HIGH_INPUT_POOL(6, "大R奖池"),
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -12,23 +12,18 @@ public class Lucky25GiftConfig {
|
|||||||
private BigDecimal platformRatio;
|
private BigDecimal platformRatio;
|
||||||
private BigDecimal receiverRatio;
|
private BigDecimal receiverRatio;
|
||||||
//n
|
//n
|
||||||
private BigDecimal productionRatio;
|
private BigDecimal productionRatio_N;
|
||||||
|
|
||||||
private Map<Integer, Lucky25GiftConfig> ratioPartitionMap;
|
private Map<Integer, Lucky25GiftConfig> ratioPartitionMap;
|
||||||
|
|
||||||
private Long highInput_A;
|
|
||||||
private BigDecimal highInputExpect_D;
|
|
||||||
|
|
||||||
private Long preJudgeValue_H;
|
|
||||||
private BigDecimal totalInput_J;
|
|
||||||
private BigDecimal totalInputOffset_K1;
|
|
||||||
private BigDecimal totalInputOffset_K2;
|
|
||||||
|
|
||||||
private Integer poolSize = 500;
|
private Integer poolSize = 500;
|
||||||
private Integer newUserPoolCount = 0;
|
private Integer newUserPoolCount = 0;
|
||||||
|
|
||||||
|
private BigDecimal todayInput;
|
||||||
private BigDecimal todayProductionRatio;
|
private BigDecimal todayProductionRatio;
|
||||||
|
|
||||||
|
private Long highRechargeThreshold_M;
|
||||||
|
|
||||||
private Integer specialTipMulti;
|
private Integer specialTipMulti;
|
||||||
|
|
||||||
private Long allRoomChatToastValue;
|
private Long allRoomChatToastValue;
|
||||||
@@ -42,8 +37,6 @@ public class Lucky25GiftConfig {
|
|||||||
private Map<Long, BigDecimal> whiteUidProductionRatioMap;
|
private Map<Long, BigDecimal> whiteUidProductionRatioMap;
|
||||||
private List<Long> blackUidList;
|
private List<Long> blackUidList;
|
||||||
|
|
||||||
private String diamondIcon;
|
|
||||||
|
|
||||||
public Lucky25GiftConfig getRatioByPartitionId(Integer partitionId){
|
public Lucky25GiftConfig getRatioByPartitionId(Integer partitionId){
|
||||||
return ratioPartitionMap.getOrDefault(partitionId, this);
|
return ratioPartitionMap.getOrDefault(partitionId, this);
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,21 @@
|
|||||||
package com.accompany.business.dto.lucky;
|
package com.accompany.business.dto.lucky;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class Lucky25Result extends Lucky24Result {
|
public class Lucky25Result extends Lucky24Result {
|
||||||
|
|
||||||
|
private Long receiverUid;
|
||||||
|
|
||||||
public Lucky25Result(Integer poolId, Long input, long output, Boolean isSupplement) {
|
public Lucky25Result(Integer poolId, Long input, long output, Boolean isSupplement) {
|
||||||
super(poolId, input, output, isSupplement);
|
super(poolId, input, output, isSupplement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Lucky25Result(Integer poolId, Long receiverUid, Long input, long output, Boolean isSupplement) {
|
||||||
|
super(poolId, input, output, isSupplement);
|
||||||
|
this.receiverUid = receiverUid;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,156 @@
|
|||||||
|
package com.accompany.business.service.gift;
|
||||||
|
|
||||||
|
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
||||||
|
import com.accompany.business.dto.lucky.Lucky25Result;
|
||||||
|
import com.accompany.business.model.Gift;
|
||||||
|
import com.accompany.business.service.lucky.*;
|
||||||
|
import com.accompany.core.model.Room;
|
||||||
|
import com.accompany.sharding.model.Lucky25Record;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RMap;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class Lucky25DrawService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Lucky25StockService stockService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25UserMetaService userMetaService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25PoolService poolService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25HighRechargePoolService highRechargePoolService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25RecordService recordService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25SettlementService settlementService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25RobotMsgService robotMsgService;
|
||||||
|
|
||||||
|
public List<Lucky25Record> draw(Lucky25GiftConfig config, Long senderUid, int partitionId,
|
||||||
|
Gift gift, int everyGiftNum, long everyoneGoldNum,
|
||||||
|
List<Long> receiverList, Room room, Date sendGiftTime) {
|
||||||
|
List<Lucky25Result> resultList = new ArrayList<>();
|
||||||
|
|
||||||
|
// 大R
|
||||||
|
long totalGoldNum = everyoneGoldNum * receiverList.size();
|
||||||
|
RMap<String, Number> userMetaMap = userMetaService.getUserMeta(senderUid);
|
||||||
|
long afterTotalInput = userMetaMap.addAndGet(Lucky25UserMetaService.INPUT_KEY, totalGoldNum).longValue();
|
||||||
|
|
||||||
|
Lucky25Result highRechargeResult = drawHighRechargeUserPool(config, senderUid, partitionId,
|
||||||
|
totalGoldNum, afterTotalInput);
|
||||||
|
if (null != highRechargeResult){
|
||||||
|
Long receiver = receiverList.remove(0);
|
||||||
|
highRechargeResult.setReceiverUid(receiver);
|
||||||
|
//todo log
|
||||||
|
resultList.add(highRechargeResult);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(receiverList)){
|
||||||
|
return resultList.stream().map(drawResult->
|
||||||
|
updateMeta(config, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, room, sendGiftTime, drawResult))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// admin 1000
|
||||||
|
|
||||||
|
int adminSuperNum = userMetaMap.getOrDefault(Lucky25UserMetaService.ADMIN_1000_NUM_KEY, 0).intValue();
|
||||||
|
if (adminSuperNum > 0){
|
||||||
|
int trySuperNum = Math.min(adminSuperNum, receiverList.size());
|
||||||
|
int afterSuperNum = userMetaService.subAdminTicketNum(senderUid, trySuperNum);
|
||||||
|
for (int i = 0; i < afterSuperNum; i++) {
|
||||||
|
Long receiver = receiverList.remove(0);
|
||||||
|
//todo log
|
||||||
|
Lucky25Result adminSuperResult = new Lucky25Result(null, receiver, everyoneGoldNum, 1000L, true);
|
||||||
|
resultList.add(adminSuperResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(receiverList)){
|
||||||
|
return resultList.stream().map(drawResult->
|
||||||
|
updateMeta(config, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, room, sendGiftTime, drawResult))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo 比较
|
||||||
|
|
||||||
|
|
||||||
|
// todo 原数组
|
||||||
|
|
||||||
|
|
||||||
|
return receiverList.parallelStream()
|
||||||
|
.map(receiverUid-> drawMultiple(config, senderUid, partitionId, gift, everyGiftNum, receiverUid, everyoneGoldNum, room, sendGiftTime))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Lucky25Result drawHighRechargeUserPool(Lucky25GiftConfig config, long uid, int partitionId, long totalGoldNum, long afterInput) {
|
||||||
|
Lucky25GiftConfig partitionConfig = config.getRatioByPartitionId(partitionId);
|
||||||
|
if (null == partitionConfig || null == partitionConfig.getHighRechargeThreshold_M()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
long beforeInput = afterInput - totalGoldNum;
|
||||||
|
long beforeThreshold = beforeInput / partitionConfig.getHighRechargeThreshold_M();
|
||||||
|
long afterThreshold = afterInput / partitionConfig.getHighRechargeThreshold_M();
|
||||||
|
if (beforeThreshold >= afterThreshold){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return highRechargePoolService.drawMultipleFromPool(config, uid, partitionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Lucky25Record drawMultiple(Lucky25GiftConfig config, long senderUid, int partitionId,
|
||||||
|
Gift gift, int giftNum, long receiverUid, long everyoneGoldNum, Room room, Date sendGiftTime) {
|
||||||
|
Lucky25Result drawResult = poolService.drawMultipleFromPool(config, senderUid, partitionId);
|
||||||
|
drawResult.setReceiverUid(receiverUid);
|
||||||
|
return updateMeta(config, senderUid, partitionId, gift, giftNum, everyoneGoldNum, room, sendGiftTime, drawResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Lucky25Record updateMeta(Lucky25GiftConfig config, long senderUid, int partitionId,
|
||||||
|
Gift gift, int giftNum, long everyoneGoldNum, Room room, Date sendGiftTime,
|
||||||
|
Lucky25Result drawResult){
|
||||||
|
long receiverUid = drawResult.getReceiverUid();
|
||||||
|
long drawMultiple = drawResult.getOutput();
|
||||||
|
long afterMultiple = drawMultiple;
|
||||||
|
// 平台库存
|
||||||
|
if (afterMultiple > 0L){
|
||||||
|
BigDecimal preWinGoldNum = BigDecimal.valueOf(afterMultiple * everyoneGoldNum);
|
||||||
|
if (!judgeStock(partitionId, preWinGoldNum, senderUid, receiverUid)){
|
||||||
|
afterMultiple = 0L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long winGoldNum = afterMultiple * everyoneGoldNum;
|
||||||
|
userMetaService.updateUserMeta(senderUid, partitionId, everyoneGoldNum, winGoldNum);
|
||||||
|
|
||||||
|
if (winGoldNum > 0L){
|
||||||
|
settlementService.syncSendReward(config, senderUid, room, gift, winGoldNum, afterMultiple);
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordService.buildRecord(senderUid, partitionId, gift, giftNum, null != room? room.getUid(): null,
|
||||||
|
receiverUid, drawResult.getPoolId(), Boolean.TRUE.equals(drawResult.getIsSupplement()),
|
||||||
|
drawMultiple, afterMultiple, sendGiftTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean judgeStock(Integer partitionId, BigDecimal winGoldNum, Long senderUid, Long receiverUid){
|
||||||
|
BigDecimal afterStock = stockService.subStock(partitionId, winGoldNum);
|
||||||
|
boolean enough = afterStock.compareTo(BigDecimal.ZERO) >= 0;
|
||||||
|
if (!enough){
|
||||||
|
log.info("[lucky25] drawMultiple sender {} receiver {} 产出大于库存 winGoldNum {} afterStock {}",
|
||||||
|
senderUid, receiverUid, winGoldNum, afterStock);
|
||||||
|
afterStock = stockService.addStock(partitionId, winGoldNum);
|
||||||
|
robotMsgService.pushStockNotEnough(partitionId, afterStock);
|
||||||
|
}
|
||||||
|
return enough;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,36 +1,23 @@
|
|||||||
package com.accompany.business.service.gift;
|
package com.accompany.business.service.gift;
|
||||||
|
|
||||||
import com.accompany.business.dto.lucky.*;
|
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
||||||
import com.accompany.business.message.Lucky24Message;
|
import com.accompany.business.dto.lucky.SuperLuckyGiftIncomeAllot;
|
||||||
import com.accompany.business.message.Lucky25Message;
|
|
||||||
import com.accompany.business.model.Gift;
|
import com.accompany.business.model.Gift;
|
||||||
import com.accompany.business.service.lucky.*;
|
import com.accompany.business.service.lucky.*;
|
||||||
import com.accompany.business.service.mq.RocketMQService;
|
|
||||||
import com.accompany.common.constant.Constant;
|
import com.accompany.common.constant.Constant;
|
||||||
import com.accompany.common.redis.RedisKey;
|
|
||||||
import com.accompany.common.status.BusiStatus;
|
import com.accompany.common.status.BusiStatus;
|
||||||
import com.accompany.common.utils.RandomUtil;
|
|
||||||
import com.accompany.core.exception.ServiceException;
|
import com.accompany.core.exception.ServiceException;
|
||||||
import com.accompany.core.model.Room;
|
import com.accompany.core.model.Room;
|
||||||
import com.accompany.core.service.SysConfService;
|
import com.accompany.core.service.SysConfService;
|
||||||
import com.accompany.core.service.common.JedisService;
|
|
||||||
import com.accompany.sharding.model.Lucky25Record;
|
import com.accompany.sharding.model.Lucky25Record;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.redisson.api.RMap;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -41,21 +28,11 @@ public class Lucky25GiftSendService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private Lucky25StockService stockService;
|
private Lucky25StockService stockService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private Lucky25UserMetaService userMetaService;
|
private Lucky25DrawService drawService;
|
||||||
@Autowired
|
|
||||||
private Lucky25PoolService poolService;
|
|
||||||
@Autowired
|
|
||||||
private Lucky25RecordService recordService;
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private Lucky25IncomeAllotService incomeAllotService;
|
private Lucky25IncomeAllotService incomeAllotService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private Lucky25SettlementService settlementService;
|
private Lucky25MqService mqService;
|
||||||
@Autowired
|
|
||||||
private Lucky25RobotMsgService robotMsgService;
|
|
||||||
@Autowired
|
|
||||||
private RocketMQService rocketMQService;
|
|
||||||
@Autowired
|
|
||||||
private JedisService jedisService;
|
|
||||||
|
|
||||||
public void draw(long senderUid, Integer partitionId, Room room, List<Long> receiverList,
|
public void draw(long senderUid, Integer partitionId, Room room, List<Long> receiverList,
|
||||||
Gift gift, int everyGiftNum, Date sendGiftTime) {
|
Gift gift, int everyGiftNum, Date sendGiftTime) {
|
||||||
@@ -63,190 +40,18 @@ public class Lucky25GiftSendService {
|
|||||||
long everyoneGoldNum = everyGiftNum * gift.getGoldPrice();
|
long everyoneGoldNum = everyGiftNum * gift.getGoldPrice();
|
||||||
|
|
||||||
Lucky25GiftConfig config = getConfig();
|
Lucky25GiftConfig config = getConfig();
|
||||||
Lucky25GiftConfig partitionConfig = config.getRatioByPartitionId(partitionId);
|
SuperLuckyGiftIncomeAllot incomeAllot = incomeAllotService.calculate(config, partitionId, gift, everyGiftNum, receiverList);
|
||||||
SuperLuckyGiftIncomeAllot incomeAllot = incomeAllotService.calculate(partitionConfig, gift, everyGiftNum, receiverList);
|
|
||||||
|
|
||||||
// 增加库存
|
// 增加库存
|
||||||
BigDecimal afterStock = stockService.addStock(partitionId, incomeAllot.getRemainValue());
|
BigDecimal afterStock = stockService.addStock(partitionId, incomeAllot.getRemainValue());
|
||||||
log.info("[lucky25] uid {}, partitionId {}, addStockGoldNum {}, afterStock {}",
|
log.info("[lucky25] uid {}, partitionId {}, addStockGoldNum {}, afterStock {}",
|
||||||
senderUid, partitionId, incomeAllot.getRemainValue(), afterStock);
|
senderUid, partitionId, incomeAllot.getRemainValue(), afterStock);
|
||||||
|
|
||||||
Map<Long, Lucky25Record> recordMap = draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverList, room, sendGiftTime);
|
List<Lucky25Record> recordList = drawService.draw(config, senderUid, partitionId,
|
||||||
log.info("[lucky25] uid {}, totalWinGoldNum {}", senderUid, JSON.toJSONString(recordMap));
|
gift, everyGiftNum, everyoneGoldNum, receiverList, room, sendGiftTime);
|
||||||
|
log.info("[lucky25] uid {}, totalWinGoldNum {}", senderUid, JSON.toJSONString(recordList));
|
||||||
|
|
||||||
sendMq(recordMap);
|
mqService.sendMq(recordList);
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Long, Lucky25Record> draw(Lucky25GiftConfig config, Lucky25GiftConfig partitionConfig, Long senderUid, int partitionId,
|
|
||||||
Gift gift, int everyGiftNum, long everyoneGoldNum,
|
|
||||||
List<Long> receiverList, Room room, Date sendGiftTime) {
|
|
||||||
if (everyoneGoldNum < partitionConfig.getHighInput_A()
|
|
||||||
|| (!CollectionUtils.isEmpty(config.getBlackUidList()) && config.getBlackUidList().contains(senderUid))){
|
|
||||||
log.error("[lucky25] uid {} totalInput {} configHighInput {} 原", senderUid, everyoneGoldNum, partitionConfig.getHighInput_A());
|
|
||||||
return receiverList.parallelStream()
|
|
||||||
.collect(Collectors.toMap(receiverUid-> receiverUid,
|
|
||||||
receiverUid-> drawMultiple(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, receiverUid, everyoneGoldNum, room, sendGiftTime, null)));
|
|
||||||
}
|
|
||||||
|
|
||||||
BigDecimal totalInput_A = BigDecimal.valueOf(everyoneGoldNum);
|
|
||||||
BigDecimal historyInput = BigDecimal.ZERO;
|
|
||||||
BigDecimal historyOutput = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
RMap<String, Number> userStatCacheMap = userMetaService.getUser10wStat(senderUid);
|
|
||||||
Map<String, Number> userStatMap = userStatCacheMap.readAllMap();
|
|
||||||
if (userStatMap.isEmpty()){
|
|
||||||
List<Lucky25Result> historyResult = userMetaService.getUserLast10wHistory(senderUid);
|
|
||||||
historyInput = BigDecimal.valueOf(historyResult.stream().mapToLong(Lucky25Result::getInput).sum());
|
|
||||||
historyOutput = BigDecimal.valueOf(historyResult.stream().mapToLong(Lucky25Result::getOutput).sum());
|
|
||||||
|
|
||||||
userStatCacheMap.fastPut(Lucky25UserMetaService.INPUT_KEY, historyInput);
|
|
||||||
userStatCacheMap.fastPut(Lucky25UserMetaService.OUTPUT_KEY, historyOutput);
|
|
||||||
userStatCacheMap.expire(Duration.of(10, ChronoUnit.SECONDS));
|
|
||||||
} else {
|
|
||||||
historyInput = BigDecimal.valueOf(userStatMap.getOrDefault(Lucky25UserMetaService.INPUT_KEY, 0L).longValue());
|
|
||||||
historyOutput = BigDecimal.valueOf(userStatMap.getOrDefault(Lucky25UserMetaService.OUTPUT_KEY, 0L).longValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomicBoolean space1000flag = new AtomicBoolean(false);
|
|
||||||
AtomicBoolean space100flag = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
BigDecimal productionRatio_B = historyOutput.compareTo(BigDecimal.ZERO) != 0 ?
|
|
||||||
historyOutput.divide(historyInput,2, RoundingMode.HALF_UP): BigDecimal.ZERO;
|
|
||||||
BigDecimal historyDiff_C = historyInput.subtract(historyOutput);
|
|
||||||
BigDecimal expect_D = partitionConfig.getHighInputExpect_D();
|
|
||||||
BigDecimal X = productionRatio_B.compareTo(BigDecimal.ONE) != 0 ?
|
|
||||||
historyDiff_C.divide(BigDecimal.ONE.subtract(productionRatio_B), 2, RoundingMode.HALF_UP): BigDecimal.ZERO;
|
|
||||||
BigDecimal water = X.multiply(BigDecimal.ONE.subtract(expect_D).add(BigDecimal.valueOf(0.01D)));
|
|
||||||
BigDecimal space1000 = (historyDiff_C.subtract(water)).divide(BigDecimal.valueOf(1000L), 2, RoundingMode.HALF_UP);
|
|
||||||
if (space1000.compareTo(totalInput_A) > 0){
|
|
||||||
return receiverList.parallelStream()
|
|
||||||
.collect(Collectors.toMap(receiverUid-> receiverUid,
|
|
||||||
receiverUid-> {
|
|
||||||
//left
|
|
||||||
int randomIndex = RandomUtil.randomByRange(0, 10);
|
|
||||||
long drawMultiple = randomIndex < 1? 1000L: randomIndex < 2? 500L: randomIndex < 5? 100L: 0L;
|
|
||||||
log.info("[lucky25] uid {} space1000 {} totalInput {} left receiverUid {} randomIndex {} drawMultiple {}",
|
|
||||||
senderUid, space1000, totalInput_A, receiverUid, randomIndex, drawMultiple);
|
|
||||||
if (drawMultiple > 0L && !space1000flag.compareAndSet(false, true)){
|
|
||||||
drawMultiple = 0L;
|
|
||||||
log.info("[lucky25] uid {} space1000 cas false {} totalInput {} left receiverUid {} randomIndex {} drawMultiple {}",
|
|
||||||
senderUid, space1000, totalInput_A, receiverUid, randomIndex, drawMultiple);
|
|
||||||
}
|
|
||||||
Lucky25Result result = new Lucky25Result(null, everyoneGoldNum, drawMultiple, false);
|
|
||||||
return updateMeta(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, receiverUid, everyoneGoldNum, room, sendGiftTime, null, result);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
BigDecimal space100 = (historyDiff_C.subtract(water)).divide(BigDecimal.valueOf(100L), 2, RoundingMode.HALF_UP);
|
|
||||||
if (space100.compareTo(totalInput_A) > 0){
|
|
||||||
return receiverList.parallelStream()
|
|
||||||
.collect(Collectors.toMap(receiverUid-> receiverUid,
|
|
||||||
receiverUid-> {
|
|
||||||
//middle
|
|
||||||
int randomIndex = RandomUtil.randomByRange(0, 100);
|
|
||||||
long drawMultiple = randomIndex < 25? 100L: randomIndex < 55? 5L: 0L;
|
|
||||||
log.info("[lucky25] uid {} space100 {} totalInput {} middle receiver {} randomIndex {} drawMultiple {}",
|
|
||||||
senderUid, space100, totalInput_A, receiverUid, randomIndex, drawMultiple);
|
|
||||||
if (drawMultiple > 0L && !space100flag.compareAndSet(false, true)){
|
|
||||||
drawMultiple = 0L;
|
|
||||||
log.info("[lucky25] uid {} space100 cas false {} totalInput {} left receiverUid {} randomIndex {} drawMultiple {}",
|
|
||||||
senderUid, space1000, totalInput_A, receiverUid, randomIndex, drawMultiple);
|
|
||||||
}
|
|
||||||
Lucky25Result result = new Lucky25Result(null, everyoneGoldNum, drawMultiple, false);
|
|
||||||
return updateMeta(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, receiverUid, everyoneGoldNum, room, sendGiftTime, null, result);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
log.info("[lucky25] uid {} space100 {} totalInput {} 原来 10L", senderUid, space1000, totalInput_A);
|
|
||||||
return receiverList.parallelStream()
|
|
||||||
.collect(Collectors.toMap(receiverUid-> receiverUid,
|
|
||||||
receiverUid-> drawMultiple(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, receiverUid, everyoneGoldNum, room, sendGiftTime, null)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMq(Map<Long, Lucky25Record> recordMap) {
|
|
||||||
Map<String, String> caches = new HashMap<>(recordMap.size());
|
|
||||||
List<Lucky25Message> messageList = new ArrayList<>();
|
|
||||||
|
|
||||||
DefaultIdentifierGenerator idGenerator = DefaultIdentifierGenerator.getInstance();
|
|
||||||
|
|
||||||
for (Lucky25Record record: recordMap.values()){
|
|
||||||
String id = idGenerator.nextUUID(null);
|
|
||||||
|
|
||||||
Lucky25Message message = new Lucky25Message();
|
|
||||||
message.setMessId(id);
|
|
||||||
message.setPartitionId(record.getPartitionId());
|
|
||||||
message.setUid(record.getUid());
|
|
||||||
message.setReceiverUid(record.getReceiverUid());
|
|
||||||
message.setRoomUid(record.getRoomUid());
|
|
||||||
message.setGiftId(record.getGiftId());
|
|
||||||
message.setGiftGoldPrice(record.getGiftGoldPrice());
|
|
||||||
message.setGiftNum(record.getGiftNum());
|
|
||||||
message.setPoolId(record.getPoolId());
|
|
||||||
message.setIsSupplement(record.getIsSupplement());
|
|
||||||
message.setDrawMultiple(record.getDrawMultiple());
|
|
||||||
message.setAfterMultiple(record.getAfterMultiple());
|
|
||||||
message.setWinGoldNum(record.getWinGoldNum());
|
|
||||||
message.setCreateTime(record.getCreateTime().getTime());
|
|
||||||
|
|
||||||
messageList.add(message);
|
|
||||||
|
|
||||||
caches.put(id, JSON.toJSONString(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
jedisService.hwrite(RedisKey.lucky_25_status.getKey(), caches);
|
|
||||||
|
|
||||||
rocketMQService.sendBatchLucky25Message(messageList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Lucky25Record drawMultiple(Lucky25GiftConfig config, Lucky25GiftConfig partitionConfig, long senderUid, int partitionId,
|
|
||||||
Gift gift, int giftNum, long receiverUid, long everyoneGoldNum, Room room, Date sendGiftTime,
|
|
||||||
Long maxMultiple) {
|
|
||||||
Lucky25Result drawResult = poolService.drawMultipleFromPool(config, senderUid, partitionId);
|
|
||||||
return updateMeta(config, partitionConfig, senderUid, partitionId, gift, giftNum, receiverUid, everyoneGoldNum, room, sendGiftTime, maxMultiple, drawResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Lucky25Record updateMeta(Lucky25GiftConfig config, Lucky25GiftConfig partitionConfig, long senderUid, int partitionId,
|
|
||||||
Gift gift, int giftNum, long receiverUid, long everyoneGoldNum, Room room, Date sendGiftTime,
|
|
||||||
Long maxMultiple, Lucky25Result drawResult){
|
|
||||||
long drawMultiple = drawResult.getOutput();
|
|
||||||
long afterMultiple = drawMultiple;
|
|
||||||
if (null != maxMultiple) {
|
|
||||||
afterMultiple = Math.min(afterMultiple, maxMultiple);
|
|
||||||
}
|
|
||||||
// 个人库存
|
|
||||||
if (afterMultiple > 0L){
|
|
||||||
long preWinGoldNum = afterMultiple * everyoneGoldNum;
|
|
||||||
if (!userMetaService.judgePersonalStock(partitionConfig, senderUid, receiverUid, everyoneGoldNum, preWinGoldNum)){
|
|
||||||
afterMultiple = 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 平台库存
|
|
||||||
if (afterMultiple > 0L){
|
|
||||||
BigDecimal preWinGoldNum = BigDecimal.valueOf(afterMultiple * everyoneGoldNum);
|
|
||||||
if (!judgeStock(partitionId, preWinGoldNum, senderUid, receiverUid)){
|
|
||||||
afterMultiple = 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
long winGoldNum = afterMultiple * everyoneGoldNum;
|
|
||||||
userMetaService.updateUserMeta(senderUid, partitionId, everyoneGoldNum, winGoldNum);
|
|
||||||
|
|
||||||
if (winGoldNum > 0L){
|
|
||||||
settlementService.syncSendReward(config, senderUid, room, gift, winGoldNum, afterMultiple);
|
|
||||||
}
|
|
||||||
|
|
||||||
return recordService.buildRecord(senderUid, partitionId, gift, giftNum, null != room? room.getUid(): null,
|
|
||||||
receiverUid, drawResult.getPoolId(), Boolean.TRUE.equals(drawResult.getIsSupplement()),
|
|
||||||
drawMultiple, afterMultiple, sendGiftTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean judgeStock(Integer partitionId, BigDecimal winGoldNum, Long senderUid, Long receiverUid){
|
|
||||||
BigDecimal afterStock = stockService.subStock(partitionId, winGoldNum);
|
|
||||||
boolean enough = afterStock.compareTo(BigDecimal.ZERO) >= 0;
|
|
||||||
if (!enough){
|
|
||||||
log.info("[lucky25] drawMultiple sender {} receiver {} 产出大于库存 winGoldNum {} afterStock {}",
|
|
||||||
senderUid, receiverUid, winGoldNum, afterStock);
|
|
||||||
afterStock = stockService.addStock(partitionId, winGoldNum);
|
|
||||||
robotMsgService.pushStockNotEnough(partitionId, afterStock);
|
|
||||||
}
|
|
||||||
return enough;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Lucky25GiftConfig getConfig() {
|
public Lucky25GiftConfig getConfig() {
|
||||||
|
@@ -1,114 +0,0 @@
|
|||||||
package com.accompany.business.service.gift;
|
|
||||||
|
|
||||||
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
|
||||||
import com.accompany.business.dto.lucky.SuperLuckyGiftIncomeAllot;
|
|
||||||
import com.accompany.business.message.Lucky25Message;
|
|
||||||
import com.accompany.business.model.Gift;
|
|
||||||
import com.accompany.business.service.lucky.*;
|
|
||||||
import com.accompany.business.service.lucky.rank.Lucky24SendWeekRankService;
|
|
||||||
import com.accompany.business.service.room.RoomService;
|
|
||||||
import com.accompany.common.redis.RedisKey;
|
|
||||||
import com.accompany.core.model.Room;
|
|
||||||
import com.accompany.core.service.base.BaseService;
|
|
||||||
import com.accompany.sharding.model.Lucky25Record;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class Lucky25MessageService extends BaseService {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Lucky25RecordService recordService;
|
|
||||||
@Autowired
|
|
||||||
private Lucky25IncomeAllotService incomeAllotService;
|
|
||||||
@Autowired
|
|
||||||
private SuperLuckyGiftSendService superLuckyGiftSendService;
|
|
||||||
@Autowired
|
|
||||||
private Lucky25RobotMsgService robotMsgService;
|
|
||||||
@Autowired
|
|
||||||
private Lucky25GiftSendService sendService;
|
|
||||||
@Autowired
|
|
||||||
private RoomService roomService;
|
|
||||||
@Autowired
|
|
||||||
private GiftService giftService;
|
|
||||||
@Autowired
|
|
||||||
private Lucky24SendWeekRankService lucky24SendWeekRankService;
|
|
||||||
|
|
||||||
public void handleGiftMessage(Lucky25Message giftMessage) {
|
|
||||||
// 防止消息被重复消费
|
|
||||||
if (!jedisLockService.isExist(RedisKey.lock_lucky_25_message.getKey(giftMessage.getMessId()), 30)) {
|
|
||||||
logger.warn("handleLucky25Message giftMessage had handle, mess: " + giftMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!jedisService.hexists(RedisKey.lucky_25_status.getKey(), giftMessage.getMessId())){
|
|
||||||
logger.warn("handleLucky25Message giftMessage had handle, mess: " + giftMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("【处理Lucky25 mq】 开始处理 giftMessage: {}", JSON.toJSONString(giftMessage));
|
|
||||||
|
|
||||||
Room room = null != giftMessage.getRoomUid()? roomService.getRoomByUid(giftMessage.getRoomUid()): null;
|
|
||||||
Gift gift = giftService.getGiftById(giftMessage.getGiftId());
|
|
||||||
Date createTime = new Date(giftMessage.getCreateTime());
|
|
||||||
|
|
||||||
Lucky25Record record = insertRecord(giftMessage);
|
|
||||||
|
|
||||||
log.info("【处理Lucky25 mq】 record 插入成功 messId:{} recordId:{} record:{}",
|
|
||||||
giftMessage.getMessId(), record.getId(), JSON.toJSONString(record));
|
|
||||||
|
|
||||||
// 收礼者收益
|
|
||||||
Lucky25GiftConfig config = sendService.getConfig();
|
|
||||||
Lucky25GiftConfig partitionConfig = config.getRatioByPartitionId(giftMessage.getPartitionId());
|
|
||||||
SuperLuckyGiftIncomeAllot receiverIncomeAllot = incomeAllotService.calculate(partitionConfig, gift, giftMessage.getGiftNum(), Collections.singletonList(record.getReceiverUid()));
|
|
||||||
superLuckyGiftSendService.syncSettlement(giftMessage.getUid(), gift, giftMessage.getGiftNum(), giftMessage.getGiftNum(), room, receiverIncomeAllot, createTime);
|
|
||||||
|
|
||||||
logger.info("【处理Lucky25 mq】 收礼收益已发放 messId: {} incomeAllot: {}", giftMessage.getMessId(), JSON.toJSONString(receiverIncomeAllot));
|
|
||||||
|
|
||||||
// 后面都是异步发消息
|
|
||||||
// if (record.getAfterMultiple() >= config.getWarnMulti()){
|
|
||||||
// long totalGoldNum = giftMessage.getGiftNum() * giftMessage.getGiftGoldPrice();
|
|
||||||
// robotMsgService.pushSuperMulti(record.getUid(), record.getReceiverUid(), record.getAfterMultiple(), totalGoldNum, record.getWinGoldNum(),
|
|
||||||
// record.getRoomUid());
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(config.getFollowUidList()) && config.getFollowUidList().contains(record.getUid())){
|
|
||||||
robotMsgService.pushFollowUser(record.getUid(), record.getReceiverUid(), record.getRoomUid());
|
|
||||||
}
|
|
||||||
|
|
||||||
lucky24SendWeekRankService.updateRank(record);
|
|
||||||
|
|
||||||
// 删除该标识,表示消息已经消费过
|
|
||||||
jedisService.hdel(RedisKey.lucky_25_status.getKey(), giftMessage.getMessId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Lucky25Record insertRecord(Lucky25Message giftMessage) {
|
|
||||||
Lucky25Record record = new Lucky25Record();
|
|
||||||
record.setMessId(giftMessage.getMessId());
|
|
||||||
record.setPartitionId(giftMessage.getPartitionId());
|
|
||||||
record.setUid(giftMessage.getUid());
|
|
||||||
record.setReceiverUid(giftMessage.getReceiverUid());
|
|
||||||
record.setRoomUid(giftMessage.getRoomUid());
|
|
||||||
record.setGiftId(giftMessage.getGiftId());
|
|
||||||
record.setGiftGoldPrice(giftMessage.getGiftGoldPrice());
|
|
||||||
record.setGiftNum(giftMessage.getGiftNum());
|
|
||||||
record.setPoolId(giftMessage.getPoolId());
|
|
||||||
record.setIsSupplement(giftMessage.getIsSupplement());
|
|
||||||
record.setDrawMultiple(giftMessage.getDrawMultiple());
|
|
||||||
record.setAfterMultiple(giftMessage.getAfterMultiple());
|
|
||||||
record.setWinGoldNum(giftMessage.getWinGoldNum());
|
|
||||||
record.setCreateTime(new Date(giftMessage.getCreateTime()));
|
|
||||||
|
|
||||||
recordService.insertRecord(record);
|
|
||||||
|
|
||||||
return record;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -0,0 +1,171 @@
|
|||||||
|
package com.accompany.business.service.gift;
|
||||||
|
|
||||||
|
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
||||||
|
import com.accompany.business.dto.lucky.SuperLuckyGiftIncomeAllot;
|
||||||
|
import com.accompany.business.message.Lucky25Message;
|
||||||
|
import com.accompany.business.model.Gift;
|
||||||
|
import com.accompany.business.service.lucky.*;
|
||||||
|
import com.accompany.business.service.lucky.rank.Lucky24SendWeekRankService;
|
||||||
|
import com.accompany.business.service.mq.RocketMQService;
|
||||||
|
import com.accompany.business.service.room.RoomService;
|
||||||
|
import com.accompany.common.redis.RedisKey;
|
||||||
|
import com.accompany.common.status.BusiStatus;
|
||||||
|
import com.accompany.core.exception.ServiceException;
|
||||||
|
import com.accompany.core.model.Room;
|
||||||
|
import com.accompany.sharding.model.Lucky25Record;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RMap;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class Lucky25MqService implements InitializingBean {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25RecordService recordService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25IncomeAllotService incomeAllotService;
|
||||||
|
@Autowired
|
||||||
|
private SuperLuckyGiftSendService superLuckyGiftSendService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25RobotMsgService robotMsgService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25GiftSendService sendService;
|
||||||
|
@Autowired
|
||||||
|
private RoomService roomService;
|
||||||
|
@Autowired
|
||||||
|
private GiftService giftService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky24SendWeekRankService lucky24SendWeekRankService;
|
||||||
|
@Autowired
|
||||||
|
private RocketMQService rocketMQService;
|
||||||
|
|
||||||
|
private RMap<String, String> statusMap;
|
||||||
|
|
||||||
|
public void sendMq(List<Lucky25Record> recordList) {
|
||||||
|
Map<String, String> caches = new HashMap<>(recordList.size());
|
||||||
|
List<Lucky25Message> messageList = new ArrayList<>();
|
||||||
|
|
||||||
|
DefaultIdentifierGenerator idGenerator = DefaultIdentifierGenerator.getInstance();
|
||||||
|
|
||||||
|
for (Lucky25Record record: recordList){
|
||||||
|
String id = idGenerator.nextUUID(null);
|
||||||
|
|
||||||
|
Lucky25Message message = new Lucky25Message();
|
||||||
|
message.setMessId(id);
|
||||||
|
message.setPartitionId(record.getPartitionId());
|
||||||
|
message.setUid(record.getUid());
|
||||||
|
message.setReceiverUid(record.getReceiverUid());
|
||||||
|
message.setRoomUid(record.getRoomUid());
|
||||||
|
message.setGiftId(record.getGiftId());
|
||||||
|
message.setGiftGoldPrice(record.getGiftGoldPrice());
|
||||||
|
message.setGiftNum(record.getGiftNum());
|
||||||
|
message.setPoolId(record.getPoolId());
|
||||||
|
message.setIsSupplement(record.getIsSupplement());
|
||||||
|
message.setDrawMultiple(record.getDrawMultiple());
|
||||||
|
message.setAfterMultiple(record.getAfterMultiple());
|
||||||
|
message.setWinGoldNum(record.getWinGoldNum());
|
||||||
|
message.setCreateTime(record.getCreateTime().getTime());
|
||||||
|
|
||||||
|
messageList.add(message);
|
||||||
|
|
||||||
|
caches.put(id, JSON.toJSONString(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
statusMap.putAll(caches);
|
||||||
|
|
||||||
|
rocketMQService.sendBatchLucky25Message(messageList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleMq(Lucky25Message giftMessage) {
|
||||||
|
// 防止消息被重复消费
|
||||||
|
boolean locked = false;
|
||||||
|
RLock lock = redissonClient.getLock(RedisKey.lock_lucky_25_message.getKey(giftMessage.getMessId()));
|
||||||
|
try {
|
||||||
|
locked = lock.tryLock(15, 5, TimeUnit.SECONDS);
|
||||||
|
if (!locked) {
|
||||||
|
log.warn("handleLucky25Message giftMessage lock fail, mess: {}", JSON.toJSONString(giftMessage));
|
||||||
|
throw new ServiceException(BusiStatus.SERVERBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!statusMap.containsKey(giftMessage.getMessId())){
|
||||||
|
log.warn("handleLucky25Message giftMessage had handle, mess: " + giftMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("【处理Lucky25 mq】 开始处理 giftMessage: {}", JSON.toJSONString(giftMessage));
|
||||||
|
|
||||||
|
Room room = null != giftMessage.getRoomUid()? roomService.getRoomByUid(giftMessage.getRoomUid()): null;
|
||||||
|
Gift gift = giftService.getGiftById(giftMessage.getGiftId());
|
||||||
|
Date createTime = new Date(giftMessage.getCreateTime());
|
||||||
|
|
||||||
|
Lucky25Record record = insertRecord(giftMessage);
|
||||||
|
|
||||||
|
log.info("【处理Lucky25 mq】 record 插入成功 messId:{} recordId:{} record:{}",
|
||||||
|
giftMessage.getMessId(), record.getId(), JSON.toJSONString(record));
|
||||||
|
|
||||||
|
// 收礼者收益
|
||||||
|
Lucky25GiftConfig config = sendService.getConfig();
|
||||||
|
SuperLuckyGiftIncomeAllot receiverIncomeAllot = incomeAllotService.calculate(config, giftMessage.getPartitionId(), gift, giftMessage.getGiftNum(), Collections.singletonList(record.getReceiverUid()));
|
||||||
|
superLuckyGiftSendService.syncSettlement(giftMessage.getUid(), gift, giftMessage.getGiftNum(), giftMessage.getGiftNum(), room, receiverIncomeAllot, createTime);
|
||||||
|
|
||||||
|
log.info("【处理Lucky25 mq】 收礼收益已发放 messId: {} incomeAllot: {}", giftMessage.getMessId(), JSON.toJSONString(receiverIncomeAllot));
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(config.getFollowUidList()) && config.getFollowUidList().contains(record.getUid())){
|
||||||
|
robotMsgService.pushFollowUser(record.getUid(), record.getReceiverUid(), record.getRoomUid());
|
||||||
|
}
|
||||||
|
|
||||||
|
lucky24SendWeekRankService.updateRank(record);
|
||||||
|
|
||||||
|
// 删除该标识,表示消息已经消费过
|
||||||
|
statusMap.fastRemove(giftMessage.getMessId());
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("handleLucky25Message giftMessage lock overtime, mess: {}", JSON.toJSONString(giftMessage), e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Lucky25Record insertRecord(Lucky25Message giftMessage) {
|
||||||
|
Lucky25Record record = new Lucky25Record();
|
||||||
|
record.setMessId(giftMessage.getMessId());
|
||||||
|
record.setPartitionId(giftMessage.getPartitionId());
|
||||||
|
record.setUid(giftMessage.getUid());
|
||||||
|
record.setReceiverUid(giftMessage.getReceiverUid());
|
||||||
|
record.setRoomUid(giftMessage.getRoomUid());
|
||||||
|
record.setGiftId(giftMessage.getGiftId());
|
||||||
|
record.setGiftGoldPrice(giftMessage.getGiftGoldPrice());
|
||||||
|
record.setGiftNum(giftMessage.getGiftNum());
|
||||||
|
record.setPoolId(giftMessage.getPoolId());
|
||||||
|
record.setIsSupplement(giftMessage.getIsSupplement());
|
||||||
|
record.setDrawMultiple(giftMessage.getDrawMultiple());
|
||||||
|
record.setAfterMultiple(giftMessage.getAfterMultiple());
|
||||||
|
record.setWinGoldNum(giftMessage.getWinGoldNum());
|
||||||
|
record.setCreateTime(new Date(giftMessage.getCreateTime()));
|
||||||
|
|
||||||
|
recordService.insertRecord(record);
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
statusMap = redissonClient.getMap(RedisKey.lucky_25_status.getKey());
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,146 @@
|
|||||||
|
package com.accompany.business.service.lucky;
|
||||||
|
|
||||||
|
import com.accompany.business.constant.Lucky25PoolTypeEnum;
|
||||||
|
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
||||||
|
import com.accompany.business.dto.lucky.Lucky25Result;
|
||||||
|
import com.accompany.business.model.lucky.Lucky25Pool;
|
||||||
|
import com.accompany.business.mybatismapper.lucky.Lucky25PoolMapper;
|
||||||
|
import com.accompany.common.redis.RedisKey;
|
||||||
|
import com.accompany.common.status.BusiStatus;
|
||||||
|
import com.accompany.common.utils.RandomUtil;
|
||||||
|
import com.accompany.core.exception.ServiceException;
|
||||||
|
import com.accompany.payment.service.HighRechargeUserService;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RDeque;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RQueue;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class Lucky25HighRechargePoolService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
@Autowired
|
||||||
|
private HighRechargeUserService highRechargeUserService;
|
||||||
|
@Autowired
|
||||||
|
private Lucky25PoolMapper poolMapper;
|
||||||
|
|
||||||
|
public Lucky25Result drawMultipleFromPool(Lucky25GiftConfig config, Long uid, Integer partitionId){
|
||||||
|
if (!highRechargeUserService.isHighRechargeUser(uid)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RQueue<Lucky25Result> partitionPool = getHighRechargePool(partitionId);
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
Lucky25Result result = partitionPool.poll();
|
||||||
|
if (null != result) {
|
||||||
|
partitionPool.expireAsync(Duration.of(14, ChronoUnit.DAYS));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
genPool(config, partitionId, partitionPool);
|
||||||
|
}
|
||||||
|
throw new ServiceException(BusiStatus.SERVERBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void genPool(Lucky25GiftConfig config, Integer partitionId, RQueue<Lucky25Result> partitionPool) {
|
||||||
|
boolean locked = false;
|
||||||
|
RLock lock = redissonClient.getLock(RedisKey.lucky_25_user_lock.getKey(partitionId.toString()));
|
||||||
|
try {
|
||||||
|
locked = lock.tryLock(5,3, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
if (!partitionPool.isEmpty()){
|
||||||
|
log.info("[lucky25] genPool uid {} 已生成pool,无需再生成", partitionId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!locked) {
|
||||||
|
throw new ServiceException(BusiStatus.SERVERBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Lucky25Pool> poolList = poolMapper.selectList(Wrappers.<Lucky25Pool>lambdaQuery()
|
||||||
|
.eq(Lucky25Pool::getType, Lucky25PoolTypeEnum.HIGH_INPUT_POOL.getType()));
|
||||||
|
if (CollectionUtils.isEmpty(poolList)){
|
||||||
|
throw new ServiceException(BusiStatus.SEIZE_TREASURE_POOL_CONFIG_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int randomIndex = RandomUtil.randomByRange(0, poolList.size());
|
||||||
|
Lucky25Pool randomPool = poolList.get(randomIndex);
|
||||||
|
log.info("[lucky25] genHighRechargePool pooList {}, randomIndex {}, expect {}",
|
||||||
|
JSON.toJSONString(poolList.stream().map(Lucky25Pool::getExpect).collect(Collectors.toList())), randomIndex, randomPool.getExpect());
|
||||||
|
|
||||||
|
buildPool(config, partitionId, partitionPool, randomPool);
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildPool(Lucky25GiftConfig config, Integer partitionId, RQueue<Lucky25Result> partitionPool, Lucky25Pool pool) {
|
||||||
|
List<Lucky25Pool.Lucky24PoolItem> poolItemList = pool.getItemList().stream().filter(item->item.getNum()>0).collect(Collectors.toList());
|
||||||
|
List<Integer> winList = buildWinList(poolItemList);
|
||||||
|
int[] poolArray = new int[config.getPoolSize()];
|
||||||
|
for (int i = 0; i < config.getPoolSize(); i++) {
|
||||||
|
poolArray[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!winList.isEmpty()){
|
||||||
|
List<Integer> winIndexList = new ArrayList<>();
|
||||||
|
int winDistance = config.getPoolSize() / winList.size();
|
||||||
|
for (int i = 0; i < winList.size(); i++) {
|
||||||
|
int nextWinIndex = config.getPoolSize() - 1 - i * winDistance;
|
||||||
|
// 确保索引不会超出超集范围
|
||||||
|
if (nextWinIndex > 0) {
|
||||||
|
poolArray[nextWinIndex] = winList.get(i);
|
||||||
|
winIndexList.add(nextWinIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("[lucky25] genHighRechargePool buildPool partitionId {}, winIndexList {}", partitionId, JSON.toJSONString(winIndexList));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Lucky25Result> poolList = Arrays.stream(poolArray).boxed().map(output->{
|
||||||
|
Lucky25Result result = new Lucky25Result();
|
||||||
|
result.setPoolId(pool.getId());
|
||||||
|
result.setOutput(output);
|
||||||
|
return result;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
partitionPool.addAll(poolList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> buildWinList(List<Lucky25Pool.Lucky24PoolItem> poolItemList) {
|
||||||
|
List<Integer> resultList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Lucky25Pool.Lucky24PoolItem item : poolItemList) {
|
||||||
|
int multi = item.getMulti();
|
||||||
|
int num = item.getNum();
|
||||||
|
|
||||||
|
// 使用循环生成 num 个 multi 值,并添加到 resultList 中
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
resultList.add(multi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.shuffle(resultList);
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RDeque<Lucky25Result> getHighRechargePool(Integer partitionId) {
|
||||||
|
return redissonClient.getDeque(RedisKey.lucky_25_high_recharge_pool.getKey(partitionId.toString()));
|
||||||
|
}
|
||||||
|
}
|
@@ -25,7 +25,10 @@ public class Lucky25IncomeAllotService implements LuckyGiftIncomeAllotService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private BillRecordService billRecordService;
|
private BillRecordService billRecordService;
|
||||||
|
|
||||||
public SuperLuckyGiftIncomeAllot calculate(Lucky25GiftConfig config, Gift gift, int giftNum, List<Long> receiverUids) {
|
public SuperLuckyGiftIncomeAllot calculate(Lucky25GiftConfig config, Integer partitionId,
|
||||||
|
Gift gift, int giftNum, List<Long> receiverUids) {
|
||||||
|
Lucky25GiftConfig partitionConfig = config.getRatioByPartitionId(partitionId);
|
||||||
|
|
||||||
BigDecimal giftNumB = BigDecimal.valueOf(giftNum);
|
BigDecimal giftNumB = BigDecimal.valueOf(giftNum);
|
||||||
BigDecimal totalNum = BigDecimal.valueOf(receiverUids.size()).multiply(giftNumB);
|
BigDecimal totalNum = BigDecimal.valueOf(receiverUids.size()).multiply(giftNumB);
|
||||||
// 单价
|
// 单价
|
||||||
@@ -35,9 +38,9 @@ public class Lucky25IncomeAllotService implements LuckyGiftIncomeAllotService {
|
|||||||
BigDecimal totalValue = giftValue.multiply(totalNum);
|
BigDecimal totalValue = giftValue.multiply(totalNum);
|
||||||
|
|
||||||
// 收礼者收益单价
|
// 收礼者收益单价
|
||||||
BigDecimal receiverIncome = everyTotalValue.multiply(config.getReceiverRatio());
|
BigDecimal receiverIncome = everyTotalValue.multiply(partitionConfig.getReceiverRatio());
|
||||||
|
|
||||||
BigDecimal receiverTotalIncome = totalValue.multiply(config.getReceiverRatio());
|
BigDecimal receiverTotalIncome = totalValue.multiply(partitionConfig.getReceiverRatio());
|
||||||
|
|
||||||
Map<Long, BigDecimal> receiverIncomeMap = new HashMap<>();
|
Map<Long, BigDecimal> receiverIncomeMap = new HashMap<>();
|
||||||
for (Long receiver: receiverUids){
|
for (Long receiver: receiverUids){
|
||||||
@@ -45,7 +48,7 @@ public class Lucky25IncomeAllotService implements LuckyGiftIncomeAllotService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 平台抽成
|
// 平台抽成
|
||||||
BigDecimal platformGoldNum = totalValue.multiply(config.getPlatformRatio());
|
BigDecimal platformGoldNum = totalValue.multiply(partitionConfig.getPlatformRatio());
|
||||||
// 增加库存
|
// 增加库存
|
||||||
BigDecimal addStockGoldNum = totalValue.subtract(platformGoldNum);
|
BigDecimal addStockGoldNum = totalValue.subtract(platformGoldNum);
|
||||||
|
|
||||||
|
@@ -3,8 +3,6 @@ package com.accompany.business.service.lucky;
|
|||||||
import com.accompany.business.constant.Lucky25PoolTypeEnum;
|
import com.accompany.business.constant.Lucky25PoolTypeEnum;
|
||||||
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
||||||
import com.accompany.business.dto.lucky.Lucky25Result;
|
import com.accompany.business.dto.lucky.Lucky25Result;
|
||||||
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
|
||||||
import com.accompany.business.dto.lucky.Lucky25Result;
|
|
||||||
import com.accompany.business.model.lucky.Lucky25Pool;
|
import com.accompany.business.model.lucky.Lucky25Pool;
|
||||||
import com.accompany.business.mybatismapper.lucky.Lucky25PoolMapper;
|
import com.accompany.business.mybatismapper.lucky.Lucky25PoolMapper;
|
||||||
import com.accompany.common.redis.RedisKey;
|
import com.accompany.common.redis.RedisKey;
|
||||||
@@ -173,15 +171,15 @@ public class Lucky25PoolService {
|
|||||||
String todayInputKey = String.join("_", todayStartTimeStr, Lucky25UserMetaService.INPUT_KEY);
|
String todayInputKey = String.join("_", todayStartTimeStr, Lucky25UserMetaService.INPUT_KEY);
|
||||||
String todayOutputKey = String.join("_", todayStartTimeStr, Lucky25UserMetaService.OUTPUT_KEY);
|
String todayOutputKey = String.join("_", todayStartTimeStr, Lucky25UserMetaService.OUTPUT_KEY);
|
||||||
|
|
||||||
RMap<String, Number> userMetaMap = userMetaService.getUserMeta(uid);
|
Map<String, Number> userMetaMap = userMetaService.getUserMeta(uid).readAllMap();
|
||||||
BigDecimal input = BigDecimal.valueOf(userMetaMap.getOrDefault(todayInputKey, 0L).longValue());
|
BigDecimal input = BigDecimal.valueOf(userMetaMap.getOrDefault(todayInputKey, 0L).longValue());
|
||||||
BigDecimal output = BigDecimal.valueOf(userMetaMap.getOrDefault(todayOutputKey, 0L).longValue());
|
BigDecimal output = BigDecimal.valueOf(userMetaMap.getOrDefault(todayOutputKey, 0L).longValue());
|
||||||
BigDecimal todayProductionRatio = BigDecimal.ZERO.equals(output)? BigDecimal.ZERO: output.divide(input,2, RoundingMode.HALF_UP);
|
BigDecimal todayProductionRatio = BigDecimal.ZERO.equals(output)? BigDecimal.ZERO: output.divide(input,2, RoundingMode.HALF_UP);
|
||||||
if (input.compareTo(BigDecimal.valueOf(300000)) >= 0 && todayProductionRatio.compareTo(partitionConfig.getTodayProductionRatio()) >= 0){
|
if (input.compareTo(partitionConfig.getTodayInput()) >= 0 && todayProductionRatio.compareTo(partitionConfig.getTodayProductionRatio()) >= 0){
|
||||||
List<Lucky25Pool> excludePoolList = poolList.stream()
|
List<Lucky25Pool> excludePoolList = poolList.stream()
|
||||||
.filter(pool->pool.getType() == Lucky25PoolTypeEnum.NORMAL_POOL.getType())
|
.filter(pool->pool.getType() == Lucky25PoolTypeEnum.NORMAL_POOL.getType())
|
||||||
.filter(pool-> pool.getItemList().stream().noneMatch(poolItem->poolItem.getMulti() == 1000 && poolItem.getNum() > 0))
|
.filter(pool-> pool.getItemList().stream().noneMatch(poolItem->poolItem.getMulti() == 1000 && poolItem.getNum() > 0))
|
||||||
.filter(pool-> partitionConfig.getProductionRatio().compareTo(pool.getExpect()) > 0)
|
.filter(pool-> partitionConfig.getProductionRatio_N().compareTo(pool.getExpect()) > 0)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
int randomIndex = RandomUtil.randomByRange(0, excludePoolList.size());
|
int randomIndex = RandomUtil.randomByRange(0, excludePoolList.size());
|
||||||
@@ -215,7 +213,7 @@ public class Lucky25PoolService {
|
|||||||
|
|
||||||
private BigDecimal calExpect(Lucky25GiftConfig config, Lucky25GiftConfig partitionConfig, Long uid) {
|
private BigDecimal calExpect(Lucky25GiftConfig config, Lucky25GiftConfig partitionConfig, Long uid) {
|
||||||
BigDecimal n = !CollectionUtils.isEmpty(config.getWhiteUidProductionRatioMap()) && config.getWhiteUidProductionRatioMap().containsKey(uid) ?
|
BigDecimal n = !CollectionUtils.isEmpty(config.getWhiteUidProductionRatioMap()) && config.getWhiteUidProductionRatioMap().containsKey(uid) ?
|
||||||
config.getWhiteUidProductionRatioMap().get(uid): partitionConfig.getProductionRatio();
|
config.getWhiteUidProductionRatioMap().get(uid): partitionConfig.getProductionRatio_N();
|
||||||
|
|
||||||
BigDecimal userLast2000ProductionRatio = userMetaService.getUserLast2000ProductionRatio(uid);
|
BigDecimal userLast2000ProductionRatio = userMetaService.getUserLast2000ProductionRatio(uid);
|
||||||
if (userLast2000ProductionRatio.compareTo(n) <= 0){
|
if (userLast2000ProductionRatio.compareTo(n) <= 0){
|
||||||
@@ -260,42 +258,4 @@ public class Lucky25PoolService {
|
|||||||
return redissonClient.getDeque(RedisKey.lucky_25_user_pool.getKey(uid.toString()));
|
return redissonClient.getDeque(RedisKey.lucky_25_user_pool.getKey(uid.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateUserMulti(Long uid) {
|
|
||||||
RDeque<Lucky25Result> userPool = getUserPool(uid);
|
|
||||||
if (userPool.isEmpty()){
|
|
||||||
log.info("[lucky25] updateUserMulti uid {} 未生成pool", uid);
|
|
||||||
throw new ServiceException(BusiStatus.SERVERBUSY, "用户未生成奖池");
|
|
||||||
}
|
|
||||||
boolean locked = false;
|
|
||||||
RLock lock = redissonClient.getLock(RedisKey.lucky_25_user_lock.getKey(uid.toString()));
|
|
||||||
try {
|
|
||||||
locked = lock.tryLock(5,3, TimeUnit.SECONDS);
|
|
||||||
if (!locked) {
|
|
||||||
throw new ServiceException(BusiStatus.SERVERBUSY);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userPool.isEmpty()){
|
|
||||||
log.info("[lucky25] updateUserMulti uid {} 未生成pool", uid);
|
|
||||||
throw new ServiceException(BusiStatus.SERVERBUSY, "用户未生成奖池");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Lucky25Result> list = userPool.poll(11);
|
|
||||||
for (int i = list.size() - 1; i >= 0; i--) {
|
|
||||||
Lucky25Result result = list.get(i);
|
|
||||||
if (i >= list.size() - 1) {
|
|
||||||
result.setIsSupplement(Boolean.TRUE);
|
|
||||||
result.setOutput(1000);
|
|
||||||
}
|
|
||||||
userPool.addFirst(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
if (locked) {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package com.accompany.business.service.lucky;
|
package com.accompany.business.service.lucky;
|
||||||
|
|
||||||
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
|
||||||
import com.accompany.business.dto.lucky.Lucky25Result;
|
import com.accompany.business.dto.lucky.Lucky25Result;
|
||||||
import com.accompany.common.redis.RedisKey;
|
import com.accompany.common.redis.RedisKey;
|
||||||
import com.accompany.common.utils.DateTimeUtil;
|
import com.accompany.common.utils.DateTimeUtil;
|
||||||
@@ -26,9 +25,13 @@ public class Lucky25UserMetaService {
|
|||||||
public static final String INPUT_KEY = "input";
|
public static final String INPUT_KEY = "input";
|
||||||
public static final String OUTPUT_KEY = "output";
|
public static final String OUTPUT_KEY = "output";
|
||||||
|
|
||||||
|
private static final String POOL_TYPE = "pool_type";
|
||||||
|
|
||||||
private static final String TODAY = "today";
|
private static final String TODAY = "today";
|
||||||
|
|
||||||
private static final int HISTORY_QUEUE_SIZE = 40000;
|
public static final String ADMIN_1000_NUM_KEY = "admin_1000_num";
|
||||||
|
|
||||||
|
private static final BigDecimal HISTORY_QUEUE_INPUT_MAX = BigDecimal.valueOf(100000L);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedissonClient redissonClient;
|
private RedissonClient redissonClient;
|
||||||
@@ -39,33 +42,21 @@ public class Lucky25UserMetaService {
|
|||||||
|
|
||||||
public BigDecimal getUserLast2000ProductionRatio(Long uid) {
|
public BigDecimal getUserLast2000ProductionRatio(Long uid) {
|
||||||
RList<Lucky25Result> historyQueue = getUserHistoryQueue(uid);
|
RList<Lucky25Result> historyQueue = getUserHistoryQueue(uid);
|
||||||
int size = historyQueue.size();
|
//保留2000条记录
|
||||||
//保留20000条记录
|
int num = 2000;
|
||||||
int num = Math.min(size, 2000);
|
|
||||||
List<Lucky25Result> historyResult = historyQueue.range(num);
|
List<Lucky25Result> historyResult = historyQueue.range(num);
|
||||||
long historyInput = historyResult.stream().limit(num).mapToLong(Lucky25Result::getInput).sum();
|
long historyInput = historyResult.stream().limit(num).mapToLong(Lucky25Result::getInput).sum();
|
||||||
|
BigDecimal historyInputB = BigDecimal.valueOf(historyInput);
|
||||||
long historyOutput = historyResult.stream().limit(num).mapToLong(Lucky25Result::getOutput).sum();
|
long historyOutput = historyResult.stream().limit(num).mapToLong(Lucky25Result::getOutput).sum();
|
||||||
BigDecimal productionRatio = num > 0 ? BigDecimal.valueOf(historyOutput).divide(BigDecimal.valueOf(historyInput),2, RoundingMode.HALF_UP): BigDecimal.ZERO;
|
BigDecimal historyOutputB = BigDecimal.valueOf(historyOutput);
|
||||||
|
|
||||||
|
BigDecimal productionRatio = historyOutputB.compareTo(BigDecimal.ZERO) > 0 ?
|
||||||
|
historyOutputB.divide(historyInputB,2, RoundingMode.HALF_UP): BigDecimal.ZERO;
|
||||||
log.info("[lucky25] buildPool last2000 uid {}, historyInput {}, historyOutput {}, num {}, productionRatio {}",
|
log.info("[lucky25] buildPool last2000 uid {}, historyInput {}, historyOutput {}, num {}, productionRatio {}",
|
||||||
uid, historyInput, historyOutput, num, productionRatio);
|
uid, historyInput, historyOutput, num, productionRatio);
|
||||||
if (size > HISTORY_QUEUE_SIZE){
|
|
||||||
historyQueue.trim(0, HISTORY_QUEUE_SIZE);
|
|
||||||
}
|
|
||||||
return productionRatio;
|
return productionRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Lucky25Result> getUserLast10wHistory(Long uid) {
|
|
||||||
RList<Lucky25Result> historyQueue = getUserHistoryQueue(uid);
|
|
||||||
int size = historyQueue.size();
|
|
||||||
//保留20000条记录
|
|
||||||
int num = Math.min(size, HISTORY_QUEUE_SIZE);
|
|
||||||
List<Lucky25Result> historyResult = historyQueue.range(num);
|
|
||||||
if (size > HISTORY_QUEUE_SIZE){
|
|
||||||
historyQueue.trim(0, HISTORY_QUEUE_SIZE);
|
|
||||||
}
|
|
||||||
return historyResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getUserProductionRatio(Long uid) {
|
public BigDecimal getUserProductionRatio(Long uid) {
|
||||||
RMap<String, Number> userMetaMap = getUserMeta(uid);
|
RMap<String, Number> userMetaMap = getUserMeta(uid);
|
||||||
BigDecimal output = BigDecimal.valueOf(userMetaMap.getOrDefault(OUTPUT_KEY, 0L).longValue());
|
BigDecimal output = BigDecimal.valueOf(userMetaMap.getOrDefault(OUTPUT_KEY, 0L).longValue());
|
||||||
@@ -76,51 +67,21 @@ public class Lucky25UserMetaService {
|
|||||||
return productionRatio;
|
return productionRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean judgePersonalStock(Lucky25GiftConfig config, long senderUid, long receiverUid, long thisInput, long preWinGoldNum) {
|
|
||||||
if (preWinGoldNum < config.getPreJudgeValue_H()){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BigDecimal preWinGoldNumB = BigDecimal.valueOf(preWinGoldNum);
|
|
||||||
|
|
||||||
RMap<String, Number> userMetaMap = getUserMeta(senderUid);
|
|
||||||
BigDecimal input = BigDecimal.valueOf(userMetaMap.addAndGet(INPUT_KEY, thisInput).longValue());
|
|
||||||
BigDecimal output = BigDecimal.valueOf(userMetaMap.addAndGet(OUTPUT_KEY, preWinGoldNum).longValue());
|
|
||||||
BigDecimal inputOffset = input.compareTo(config.getTotalInput_J()) >= 0 ? config.getTotalInputOffset_K1() : config.getTotalInputOffset_K2();
|
|
||||||
|
|
||||||
BigDecimal beforeInput = input.subtract(BigDecimal.valueOf(thisInput));
|
|
||||||
BigDecimal beforeOutput = output.subtract(preWinGoldNumB);
|
|
||||||
BigDecimal personalStock = beforeInput.multiply(inputOffset).subtract(beforeOutput);
|
|
||||||
if (personalStock.compareTo(preWinGoldNumB) < 0){
|
|
||||||
userMetaMap.addAndGet(INPUT_KEY, -thisInput);
|
|
||||||
userMetaMap.addAndGet(OUTPUT_KEY, -preWinGoldNum);
|
|
||||||
log.info("[lucky25] personalStock false uid {} input {} J {} inputOffset {} output {} personalStock {} preWinGoldNum {} receiver {}",
|
|
||||||
senderUid, beforeInput, config.getTotalInput_J(), inputOffset, beforeOutput, personalStock, preWinGoldNum, receiverUid);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
userMetaMap.addAndGet(INPUT_KEY, -thisInput);
|
|
||||||
userMetaMap.addAndGet(OUTPUT_KEY, -preWinGoldNum);
|
|
||||||
log.info("[lucky25] personalStock true uid {} input {} J {} inputOffset {} output {} personalStock {} preWinGoldNum {} receiver {}",
|
|
||||||
senderUid, beforeInput, config.getTotalInput_J(), inputOffset, beforeOutput, personalStock, preWinGoldNum, receiverUid);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateUserMeta(long senderUid, int partitionId, long input, long output) {
|
public void updateUserMeta(long senderUid, int partitionId, long input, long output) {
|
||||||
RList<Lucky25Result> historyQueue = getUserHistoryQueue(senderUid);
|
RList<Lucky25Result> historyQueue = getUserHistoryQueue(senderUid);
|
||||||
historyQueue.add(0, new Lucky25Result(null, input, output, null));
|
historyQueue.add(0, new Lucky25Result(null, input, output, null));
|
||||||
historyQueue.expire(Duration.of(14, ChronoUnit.DAYS));
|
historyQueue.expire(Duration.of(14, ChronoUnit.DAYS));
|
||||||
|
|
||||||
if (output > 0L){
|
|
||||||
getUser10wStat(senderUid).delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
RMap<String, Number> userMetaMap = getUserMeta(senderUid);
|
RMap<String, Number> userMetaMap = getUserMeta(senderUid);
|
||||||
long times = userMetaMap.addAndGet(TIMES_KEY, 1L).longValue();
|
long times = userMetaMap.addAndGet(TIMES_KEY, 1L).longValue();
|
||||||
long totalInput = userMetaMap.addAndGet(INPUT_KEY, input).longValue();
|
//long totalInput = userMetaMap.addAndGet(INPUT_KEY, input).longValue();
|
||||||
long totalOutput = userMetaMap.addAndGet(OUTPUT_KEY, output).longValue();
|
long totalOutput = userMetaMap.addAndGet(OUTPUT_KEY, output).longValue();
|
||||||
|
|
||||||
log.info("[lucky25] updateUserMeta uid {} times {} totalInput {} totalOutput {}",
|
//log.info("[lucky25] updateUserMeta uid {} times {} totalInput {} totalOutput {}",
|
||||||
senderUid, times, totalInput, totalOutput);
|
// senderUid, times, totalInput, totalOutput);
|
||||||
|
|
||||||
|
log.info("[lucky25] updateUserMeta uid {} times {} totalOutput {}",
|
||||||
|
senderUid, times, totalOutput);
|
||||||
|
|
||||||
PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(partitionId);
|
PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(partitionId);
|
||||||
long todayStartTimeLong = DateTimeUtil.getZonedTodayTime(partitionEnum.getZoneId());
|
long todayStartTimeLong = DateTimeUtil.getZonedTodayTime(partitionEnum.getZoneId());
|
||||||
@@ -145,6 +106,32 @@ public class Lucky25UserMetaService {
|
|||||||
senderUid, times, todayStartTimeLong, todayInput, todayOutput);
|
senderUid, times, todayStartTimeLong, todayInput, todayOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int subAdminTicketNum(long uid, int superTicketNum) {
|
||||||
|
RMap<String, Number> userMetaMap = getUserMeta(uid);
|
||||||
|
int afterNum = userMetaMap.addAndGet(ADMIN_1000_NUM_KEY, -superTicketNum).intValue();
|
||||||
|
if (afterNum >= 0){
|
||||||
|
return superTicketNum;
|
||||||
|
}
|
||||||
|
for (int i = superTicketNum - 1; i > 0; i--) {
|
||||||
|
afterNum++;
|
||||||
|
if (afterNum >= 0){
|
||||||
|
int returnTicketNum = superTicketNum - i;
|
||||||
|
int userTicketNumAfterReturn = userMetaMap.addAndGet(ADMIN_1000_NUM_KEY, returnTicketNum).intValue();
|
||||||
|
log.info("[lucky25] subAdminTicketNum uid {} not enough ticket num, return {} after {}", uid, returnTicketNum, userTicketNumAfterReturn);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int userTicketNumAfterReturn = userMetaMap.addAndGet(ADMIN_1000_NUM_KEY, superTicketNum).intValue();
|
||||||
|
log.info("[lucky25] subAdminTicketNum uid {} not enough ticket num, return all {} after {}", uid, superTicketNum, userTicketNumAfterReturn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateUserMulti(Long uid) {
|
||||||
|
RMap<String, Number> userMetaMap = getUserMeta(uid);
|
||||||
|
int remainNum = userMetaMap.addAndGet(ADMIN_1000_NUM_KEY, 1).intValue();
|
||||||
|
log.info("[lucky25] admin send 1000 multi to uid {} remainNum {}", uid, remainNum);
|
||||||
|
}
|
||||||
|
|
||||||
public RMap<String, Number> getUserMeta(Long uid) {
|
public RMap<String, Number> getUserMeta(Long uid) {
|
||||||
return redissonClient.getMap(RedisKey.lucky_25_user_meta.getKey(uid.toString()));
|
return redissonClient.getMap(RedisKey.lucky_25_user_meta.getKey(uid.toString()));
|
||||||
}
|
}
|
||||||
@@ -153,8 +140,4 @@ public class Lucky25UserMetaService {
|
|||||||
return redissonClient.getList(RedisKey.lucky_25_user_history.getKey(uid.toString()));
|
return redissonClient.getList(RedisKey.lucky_25_user_history.getKey(uid.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public RMap<String, Number> getUser10wStat(Long uid) {
|
|
||||||
return redissonClient.getMapCache(RedisKey.lucky_25_user_10w_stat.getKey(uid.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package com.accompany.mq.consumer;
|
package com.accompany.mq.consumer;
|
||||||
|
|
||||||
import com.accompany.business.message.Lucky25Message;
|
import com.accompany.business.message.Lucky25Message;
|
||||||
import com.accompany.business.service.gift.Lucky25MessageService;
|
import com.accompany.business.service.gift.Lucky25MqService;
|
||||||
import com.accompany.mq.constant.MqConstant;
|
import com.accompany.mq.constant.MqConstant;
|
||||||
import com.accompany.mq.listener.AbstractMessageListener;
|
import com.accompany.mq.listener.AbstractMessageListener;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -17,12 +17,12 @@ import org.springframework.stereotype.Component;
|
|||||||
public class Lucky25MessageConsumer extends AbstractMessageListener<Lucky25Message> {
|
public class Lucky25MessageConsumer extends AbstractMessageListener<Lucky25Message> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private Lucky25MessageService messageService;
|
private Lucky25MqService messageService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(Lucky25Message giftMessage) {
|
public void onMessage(Lucky25Message giftMessage) {
|
||||||
log.info("onMessage lucky25Message: {}", giftMessage.toString());
|
log.info("onMessage lucky25Message: {}", giftMessage.toString());
|
||||||
messageService.handleGiftMessage(giftMessage);
|
messageService.handleMq(giftMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package com.accompany.scheduler.task.luckyBag;
|
package com.accompany.scheduler.task.luckyBag;
|
||||||
|
|
||||||
import com.accompany.business.message.Lucky25Message;
|
import com.accompany.business.message.Lucky25Message;
|
||||||
import com.accompany.business.service.gift.Lucky25MessageService;
|
import com.accompany.business.service.gift.Lucky25MqService;
|
||||||
import com.accompany.business.service.lucky.Lucky25RecordService;
|
import com.accompany.business.service.lucky.Lucky25RecordService;
|
||||||
import com.accompany.common.redis.RedisKey;
|
import com.accompany.common.redis.RedisKey;
|
||||||
import com.accompany.common.utils.DateTimeUtil;
|
import com.accompany.common.utils.DateTimeUtil;
|
||||||
@@ -37,7 +37,7 @@ public class Lucky25Task {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private JedisService jedisService;
|
private JedisService jedisService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private Lucky25MessageService messageService;
|
private Lucky25MqService mqService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重新消费队列的消息
|
* 重新消费队列的消息
|
||||||
@@ -58,7 +58,7 @@ public class Lucky25Task {
|
|||||||
String val = entry.getValue();
|
String val = entry.getValue();
|
||||||
Lucky25Message giftMessage = JSON.parseObject(val, Lucky25Message.class);
|
Lucky25Message giftMessage = JSON.parseObject(val, Lucky25Message.class);
|
||||||
if (curTime - giftMessage.getCreateTime() > gapTime) {
|
if (curTime - giftMessage.getCreateTime() > gapTime) {
|
||||||
messageService.handleGiftMessage(giftMessage);
|
mqService.handleMq(giftMessage);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("retryLucky25Queue error", e);
|
log.error("retryLucky25Queue error", e);
|
||||||
|
Reference in New Issue
Block a user