You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1437 lines
41 KiB
1437 lines
41 KiB
package dao |
|
|
|
import ( |
|
"context" |
|
"encoding/json" |
|
"fmt" |
|
"math/rand" |
|
"strconv" |
|
"sync" |
|
"time" |
|
|
|
v12 "go-common/app/service/live/rc/api/liverpc/v1" |
|
|
|
"github.com/pkg/errors" |
|
|
|
"go-common/app/service/live/xlottery/api/grpc/v1" |
|
"go-common/library/cache/redis" |
|
"go-common/library/database/sql" |
|
"go-common/library/log" |
|
"go-common/library/queue/databus/report" |
|
) |
|
|
|
const ( |
|
_userCapsuleCoinMysql = "select normal_score, colorful_score from capsule_%d where uid = ?" |
|
_addCapsuleCoinMysql = "insert into capsule_%d(uid, normal_score, colorful_score) values(?, ?, ?)" |
|
_userInfoMysql = "select score from capsule_info_%d where uid = ? and type = ?" |
|
_addInfoMysql = "insert into capsule_info_%d(uid,type,score) values(?, ?, ?)" |
|
_updateUserCapsuleMysql = "update capsule_%d set %s_score = %s_score + ? where uid = ?" |
|
_updateUserInfoMysql = "update capsule_info_%d set score = score + ? where uid = ? and type = ?" |
|
_transUserCapsuleMysql = "update capsule_%d set colorful_score = 0, normal_score = normal_score + ? where uid = ?" |
|
_reportCapsuleChangeMysql = "insert into capsule_log_%s(uid, type, score, action, platform, pre_normal_score, pre_colorful_score, cur_normal_score, cur_colorful_score) values(?,?,?,?,?,?,?,?,?)" |
|
_userCapsuleCoinRedis = "hash:capsule:user:%d" |
|
_userInfoRedis = "capsule:user:info:%d:%d" |
|
_openHistoryRedis = "list:capsule:%s:list" |
|
_openLockRedis = "capsule-pay-%d" |
|
_capsuleConfRand = "capsule:rand" |
|
_historyOpenCount = "hash:capsule:count" |
|
_historyGiftCount = "capsule:gift:count:%d:%s" |
|
_capsuleNotice = "capsule:notice:%s:%d" |
|
_whiteUserPrizeRedis = "capsule:white:user:%d" |
|
) |
|
const ( |
|
_ = iota |
|
// CapsulePrizeGift1Type 辣条 |
|
CapsulePrizeGift1Type // 辣条 |
|
// CapsulePrizeTitleType 头衔 |
|
CapsulePrizeTitleType |
|
// CapsulePrizeStuff1Type 经验原石 |
|
CapsulePrizeStuff1Type |
|
// CapsulePrizeStuff2Type 经验曜石 |
|
CapsulePrizeStuff2Type |
|
// CapsulePrizeStuff3Type 贤者之石 |
|
CapsulePrizeStuff3Type |
|
// CapsulePrizeSmallTvType 小电视 |
|
CapsulePrizeSmallTvType |
|
// CapsulePrizeGuard3Type 舰长体验 |
|
CapsulePrizeGuard3Type |
|
// CapsulePrizeGuard2Type 提督体验 |
|
CapsulePrizeGuard2Type |
|
// CapsulePrizeGuard1Type 总督体验 |
|
CapsulePrizeGuard1Type |
|
// CapsulePrizeScoreAdd 积分加成卡 |
|
CapsulePrizeScoreAdd |
|
// CapsulePrizeSmallStar 小星星 |
|
CapsulePrizeSmallStar |
|
// CapsulePrizeWeekScore 抽奖券 |
|
CapsulePrizeWeekScore |
|
// CapsulePrizeDanmuColor 弹幕颜色 |
|
CapsulePrizeDanmuColor |
|
// CapsulePrizeLplScore lpl抽奖券 |
|
CapsulePrizeLplScore |
|
// CapsulePrizeLplProduct1 lpl实物奖励1 |
|
CapsulePrizeLplProduct1 |
|
// CapsulePrizeLplProduct2 lpl实物奖励2 |
|
CapsulePrizeLplProduct2 |
|
// CapsulePrizeLplProduct3 lpl实物奖励3 |
|
CapsulePrizeLplProduct3 |
|
) |
|
|
|
const ( |
|
// CapsulePrizeProduct1 . |
|
CapsulePrizeProduct1 = 100000 // 实物奖励 |
|
// CapsulePrizeProduct2 . |
|
CapsulePrizeProduct2 = 100001 // 实物奖励 |
|
// CapsulePrizeProduct3 . |
|
CapsulePrizeProduct3 = 100002 |
|
// CapsulePrizeProduct4 . |
|
CapsulePrizeProduct4 = 100003 // 实物奖励 |
|
// CapsulePrizeProduct5 . |
|
CapsulePrizeProduct5 = 100004 // 实物奖励 |
|
// CapsulePrizeProduct6 . |
|
CapsulePrizeProduct6 = 100005 |
|
) |
|
|
|
const ( |
|
// CapsulePrizeCoupon1 . |
|
CapsulePrizeCoupon1 = 200000 |
|
// CapsulePrizeCoupon2 . |
|
CapsulePrizeCoupon2 = 200001 |
|
// CapsulePrizeCoupon3 . |
|
CapsulePrizeCoupon3 = 200002 |
|
) |
|
|
|
const ( |
|
// CapsulePrizeExpire1Day 过期时间24小时 |
|
CapsulePrizeExpire1Day = 1 |
|
// CapsulePrizeExpire3Day 过期时间72小时 |
|
CapsulePrizeExpire3Day = 10 |
|
// CapsulePrizeExpire1Week 过期时间1周 |
|
CapsulePrizeExpire1Week = 20 |
|
// CapsulePrizeExpire3Month 过期时间3个月 |
|
CapsulePrizeExpire3Month = 30 |
|
// CapsulePrizeExpireForever 过期时间永久 |
|
CapsulePrizeExpireForever = 100 |
|
) |
|
const ( |
|
_ = iota |
|
// ProTypeNormal 概率 |
|
ProTypeNormal |
|
// ProTypeFixDay 每天固定数量 |
|
ProTypeFixDay |
|
// ProTypeFixWeek 每周固定数量 |
|
ProTypeFixWeek |
|
// ProTypeWhite 白名单 |
|
ProTypeWhite |
|
) |
|
const ( |
|
// CapsuleGiftTypeAll gift_type 为全部道具 |
|
CapsuleGiftTypeAll = 1 |
|
) |
|
const ( |
|
// NormalCoinId 普通扭蛋id |
|
NormalCoinId = 1 |
|
// ColorfulCoinId 梦幻扭蛋id |
|
ColorfulCoinId = 2 |
|
// WeekCoinId 梦幻扭蛋id |
|
WeekCoinId = 3 |
|
// LplCoinId 梦幻扭蛋id |
|
LplCoinId = 4 |
|
// BlessCoinId 祈福券 |
|
BlessCoinId = 5 |
|
// OpenHistoryNum 开奖历史 |
|
OpenHistoryNum = 30 |
|
// NormalCoinString 普通扭蛋字符串标识,数据库和redis |
|
NormalCoinString = "normal" |
|
// ColorfulCoinString 梦幻扭蛋字符串标识,数据库和redis |
|
ColorfulCoinString = "colorful" |
|
// WeekCoinString 周星扭蛋字符串标识,数据库和redis |
|
WeekCoinString = "week" |
|
// LplCoinString lpl扭蛋字符串标识,数据库和redis |
|
LplCoinString = "lpl" |
|
// BlessCoinString 新年祈愿扭蛋字符串标识,数据库和redis |
|
BlessCoinString = "bless" |
|
// GetCapsuleDetailFromRoom 接口来源 |
|
GetCapsuleDetailFromRoom = "room" |
|
// GetCapsuleDetailFromWeb 接口来源 |
|
GetCapsuleDetailFromWeb = "web" |
|
// GetCapsuleDetailFromH5 接口来源 |
|
GetCapsuleDetailFromH5 = "h5" |
|
) |
|
|
|
const ( |
|
//IsBottomPool 是保底奖池 |
|
IsBottomPool = 1 |
|
//CapsuleActionTrans 转换扭蛋 |
|
CapsuleActionTrans = "trans" |
|
) |
|
|
|
// CapsuleConf 扭蛋全局配置 |
|
type CapsuleConf struct { |
|
CoinConfMap map[int64]*CapsuleCoinConf |
|
CacheTime int64 |
|
ChangeFlag int64 |
|
RwLock sync.RWMutex |
|
} |
|
|
|
// CapsuleCoinConf 扭蛋币配置 |
|
type CapsuleCoinConf struct { |
|
Id int64 |
|
Title string |
|
GiftType int64 |
|
ChangeNum int64 |
|
StartTime int64 |
|
EndTime int64 |
|
Status int64 |
|
GiftMap map[int64]struct{} |
|
AreaMap map[int64]struct{} |
|
PoolConf *CapsulePoolConf |
|
AllPoolConf []*CapsulePoolConf |
|
} |
|
|
|
// CapsulePoolConf 奖池配置 |
|
type CapsulePoolConf struct { |
|
Id int64 |
|
CoinId int64 |
|
Title string |
|
Rule string |
|
StartTime, EndTime int64 |
|
Status int64 |
|
IsBottom int64 |
|
PoolPrize []*CapsulePoolPrize |
|
} |
|
|
|
// CapsulePoolPrize 奖池奖品 |
|
type CapsulePoolPrize struct { |
|
Id, PoolId, Type, Num, ObjectId, Expire int64 |
|
Name, WebImage, MobileImage, Description, JumpUrl string |
|
ProType int64 |
|
Chance int64 |
|
LoopNum, LimitNum, Weight int64 |
|
WhiteUserMap map[int64]struct{} |
|
} |
|
|
|
// HistoryOpenInfo 开奖历史 |
|
type HistoryOpenInfo struct { |
|
Uid int64 `json:"uid"` |
|
Name string `json:"name"` |
|
Date string `json:"date"` |
|
Num int64 `json:"num"` |
|
} |
|
|
|
var ( |
|
// CoinIdIntMap map |
|
CoinIdIntMap map[int64]string |
|
// CoinIdStringMap map |
|
CoinIdStringMap map[string]int64 |
|
// ReprotConfig map |
|
ReprotConfig map[int64]string |
|
// PrizeNameMap map |
|
PrizeNameMap map[int64]string |
|
// PrizeExpireMap map |
|
PrizeExpireMap map[int64]string |
|
// UnLockGetWrong flag |
|
UnLockGetWrong = "UnLockGetWrong" |
|
// ErrUnLockGet error |
|
ErrUnLockGet = errors.New(UnLockGetWrong) |
|
capsuleConf CapsuleConf |
|
whitePrizeMap sync.Map |
|
) |
|
|
|
func init() { |
|
CoinIdIntMap = make(map[int64]string) |
|
CoinIdIntMap[NormalCoinId] = NormalCoinString |
|
CoinIdIntMap[ColorfulCoinId] = ColorfulCoinString |
|
CoinIdIntMap[WeekCoinId] = WeekCoinString |
|
CoinIdIntMap[LplCoinId] = LplCoinString |
|
CoinIdIntMap[BlessCoinId] = BlessCoinString |
|
CoinIdStringMap = make(map[string]int64) |
|
CoinIdStringMap[NormalCoinString] = NormalCoinId |
|
CoinIdStringMap[ColorfulCoinString] = ColorfulCoinId |
|
CoinIdStringMap[WeekCoinString] = WeekCoinId |
|
CoinIdStringMap[LplCoinString] = LplCoinId |
|
CoinIdStringMap[BlessCoinString] = BlessCoinId |
|
ReprotConfig = make(map[int64]string) |
|
ReprotConfig[0] = "未知" |
|
ReprotConfig[1] = "增加普通扭蛋" |
|
ReprotConfig[2] = "增加梦幻扭蛋" |
|
ReprotConfig[3] = "减少普通扭蛋" |
|
ReprotConfig[4] = "减少梦幻扭蛋" |
|
ReprotConfig[5] = "梦幻转化普通" |
|
PrizeNameMap = make(map[int64]string) |
|
PrizeNameMap[CapsulePrizeGift1Type] = "辣条" |
|
PrizeNameMap[CapsulePrizeTitleType] = "头衔" |
|
PrizeNameMap[CapsulePrizeStuff1Type] = "经验原石" |
|
PrizeNameMap[CapsulePrizeStuff2Type] = "经验曜石" |
|
PrizeNameMap[CapsulePrizeStuff3Type] = "贤者之石" |
|
PrizeNameMap[CapsulePrizeSmallTvType] = "小电视抱枕" |
|
PrizeNameMap[CapsulePrizeGuard3Type] = "舰长体验" |
|
PrizeNameMap[CapsulePrizeGuard2Type] = "提督体验" |
|
PrizeNameMap[CapsulePrizeScoreAdd] = "积分加成卡" |
|
PrizeNameMap[CapsulePrizeSmallStar] = "小星星" |
|
PrizeNameMap[CapsulePrizeWeekScore] = "抽奖券" |
|
PrizeNameMap[CapsulePrizeDanmuColor] = "金色弹幕" |
|
PrizeNameMap[CapsulePrizeLplScore] = "LPL抽奖券" |
|
PrizeNameMap[CapsulePrizeLplProduct1] = "2019拜年祭小电视猪" |
|
PrizeNameMap[CapsulePrizeLplProduct2] = "小电视毛绒公仔" |
|
PrizeNameMap[CapsulePrizeLplProduct3] = "机械之心桌垫" |
|
PrizeNameMap[CapsulePrizeProduct1] = "迎新礼盒+新年台历" |
|
PrizeNameMap[CapsulePrizeProduct2] = "新年锦鲤围巾" |
|
PrizeNameMap[CapsulePrizeProduct3] = "拜年祭挂件+拜年祭立牌+年夜饭挂画" |
|
PrizeNameMap[CapsulePrizeProduct4] = "拜年祭耳罩" |
|
PrizeNameMap[CapsulePrizeProduct5] = "小电视猪挂件+小电视猪公仔" |
|
PrizeNameMap[CapsulePrizeProduct6] = "拜年祭徽章" |
|
PrizeNameMap[CapsulePrizeCoupon1] = "会员购20元优惠券" |
|
PrizeNameMap[CapsulePrizeCoupon2] = "会员购40元优惠券" |
|
PrizeNameMap[CapsulePrizeCoupon3] = "会员购60元优惠券" |
|
PrizeExpireMap = make(map[int64]string) |
|
PrizeExpireMap[CapsulePrizeExpire1Day] = "1天" |
|
PrizeExpireMap[CapsulePrizeExpire3Day] = "3天" |
|
PrizeExpireMap[CapsulePrizeExpire1Week] = "1周" |
|
PrizeExpireMap[CapsulePrizeExpire3Month] = "3个月" |
|
PrizeExpireMap[CapsulePrizeExpireForever] = "永久" |
|
} |
|
|
|
// GetCapsuleConf 获取扭蛋币配置 |
|
func (d *Dao) GetCapsuleConf(ctx context.Context) (conf map[int64]*CapsuleCoinConf, err error) { |
|
capsuleConf.RwLock.RLock() |
|
tmpConf := capsuleConf.CoinConfMap |
|
capsuleConf.RwLock.RUnlock() |
|
if len(tmpConf) == 0 { |
|
redisChangeFlag, _ := d.GetCapsuleChangeFlag(ctx) |
|
tmpConf, err = d.RelaodCapsuleConfig(ctx, redisChangeFlag) |
|
if err != nil || tmpConf == nil || len(tmpConf) == 0 { |
|
log.Error("[dap.capsule | GetCapsuleConf] CapsuleCoinConf is empty") |
|
return nil, err |
|
} |
|
} |
|
now := time.Now().Unix() |
|
conf = make(map[int64]*CapsuleCoinConf) |
|
for coinId := range CoinIdIntMap { |
|
if _, ok := tmpConf[coinId]; ok { |
|
coinConf := tmpConf[coinId] |
|
if coinConf.AllPoolConf != nil && len(coinConf.AllPoolConf) > 0 { |
|
for _, poolConf := range coinConf.AllPoolConf { |
|
if poolConf.StartTime < now && poolConf.EndTime > now { |
|
if _, ok := conf[coinId]; !ok { |
|
conf[coinId] = &CapsuleCoinConf{ |
|
Id: coinConf.Id, |
|
Title: coinConf.Title, |
|
GiftType: coinConf.GiftType, |
|
ChangeNum: coinConf.ChangeNum, |
|
StartTime: coinConf.StartTime, |
|
EndTime: coinConf.EndTime, |
|
Status: coinConf.Status, |
|
GiftMap: coinConf.GiftMap, |
|
AreaMap: coinConf.AreaMap, |
|
PoolConf: poolConf, |
|
AllPoolConf: coinConf.AllPoolConf, |
|
} |
|
} else { |
|
if poolConf.IsBottom != IsBottomPool { |
|
conf[coinId] = &CapsuleCoinConf{ |
|
Id: coinConf.Id, |
|
Title: coinConf.Title, |
|
GiftType: coinConf.GiftType, |
|
ChangeNum: coinConf.ChangeNum, |
|
StartTime: coinConf.StartTime, |
|
EndTime: coinConf.EndTime, |
|
Status: coinConf.Status, |
|
GiftMap: coinConf.GiftMap, |
|
AreaMap: coinConf.AreaMap, |
|
PoolConf: poolConf, |
|
AllPoolConf: coinConf.AllPoolConf, |
|
} |
|
} |
|
} |
|
} |
|
|
|
} |
|
} |
|
} |
|
} |
|
return conf, nil |
|
} |
|
|
|
func getCapsuleTable(Uid int64) int64 { |
|
return Uid % 10 |
|
} |
|
|
|
func userKey(uid int64) string { |
|
return fmt.Sprintf(_userCapsuleCoinRedis, uid) |
|
} |
|
|
|
func userInfoKey(uid int64, coinId int64) string { |
|
return fmt.Sprintf(_userInfoRedis, uid, coinId) |
|
} |
|
|
|
func openHistoryKey(coinType string) string { |
|
return fmt.Sprintf(_openHistoryRedis, coinType) |
|
} |
|
|
|
func openTotalCountKey() string { |
|
return _historyOpenCount |
|
} |
|
|
|
func openGiftCountKey(giftId int64, day string) string { |
|
return fmt.Sprintf(_historyGiftCount, giftId, day) |
|
} |
|
|
|
func whiteUserPrizeKey(uid int64) string { |
|
return fmt.Sprintf(_whiteUserPrizeRedis, uid) |
|
} |
|
|
|
// GetUserCapsuleInfo 获取扭蛋币积分 |
|
func (d *Dao) GetUserCapsuleInfo(c context.Context, uid int64) (coinMap map[int64]int64, err error) { |
|
var ( |
|
isEmpty bool |
|
uKey string |
|
normalScore int64 |
|
colorfulScore int64 |
|
) |
|
uKey = userKey(uid) |
|
|
|
conn := d.redis.Get(c) |
|
defer conn.Close() |
|
uInfo, err := redis.Int64Map(conn.Do("HGETALL", uKey)) |
|
if err != nil { |
|
if err == redis.ErrNil { |
|
isEmpty = true |
|
err = nil |
|
} else { |
|
log.Error("[dao.redis_lottery|setUserCapsuleInfoCache] getUserCapsuleInfoCache conn.HMGET(%s) error(%v)", uKey, err) |
|
return |
|
} |
|
|
|
} else if len(uInfo) == 0 { |
|
isEmpty = true |
|
} |
|
coinMap = make(map[int64]int64) |
|
if isEmpty { |
|
sqlStr := fmt.Sprintf(_userCapsuleCoinMysql, getCapsuleTable(uid)) |
|
row := d.db.QueryRow(c, sqlStr, uid) |
|
err = row.Scan(&normalScore, &colorfulScore) |
|
if err != nil && err != sql.ErrNoRows { |
|
return |
|
} |
|
if err == sql.ErrNoRows { |
|
sqlStr := fmt.Sprintf(_addCapsuleCoinMysql, getCapsuleTable(uid)) |
|
_, err = d.db.Exec(c, sqlStr, uid, 0, 0) |
|
if err != nil { |
|
log.Error("[dao.redis_lottery|GetUserCapsuleInfo] init sql(%s) uid(%d) error(%v)", sqlStr, uid, err) |
|
return |
|
} |
|
normalScore, colorfulScore = 0, 0 |
|
} |
|
_, err = conn.Do("HMSET", uKey, CoinIdIntMap[NormalCoinId], normalScore, CoinIdIntMap[ColorfulCoinId], colorfulScore) |
|
if err != nil { |
|
log.Error("[dao.redis_lottery|GetUserCapsuleInfo] setUserCapsuleInfoCache conn.HMSET(%s) error(%v)", uKey, err) |
|
} |
|
coinMap[NormalCoinId] = normalScore |
|
coinMap[ColorfulCoinId] = colorfulScore |
|
err = nil |
|
} else { |
|
if _, ok := uInfo[CoinIdIntMap[NormalCoinId]]; ok { |
|
coinMap[NormalCoinId] = uInfo[CoinIdIntMap[NormalCoinId]] |
|
} |
|
if _, ok := uInfo[CoinIdIntMap[ColorfulCoinId]]; ok { |
|
coinMap[ColorfulCoinId] = uInfo[CoinIdIntMap[ColorfulCoinId]] |
|
} |
|
} |
|
return |
|
} |
|
|
|
// GetUserInfo 获取扭蛋币详情 |
|
func (d *Dao) GetUserInfo(c context.Context, uid, coinId int64) (coinMap map[int64]int64, err error) { |
|
if coinId <= ColorfulCoinId { |
|
coinMap, err = d.GetUserCapsuleInfo(c, uid) |
|
return |
|
} |
|
var ( |
|
isEmpty bool |
|
uKey string |
|
score int64 |
|
) |
|
uKey = userInfoKey(uid, coinId) |
|
|
|
conn := d.redis.Get(c) |
|
defer conn.Close() |
|
score, err = redis.Int64(conn.Do("GET", uKey)) |
|
if err != nil { |
|
if err == redis.ErrNil { |
|
isEmpty = true |
|
err = nil |
|
} else { |
|
log.Error("[dao.redis_lottery|GetUserInfo] getUserInfoCache conn.HMGET(%s) error(%v)", uKey, err) |
|
return |
|
} |
|
|
|
} |
|
coinMap = make(map[int64]int64) |
|
if isEmpty { |
|
sqlStr := fmt.Sprintf(_userInfoMysql, getCapsuleTable(uid)) |
|
row := d.db.QueryRow(c, sqlStr, uid, CoinIdIntMap[coinId]) |
|
err = row.Scan(&score) |
|
if err != nil && err != sql.ErrNoRows { |
|
log.Error("[dao.redis_lottery|GetUserInfo] getUserInfoFromDB uid(%d) error(%v)", uid, err) |
|
return |
|
} |
|
if err == sql.ErrNoRows { |
|
sqlStr := fmt.Sprintf(_addInfoMysql, getCapsuleTable(uid)) |
|
_, err = d.db.Exec(c, sqlStr, uid, CoinIdIntMap[coinId], 0) |
|
if err != nil { |
|
log.Error("[dao.redis_lottery|GetUserInfo] init sql(%s) uid(%d) error(%v)", sqlStr, uid, err) |
|
return nil, err |
|
} |
|
score = 0 |
|
} |
|
_, err = conn.Do("SET", uKey, score) |
|
if err != nil { |
|
log.Error("[dao.redis_lottery|GetUserInfo] setUserCapsuleInfoCache conn.HMSET(%s) error(%v)", uKey, err) |
|
} |
|
coinMap[coinId] = score |
|
err = nil |
|
} else { |
|
coinMap[coinId] = score |
|
} |
|
return |
|
} |
|
|
|
// GetOpenHistory 获取扭蛋币历史 |
|
func (d *Dao) GetOpenHistory(c context.Context, coinType int64) (ret []*HistoryOpenInfo, err error) { |
|
hkey := openHistoryKey(CoinIdIntMap[coinType]) |
|
conn := d.redis.Get(c) |
|
defer conn.Close() |
|
jsons, err := redis.Strings(conn.Do("LRANGE", hkey, 0, OpenHistoryNum-1)) |
|
if err != nil { |
|
return |
|
} |
|
length := len(jsons) |
|
if length == 0 { |
|
return |
|
} |
|
ret = make([]*HistoryOpenInfo, length) |
|
for ix, jsonStr := range jsons { |
|
var openInfo HistoryOpenInfo |
|
json.Unmarshal([]byte(jsonStr), &openInfo) |
|
ret[ix] = &openInfo |
|
} |
|
return |
|
} |
|
|
|
// GetCoin 获取扭蛋数量 |
|
func (d *Dao) GetCoin(score int64, coinConf *CapsuleCoinConf) (coinNum int64) { |
|
if coinConf == nil || coinConf.ChangeNum == 0 { |
|
return 0 |
|
} |
|
coinNum = score / coinConf.ChangeNum |
|
return |
|
} |
|
|
|
// GetProgress 获取扭蛋币进度 |
|
func (d *Dao) GetProgress(score int64, coinConf *CapsuleCoinConf) (process *v1.Progress) { |
|
process = &v1.Progress{} |
|
if coinConf == nil || coinConf.ChangeNum == 0 { |
|
return |
|
} |
|
process.Max = coinConf.ChangeNum |
|
process.Now = score % coinConf.ChangeNum |
|
return |
|
} |
|
|
|
// UpdateScore 更新扭蛋币积分 |
|
func (d *Dao) UpdateScore(ctx context.Context, uid, coinId, score int64, action, platform string, coinConf *CapsuleCoinConf) (affect int64, err error) { |
|
var ( |
|
sqlStr, uKey, iKey string |
|
) |
|
if action == CapsuleActionTrans { |
|
sqlStr = fmt.Sprintf(_transUserCapsuleMysql, getCapsuleTable(uid)) |
|
} else { |
|
sqlStr = fmt.Sprintf(_updateUserCapsuleMysql, getCapsuleTable(uid), CoinIdIntMap[coinId], CoinIdIntMap[coinId]) |
|
} |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
uKey = userKey(uid) |
|
iKey = userInfoKey(uid, coinId) |
|
log.Info("trace UpdateScore start") |
|
affect, err = d.execSqlWithBindParams(ctx, &sqlStr, score, uid) |
|
log.Info("trace UpdateScore end") |
|
if err != nil { |
|
log.Error("[dao.mysql_lottery|updateScore] uid(%d) type(%d) score(%d) error(%v)", uid, coinId, score, err) |
|
_, e := conn.Do("DEL", uKey, iKey) |
|
if e != nil { |
|
log.Error("[dao.redis_lottery|updateScore] conn.DEL(%s, %s) error(%v)", uKey, iKey, e) |
|
} |
|
return |
|
} |
|
_, e := conn.Do("DEL", uKey, iKey) |
|
if e != nil { |
|
log.Error("[dao.redis_lottery|updateScore] conn.DEL(%s, %s) error(%v)", uKey, iKey, e) |
|
} |
|
return |
|
} |
|
|
|
// UpdateCapsule 更新扭蛋币积分 |
|
func (d *Dao) UpdateCapsule(ctx context.Context, uid, coinId, score int64, action, platform string, coinConf *CapsuleCoinConf) (affect int64, err error) { |
|
var ( |
|
sqlStr, uKey, iKey string |
|
) |
|
sqlStr = fmt.Sprintf(_updateUserInfoMysql, getCapsuleTable(uid)) |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
uKey = userKey(uid) |
|
iKey = userInfoKey(uid, coinId) |
|
log.Info("trace UpdateCapsule start") |
|
affect, err = d.execSqlWithBindParams(ctx, &sqlStr, score, uid, CoinIdIntMap[coinId]) |
|
log.Info("trace UpdateCapsule end") |
|
if err != nil { |
|
log.Error("[dao.mysql_lottery|UpdateCapsule] uid(%d) type(%d) score(%d) error(%v)", uid, coinId, score, err) |
|
_, e := conn.Do("DEL", uKey, iKey) |
|
if e != nil { |
|
log.Error("[dao.redis_lottery|UpdateCapsule] conn.DEL(%s, %s) error(%v)", uKey, iKey, e) |
|
} |
|
return |
|
} |
|
_, e := conn.Do("DEL", uKey, iKey) |
|
if e != nil { |
|
log.Error("[dao.redis_lottery|UpdateCapsule] conn.DEL(%s, %s) error(%v)", uKey, iKey, e) |
|
} |
|
return |
|
} |
|
|
|
// ReportCapsuleChange 扭蛋流水 |
|
func (d *Dao) ReportCapsuleChange(ctx context.Context, coinId, uid, score int64, action, platform string, pInfo, cInfo map[int64]int64, coinConf *CapsuleCoinConf) bool { |
|
if _, ok := pInfo[coinId]; !ok { |
|
return false |
|
} |
|
if _, ok := cInfo[coinId]; !ok { |
|
return false |
|
} |
|
chnageType := coinId |
|
change := d.GetCoin(cInfo[coinId], coinConf) - d.GetCoin(pInfo[coinId], coinConf) |
|
if change > 0 { |
|
d.AddNotice(ctx, uid, coinId, change) |
|
} |
|
var normalPreScore, colorPreScore, normalNowScore, colorNowScore int64 |
|
if coinId <= ColorfulCoinId { |
|
if action == CapsuleActionTrans { |
|
chnageType = 5 |
|
} else { |
|
if score < 0 { |
|
chnageType += 2 |
|
score = -score |
|
} |
|
} |
|
normalPreScore, colorPreScore, normalNowScore, colorNowScore = pInfo[NormalCoinId], pInfo[ColorfulCoinId], cInfo[NormalCoinId], cInfo[ColorfulCoinId] |
|
} else { |
|
chnageType = coinId * 10 |
|
if score < 0 { |
|
chnageType += 1 |
|
} |
|
normalPreScore, colorPreScore, normalNowScore, colorNowScore = 0, pInfo[coinId], 0, cInfo[coinId] |
|
} |
|
|
|
date := time.Now().Format("200601") |
|
sqlStr := fmt.Sprintf(_reportCapsuleChangeMysql, date) |
|
affect, _ := d.execSqlWithBindParams(ctx, &sqlStr, uid, chnageType, score, action, platform, normalPreScore, colorPreScore, normalNowScore, colorNowScore) |
|
var rcontent string |
|
if _, ok := ReprotConfig[chnageType]; ok { |
|
rcontent = ReprotConfig[chnageType] |
|
} |
|
if rcontent == "" { |
|
if chnageType%10 == 0 { |
|
rcontent = "减少" + coinConf.Title |
|
} else if chnageType%10 == 1 { |
|
rcontent = "增加" + coinConf.Title |
|
} else if chnageType%10 == 2 { |
|
rcontent = "转化" + coinConf.Title |
|
} |
|
} |
|
report.User(&report.UserInfo{ |
|
Platform: platform, |
|
Business: 101, // 101 102 103 104 105 106 |
|
Type: int(chnageType), |
|
Oid: uid, |
|
Action: "capsule_change", |
|
Ctime: time.Now(), |
|
Index: []interface{}{ |
|
rcontent, |
|
score, |
|
normalNowScore, |
|
colorNowScore, |
|
action, |
|
}, |
|
}) |
|
return affect > 0 |
|
} |
|
|
|
// PayCoin 支付扭蛋币 |
|
func (d *Dao) PayCoin(ctx context.Context, uid int64, coinConf *CapsuleCoinConf, openCount int64, action, platform string) (status int64, pInfo map[int64]int64, err error) { |
|
lockKey := fmt.Sprintf(_openLockRedis, uid) |
|
isGetLock, lockString, err := d.Lock(ctx, lockKey, 10000, 0, 0) |
|
if err != nil || !isGetLock { |
|
return |
|
} |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
userData, err := d.GetUserInfo(ctx, uid, coinConf.Id) |
|
if err != nil { |
|
d.UnLock(ctx, lockKey, lockString) |
|
return |
|
} |
|
var score int64 |
|
if _, ok := userData[coinConf.Id]; ok { |
|
score = userData[coinConf.Id] |
|
} |
|
coinNum := d.GetCoin(score, coinConf) |
|
if coinNum < openCount { |
|
d.UnLock(ctx, lockKey, lockString) |
|
return 1, userData, nil |
|
|
|
} |
|
value := openCount * coinConf.ChangeNum |
|
_, err = d.UpdateScore(ctx, uid, coinConf.Id, -value, action, platform, coinConf) |
|
if err != nil { |
|
d.UnLock(ctx, lockKey, lockString) |
|
return |
|
} |
|
d.UnLock(ctx, lockKey, lockString) |
|
return 0, userData, nil |
|
} |
|
|
|
// PayCapsule 支付扭蛋币 |
|
func (d *Dao) PayCapsule(ctx context.Context, uid int64, coinConf *CapsuleCoinConf, openCount int64, action, platform string) (status int64, pInfo map[int64]int64, err error) { |
|
lockKey := fmt.Sprintf(_openLockRedis, uid) |
|
isGetLock, lockString, err := d.Lock(ctx, lockKey, 10000, 0, 0) |
|
if err != nil { |
|
return |
|
} |
|
if !isGetLock { |
|
return 1, nil, nil |
|
} |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
userData, err := d.GetUserInfo(ctx, uid, coinConf.Id) |
|
if err != nil { |
|
d.UnLock(ctx, lockKey, lockString) |
|
return |
|
} |
|
var score int64 |
|
if _, ok := userData[coinConf.Id]; ok { |
|
score = userData[coinConf.Id] |
|
} |
|
coinNum := d.GetCoin(score, coinConf) |
|
if coinNum < openCount { |
|
d.UnLock(ctx, lockKey, lockString) |
|
return 2, userData, nil |
|
|
|
} |
|
value := openCount * coinConf.ChangeNum |
|
_, err = d.UpdateCapsule(ctx, uid, coinConf.Id, -value, action, platform, coinConf) |
|
if err != nil { |
|
d.UnLock(ctx, lockKey, lockString) |
|
return |
|
} |
|
d.UnLock(ctx, lockKey, lockString) |
|
return 0, userData, nil |
|
} |
|
|
|
// IsPoolOpen 判断扭蛋池是否开启 |
|
func (d *Dao) IsPoolOpen(coinConf *CapsuleCoinConf, coinId int64) bool { |
|
if coinConf == nil { |
|
return false |
|
} |
|
if coinConf.PoolConf == nil || len(coinConf.PoolConf.PoolPrize) == 0 { |
|
return false |
|
} |
|
now := time.Now().Unix() |
|
if coinConf.PoolConf.StartTime < now && coinConf.PoolConf.EndTime > now { |
|
return true |
|
} |
|
return false |
|
} |
|
|
|
// GetGift 获取扭蛋奖池奖品 |
|
func (d *Dao) GetGift(ctx context.Context, coinId int64) (gift []*CapsulePoolPrize, err error) { |
|
coinConfMap, err := d.GetCapsuleConf(ctx) |
|
if err != nil || len(coinConfMap) == 0 { |
|
return |
|
} |
|
if _, ok := coinConfMap[coinId]; !ok { |
|
return |
|
} |
|
conf := coinConfMap[coinId] |
|
if conf.PoolConf == nil || len(conf.PoolConf.PoolPrize) == 0 { |
|
return |
|
} |
|
gift = conf.PoolConf.PoolPrize |
|
return |
|
} |
|
|
|
// IncrOpenCount 增加开奖次数 |
|
func (d *Dao) IncrOpenCount(ctx context.Context, coinId int64) (cnt int64) { |
|
hkey := openTotalCountKey() |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
cnt, err := redis.Int64(conn.Do("HINCRBY", hkey, CoinIdIntMap[coinId], 1)) |
|
if err != nil { |
|
return |
|
} |
|
if cnt > 0 { |
|
return cnt |
|
} |
|
return 0 |
|
} |
|
|
|
// GetOpenCount 获取开奖次数 |
|
func (d *Dao) GetOpenCount(ctx context.Context, coinId int64) (cnt int64) { |
|
hkey := openTotalCountKey() |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
cnt, err := redis.Int64(conn.Do("HGET", hkey, CoinIdIntMap[coinId])) |
|
if err != nil { |
|
return 0 |
|
} |
|
if cnt > 0 { |
|
return cnt |
|
} |
|
return 0 |
|
} |
|
|
|
func getWhiteGift(coinConf *CapsuleCoinConf) (fixPrize []*CapsulePoolPrize) { |
|
if coinConf == nil || coinConf.PoolConf == nil || len(coinConf.PoolConf.PoolPrize) == 0 { |
|
return |
|
} |
|
fLen := 0 |
|
for _, prize := range coinConf.PoolConf.PoolPrize { |
|
if prize.ProType == ProTypeWhite { |
|
fLen++ |
|
} |
|
} |
|
if fLen <= 0 { |
|
return |
|
} |
|
fixPrize = make([]*CapsulePoolPrize, fLen) |
|
fLen = 0 |
|
for _, prize := range coinConf.PoolConf.PoolPrize { |
|
if prize.ProType == ProTypeWhite { |
|
fixPrize[fLen] = prize |
|
fLen++ |
|
} |
|
} |
|
return |
|
} |
|
|
|
func getFixGift(coinConf *CapsuleCoinConf) (fixPrize []*CapsulePoolPrize) { |
|
if coinConf == nil || coinConf.PoolConf == nil || len(coinConf.PoolConf.PoolPrize) == 0 { |
|
return |
|
} |
|
fLen := 0 |
|
for _, prize := range coinConf.PoolConf.PoolPrize { |
|
if prize.ProType == ProTypeFixDay || prize.ProType == ProTypeFixWeek { |
|
fLen++ |
|
} |
|
} |
|
if fLen <= 0 { |
|
return |
|
} |
|
fixPrize = make([]*CapsulePoolPrize, fLen) |
|
fLen = 0 |
|
for _, prize := range coinConf.PoolConf.PoolPrize { |
|
if prize.ProType == ProTypeFixDay || prize.ProType == ProTypeFixWeek { |
|
fixPrize[fLen] = prize |
|
fLen++ |
|
} |
|
} |
|
return |
|
} |
|
|
|
func getRandomGift(coinConf *CapsuleCoinConf) (randomPrize []*CapsulePoolPrize) { |
|
if coinConf == nil || coinConf.PoolConf == nil || len(coinConf.PoolConf.PoolPrize) == 0 { |
|
return |
|
} |
|
rLen := 0 |
|
for _, prize := range coinConf.PoolConf.PoolPrize { |
|
if prize.ProType == ProTypeNormal { |
|
rLen++ |
|
} |
|
} |
|
if rLen <= 0 { |
|
return |
|
} |
|
randomPrize = make([]*CapsulePoolPrize, rLen) |
|
rLen = 0 |
|
for _, prize := range coinConf.PoolConf.PoolPrize { |
|
if prize.ProType == ProTypeNormal { |
|
randomPrize[rLen] = prize |
|
rLen++ |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (d *Dao) checkWhiteLimit(ctx context.Context, uid int64, prize *CapsulePoolPrize) bool { |
|
if prize == nil || prize.ProType != ProTypeWhite || len(prize.WhiteUserMap) == 0 { |
|
return false |
|
} |
|
if _, ok := prize.WhiteUserMap[uid]; !ok { |
|
return false |
|
} |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
dtime := time.Now() |
|
day := dtime.Format("2006-01-02") |
|
uKey := whiteUserPrizeKey(uid) |
|
lastTime, err := redis.Int64(conn.Do("GET", uKey)) |
|
if err != nil { |
|
if err == redis.ErrNil { |
|
// 回源数据库 |
|
prizeLog, err := d.GetUserPrizeLog(ctx, prize.Id, uid) |
|
if err != nil { |
|
return false |
|
} |
|
if prizeLog != nil { |
|
lastTime = prizeLog.Timestamp |
|
} else { |
|
lastTime = 0 |
|
} |
|
conn.Do("SET", uKey, lastTime, "EX", 30*86400) |
|
} else { |
|
return false |
|
} |
|
} |
|
if dtime.Unix()-lastTime < 7*86400 { |
|
return false |
|
} |
|
gKey := openGiftCountKey(prize.Id, day) |
|
isGetLock, lockString, errLock := d.Lock(ctx, gKey, 1000000, 0, 0) |
|
if errLock != nil || !isGetLock { |
|
return false |
|
} |
|
mKey := day + strconv.FormatInt(prize.Id, 10) |
|
_, ok := whitePrizeMap.Load(mKey) |
|
if ok { |
|
d.UnLock(ctx, gKey, lockString) |
|
return false |
|
} |
|
// 回源数据库 |
|
prizeLog, errDb := d.GetPrizeDayLog(ctx, prize.Id, day) |
|
if errDb != nil { |
|
d.UnLock(ctx, gKey, lockString) |
|
return false |
|
} |
|
if prizeLog != nil { |
|
whitePrizeMap.Store(mKey, prizeLog.Uid) |
|
d.UnLock(ctx, gKey, lockString) |
|
return false |
|
} |
|
stutus, errAdd := d.AddPrizeData(ctx, prize.Id, uid, day, dtime.Unix()) |
|
if errAdd != nil || !stutus { |
|
d.UnLock(ctx, gKey, lockString) |
|
return false |
|
} |
|
whitePrizeMap.Store(mKey, uid) |
|
conn.Do("DEL", uKey) |
|
d.UnLock(ctx, gKey, lockString) |
|
return true |
|
|
|
} |
|
|
|
func (d *Dao) checkPrizeLimit(ctx context.Context, prize *CapsulePoolPrize) bool { |
|
if prize == nil { |
|
return false |
|
} |
|
if prize.ProType != ProTypeFixDay && prize.ProType != ProTypeFixWeek { |
|
return false |
|
} |
|
|
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
var status bool |
|
switch prize.ProType { |
|
case ProTypeFixDay: |
|
day := time.Now().Format("2006-01-02") |
|
gKey := openGiftCountKey(prize.Id, day) |
|
cnt, err := redis.Int64(conn.Do("INCRBY", gKey, 1)) |
|
if err != nil { |
|
status = false |
|
break |
|
} |
|
status = cnt <= prize.LimitNum |
|
case ProTypeFixWeek: |
|
wDay := time.Now().Weekday() |
|
if wDay == 0 { |
|
wDay = 7 |
|
} |
|
diff := time.Duration(wDay) |
|
day := time.Now().Add(time.Second * 86400 * (diff - 1)).Format("2006-01-02") |
|
gKey := openGiftCountKey(prize.Id, day) |
|
cnt, err := redis.Int64(conn.Do("INCRBY", gKey, 1)) |
|
if err != nil { |
|
status = false |
|
break |
|
} |
|
status = cnt <= prize.LimitNum |
|
default: |
|
status = false |
|
} |
|
return status |
|
} |
|
|
|
func (d *Dao) getWhiteAward(ctx context.Context, uid int64, coinConf *CapsuleCoinConf) (prize *CapsulePoolPrize) { |
|
whitePrize := getWhiteGift(coinConf) |
|
if len(whitePrize) == 0 { |
|
return |
|
} |
|
openCount := d.GetOpenCount(ctx, coinConf.Id) |
|
if openCount == 0 { |
|
return |
|
} |
|
for _, wprize := range whitePrize { |
|
if !d.checkWhiteLimit(ctx, uid, wprize) { |
|
continue |
|
} |
|
return &CapsulePoolPrize{ |
|
Id: wprize.Id, |
|
PoolId: wprize.PoolId, |
|
Type: wprize.Type, |
|
Num: wprize.Num, |
|
Name: wprize.Name, |
|
WebImage: wprize.WebImage, |
|
MobileImage: wprize.MobileImage, |
|
Description: wprize.Description, |
|
ProType: wprize.ProType, |
|
JumpUrl: wprize.JumpUrl, |
|
ObjectId: wprize.ObjectId, |
|
Expire: wprize.Expire, |
|
Weight: wprize.Weight, |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (d *Dao) getFixAward(ctx context.Context, uid, openCount int64, coinConf *CapsuleCoinConf) (prize *CapsulePoolPrize) { |
|
fixPrize := getFixGift(coinConf) |
|
if len(fixPrize) == 0 { |
|
return |
|
} |
|
if openCount == 0 { |
|
return |
|
} |
|
var loop int64 |
|
for _, fprize := range fixPrize { |
|
loop = fprize.LoopNum |
|
if openCount%loop != 0 { |
|
continue |
|
} |
|
if d.checkPrizeLimit(ctx, fprize) { |
|
return &CapsulePoolPrize{ |
|
Id: fprize.Id, |
|
PoolId: fprize.PoolId, |
|
Type: fprize.Type, |
|
Num: fprize.Num, |
|
Name: fprize.Name, |
|
WebImage: fprize.WebImage, |
|
MobileImage: fprize.MobileImage, |
|
Description: fprize.Description, |
|
ProType: fprize.ProType, |
|
JumpUrl: fprize.JumpUrl, |
|
ObjectId: fprize.ObjectId, |
|
Expire: fprize.Expire, |
|
Weight: fprize.Weight, |
|
} |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (d *Dao) getRandomAward(ctx context.Context, uid int64, coinConf *CapsuleCoinConf) (prize *CapsulePoolPrize) { |
|
randomPrize := getRandomGift(coinConf) |
|
if len(randomPrize) == 0 { |
|
return |
|
} |
|
var start, random, total int64 |
|
for _, prize := range randomPrize { |
|
if prize == nil { |
|
rbyte, _ := json.Marshal(randomPrize) |
|
log.Error("[dao.capsule | getRandomAward] randomPrize error : %s", string(rbyte)) |
|
continue |
|
} |
|
total += prize.Chance |
|
} |
|
r := rand.New(rand.NewSource(time.Now().UnixNano())) |
|
random = r.Int63n(total - 1) |
|
for _, prize := range randomPrize { |
|
if random >= start && random < start+prize.Chance { |
|
return &CapsulePoolPrize{ |
|
Id: prize.Id, |
|
PoolId: prize.PoolId, |
|
Type: prize.Type, |
|
Num: prize.Num, |
|
Name: prize.Name, |
|
WebImage: prize.WebImage, |
|
MobileImage: prize.MobileImage, |
|
Description: prize.Description, |
|
ProType: prize.ProType, |
|
JumpUrl: prize.JumpUrl, |
|
ObjectId: prize.ObjectId, |
|
Expire: prize.Expire, |
|
Weight: prize.Weight, |
|
} |
|
} |
|
start += prize.Chance |
|
} |
|
return |
|
} |
|
|
|
// OpenCapsule 开启扭蛋 |
|
func (d *Dao) OpenCapsule(ctx context.Context, uid int64, coinConf *CapsuleCoinConf, iTime, openCount int64, isGetFixAward bool, entryMap map[int64]bool) (award *CapsulePoolPrize) { |
|
if iTime == 0 { |
|
award = d.getWhiteAward(ctx, uid, coinConf) |
|
if award != nil { |
|
return award |
|
} |
|
} |
|
if isGetFixAward { |
|
award = d.getFixAward(ctx, uid, openCount, coinConf) |
|
if award != nil { |
|
if _, ok := entryMap[award.Id]; !ok { |
|
return |
|
} |
|
} |
|
} |
|
award = d.getRandomAward(ctx, uid, coinConf) |
|
if award != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
// LogAward 记录抽奖奖励 |
|
func (d *Dao) LogAward(ctx context.Context, uid int64, coinId int64, awards []*CapsulePoolPrize) { |
|
if len(awards) == 0 { |
|
return |
|
} |
|
hkey := openHistoryKey(CoinIdIntMap[coinId]) |
|
day := time.Now().Format("2006-01-02") |
|
logs := make([]interface{}, len(awards)+1) |
|
logs[0] = hkey |
|
ll := 1 |
|
for _, award := range awards { |
|
if award.Type == CapsulePrizeGift1Type { |
|
continue |
|
} |
|
info := HistoryOpenInfo{Uid: uid, Name: award.Name, Num: award.Num, Date: day} |
|
b, err := json.Marshal(info) |
|
if err == nil { |
|
logs[ll] = string(b) |
|
ll++ |
|
} |
|
} |
|
if ll == 1 { |
|
return |
|
} |
|
logs = logs[0:ll] |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
conn.Do("LPUSH", logs...) |
|
} |
|
|
|
// AddNotice 增加标记 |
|
func (d *Dao) AddNotice(ctx context.Context, uid, coinId, coinNum int64) { |
|
nKey := fmt.Sprintf(_capsuleNotice, CoinIdIntMap[coinId], uid) |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
conn.Do("SET", nKey, coinNum, 30*86400) |
|
|
|
} |
|
|
|
// ClearNotice 清除标记 |
|
func (d *Dao) ClearNotice(ctx context.Context, uid, coinId int64) { |
|
nKey := fmt.Sprintf(_capsuleNotice, CoinIdIntMap[coinId], uid) |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
conn.Do("DEL", nKey) |
|
} |
|
|
|
// ClearNoticeBoth 清除标记 |
|
func (d *Dao) ClearNoticeBoth(ctx context.Context, uid int64) { |
|
keys := make([]interface{}, len(CoinIdIntMap)) |
|
var i = 0 |
|
for _, coinType := range CoinIdIntMap { |
|
keys[i] = fmt.Sprintf(_capsuleNotice, coinType, uid) |
|
} |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
conn.Do("DEL", keys...) |
|
} |
|
|
|
// GetChangeNum 获取扭蛋变化数量 |
|
func (d *Dao) GetChangeNum(ctx context.Context, uid, coinId int64) int64 { |
|
nKey := fmt.Sprintf(_capsuleNotice, CoinIdIntMap[coinId], uid) |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
change, err := redis.Int64(conn.Do("GET", nKey)) |
|
if err != nil { |
|
return 0 |
|
} |
|
return change |
|
} |
|
|
|
// SetCapsuleChangeFlag 设置扭蛋配置变化标记 |
|
func (d *Dao) SetCapsuleChangeFlag(ctx context.Context) (status string, err error) { |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
status, err = redis.String(conn.Do("SET", _capsuleConfRand, time.Now().Unix())) |
|
if err != nil { |
|
log.Error("[dao.capsule | SetCapsuleChangeFlag] redis set error : %v", err) |
|
return |
|
} |
|
return |
|
} |
|
|
|
// GetCapsuleChangeFlag 获取扭蛋配置变化标记 |
|
func (d *Dao) GetCapsuleChangeFlag(ctx context.Context) (changeFlag int64, err error) { |
|
conn := d.redis.Get(ctx) |
|
defer conn.Close() |
|
changeFlag, err = redis.Int64(conn.Do("GET", _capsuleConfRand)) |
|
if err != nil { |
|
return |
|
} |
|
return |
|
} |
|
|
|
// GetCapsuleChangeInfo 获取扭蛋配置信息 |
|
func (d *Dao) GetCapsuleChangeInfo(ctx context.Context) (int64, int64) { |
|
capsuleConf.RwLock.RLock() |
|
CacheTime := capsuleConf.CacheTime |
|
ChangeFlag := capsuleConf.ChangeFlag |
|
capsuleConf.RwLock.RUnlock() |
|
return CacheTime, ChangeFlag |
|
} |
|
|
|
// RelaodCapsuleConfig 重新加载扭蛋配置 |
|
func (d *Dao) RelaodCapsuleConfig(ctx context.Context, changeFlag int64) (conf map[int64]*CapsuleCoinConf, err error) { |
|
coinMap, err := d.GetCoinMap(ctx) |
|
if err != nil || len(coinMap) == 0 { |
|
log.Error("[dao.capsule | RelaodCapsuleConfig] coinMap is empty") |
|
return |
|
} |
|
coinIds := make([]int64, len(coinMap)) |
|
ix := 0 |
|
for _, coinInfo := range coinMap { |
|
coinIds[ix] = coinInfo.Id |
|
ix++ |
|
} |
|
coinConfigMap, err := d.GetCoinConfigMap(ctx, coinIds) |
|
if err != nil || len(coinConfigMap) == 0 { |
|
log.Error("[dao.capsule | RelaodCapsuleConfig] CoinConfigMap is empty") |
|
return |
|
} |
|
poolMap, err := d.GetPoolMap(ctx, coinIds) |
|
if err != nil || len(poolMap) == 0 { |
|
log.Error("[dao.capsule | RelaodCapsuleConfig] PoolMap is empty") |
|
return |
|
} |
|
poolIds := make([]int64, 0) |
|
for _, pools := range poolMap { |
|
for _, pool := range pools { |
|
poolIds = append(poolIds, pool.Id) |
|
} |
|
|
|
} |
|
poolPrizeMap, err := d.GetPoolPrizeMap(ctx, poolIds) |
|
if err != nil || len(poolPrizeMap) == 0 { |
|
log.Error("[dao.capsule | RelaodCapsuleConfig] PoolPrizeMap is empty") |
|
return |
|
} |
|
coinConfMap := make(map[int64]*CapsuleCoinConf) |
|
ids := make([]int64, 0) |
|
prizeIds := make([]int64, 0) |
|
idMap := make(map[int64]struct{}) |
|
for _, prizeList := range poolPrizeMap { |
|
for _, prize := range prizeList { |
|
if prize.ObjectId != 0 && prize.Type == CapsulePrizeTitleType { |
|
if _, ok := idMap[prize.ObjectId]; !ok { |
|
ids = append(ids, prize.ObjectId) |
|
idMap[prize.ObjectId] = struct{}{} |
|
} |
|
} |
|
prizeIds = append(prizeIds, prize.Id) |
|
} |
|
} |
|
prizeWhiteMap, err1 := d.GetWhiteUserMap(ctx, prizeIds) |
|
if err1 != nil { |
|
log.Error("[dao.capsule | RelaodCapsuleConfig] GetWhiteUserMap error") |
|
} |
|
titleMap := make(map[int64]string) |
|
if len(ids) != 0 { |
|
TitleData, err1 := RcApi.V1UserTitle.GetTitleByIds(ctx, &v12.UserTitleGetTitleByIdsReq{Ids: ids}) |
|
if err1 != nil { |
|
log.Error("[dao.capsule | RelaodCapsuleConfig] GetTitleByIds error") |
|
} |
|
if TitleData != nil && TitleData.Data != nil { |
|
titleMap = TitleData.Data |
|
} |
|
} |
|
for coinId, coinConf := range coinMap { |
|
conf := &CapsuleCoinConf{} |
|
conf.Status = coinConf.Status |
|
conf.GiftType = coinConf.GiftType |
|
conf.Title = coinConf.Title |
|
conf.EndTime = coinConf.EndTime |
|
conf.StartTime = coinConf.StartTime |
|
conf.Id = coinConf.Id |
|
conf.ChangeNum = coinConf.ChangeNum |
|
if _, ok := coinConfigMap[coinId]; ok { |
|
coinConfig := coinConfigMap[coinId] |
|
gifts := make(map[int64]struct{}) |
|
areas := make(map[int64]struct{}) |
|
for _, config := range coinConfig { |
|
if config.GiftId > 0 { |
|
gifts[config.GiftId] = struct{}{} |
|
} |
|
if config.AreaV2ParentId > 0 { |
|
areas[config.AreaV2Id] = struct{}{} |
|
} |
|
} |
|
conf.AreaMap = areas |
|
conf.GiftMap = gifts |
|
} |
|
if _, ok := poolMap[coinId]; ok { |
|
for _, poolConf := range poolMap[coinId] { |
|
pool := &CapsulePoolConf{} |
|
pool.Id = poolConf.Id |
|
pool.StartTime = poolConf.StartTime |
|
pool.EndTime = poolConf.EndTime |
|
pool.Title = poolConf.Title |
|
pool.Status = poolConf.Status |
|
pool.Rule = poolConf.Description |
|
pool.CoinId = poolConf.CoinId |
|
pool.IsBottom = poolConf.IsBottom |
|
if _, ok := poolPrizeMap[pool.Id]; ok { |
|
prizeConfigs := poolPrizeMap[pool.Id] |
|
pool.PoolPrize = make([]*CapsulePoolPrize, len(poolPrizeMap[pool.Id])) |
|
for ix, prizeConfig := range prizeConfigs { |
|
name := PrizeNameMap[prizeConfig.Type] |
|
if prizeConfig.Type == CapsulePrizeTitleType && titleMap != nil { |
|
if _, ok := titleMap[prizeConfig.ObjectId]; ok { |
|
name = titleMap[prizeConfig.ObjectId] |
|
} |
|
} |
|
prize := &CapsulePoolPrize{ |
|
Id: prizeConfig.Id, |
|
PoolId: prizeConfig.PoolId, |
|
Type: prizeConfig.Type, |
|
Num: prizeConfig.Num, |
|
ObjectId: prizeConfig.ObjectId, |
|
Expire: prizeConfig.Expire, |
|
Name: name, |
|
WebImage: prizeConfig.WebUrl, |
|
MobileImage: prizeConfig.MobileUrl, |
|
Description: prizeConfig.Description, |
|
JumpUrl: prizeConfig.JumpUrl, |
|
ProType: prizeConfig.ProType, |
|
Chance: prizeConfig.Chance, |
|
LoopNum: prizeConfig.LoopNum, |
|
LimitNum: prizeConfig.LimitNum, |
|
Weight: prizeConfig.Weight, |
|
} |
|
prize.WhiteUserMap = make(map[int64]struct{}) |
|
if prize.ProType == ProTypeWhite { |
|
if _, ok := prizeWhiteMap[prize.Id]; ok { |
|
if len(prizeWhiteMap[prize.Id]) > 0 { |
|
for _, wuid := range prizeWhiteMap[prize.Id] { |
|
prize.WhiteUserMap[wuid] = struct{}{} |
|
} |
|
} |
|
} |
|
} |
|
pool.PoolPrize[ix] = prize |
|
} |
|
} |
|
if conf.AllPoolConf == nil { |
|
conf.AllPoolConf = make([]*CapsulePoolConf, 0) |
|
} |
|
conf.AllPoolConf = append(conf.AllPoolConf, pool) |
|
} |
|
|
|
} |
|
coinConfMap[coinId] = conf |
|
} |
|
cacheTime := time.Now().Unix() |
|
capsuleConf.RwLock.Lock() |
|
capsuleConf.CacheTime = cacheTime |
|
capsuleConf.ChangeFlag = changeFlag |
|
capsuleConf.CoinConfMap = coinConfMap |
|
capsuleConf.RwLock.Unlock() |
|
log.Info("[dao.capsule | RelaodCapsuleConfig] reload conf") |
|
return coinConfMap, nil |
|
} |
|
|
|
// GetBottomPrize 获取保底奖品 |
|
func (d *Dao) GetBottomPrize(ctx context.Context, coinConf *CapsuleCoinConf) (bottomPrize *CapsulePoolPrize) { |
|
if coinConf == nil || coinConf.PoolConf == nil || len(coinConf.PoolConf.PoolPrize) == 0 { |
|
return nil |
|
} |
|
|
|
for _, prize := range coinConf.PoolConf.PoolPrize { |
|
if bottomPrize == nil || bottomPrize.Weight > prize.Weight { |
|
bottomPrize = &CapsulePoolPrize{ |
|
Id: prize.Id, |
|
PoolId: prize.PoolId, |
|
Type: prize.Type, |
|
Name: prize.Name, |
|
WebImage: prize.WebImage, |
|
MobileImage: prize.MobileImage, |
|
Description: prize.Description, |
|
ProType: prize.ProType, |
|
JumpUrl: prize.JumpUrl, |
|
ObjectId: prize.ObjectId, |
|
Expire: prize.Expire, |
|
Weight: prize.Weight, |
|
Num: prize.Num, |
|
} |
|
} |
|
} |
|
return bottomPrize |
|
} |
|
|
|
//GetExpireTime 获取过期时间 |
|
func (d *Dao) GetExpireTime(expire int64) time.Time { |
|
var td time.Time |
|
if expire == CapsulePrizeExpire1Day { |
|
year, month, day := time.Now().Date() |
|
td = time.Date(year, month, day, 0, 0, 0, 0, time.Now().Location()).Add(86400 * time.Second).Add(86400 * time.Second) |
|
} else if expire == CapsulePrizeExpire3Day { |
|
year, month, day := time.Now().Date() |
|
td = time.Date(year, month, day, 0, 0, 0, 0, time.Now().Location()).Add(86400 * time.Second).Add(3 * 86400 * time.Second) |
|
} else if expire == CapsulePrizeExpire1Week { |
|
year, month, day := time.Now().Date() |
|
td = time.Date(year, month, day, 0, 0, 0, 0, time.Now().Location()).Add(86400 * time.Second).Add(6 * 86400 * time.Second) |
|
} else if expire == CapsulePrizeExpire3Month { |
|
year, month, day := time.Now().Date() |
|
td = time.Date(year, month, day, 0, 0, 0, 0, time.Now().Location()).Add(86400 * time.Second).Add(90 * 86400 * time.Second) |
|
} else if expire == CapsulePrizeExpireForever { |
|
td = time.Unix(0, 0) |
|
} else { |
|
td = time.Unix(0, 0) |
|
} |
|
return td |
|
} |
|
|
|
// IsAwardEntry 是否是实物奖励 |
|
func (d *Dao) IsAwardEntry(awardType int64) bool { |
|
if awardType == CapsulePrizeSmallTvType || awardType == CapsulePrizeLplProduct1 || awardType == CapsulePrizeLplProduct2 || awardType == CapsulePrizeLplProduct3 { |
|
return true |
|
} |
|
if awardType >= CapsulePrizeProduct1 && awardType < CapsulePrizeCoupon1 { |
|
return true |
|
} |
|
return false |
|
} |
|
|
|
// IsAwardCoupon 是否是会员券 |
|
func (d *Dao) IsAwardCoupon(awardType int64) bool { |
|
return awardType >= CapsulePrizeCoupon1 |
|
}
|
|
|