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.
331 lines
8.3 KiB
331 lines
8.3 KiB
package bws |
|
|
|
import ( |
|
"context" |
|
"strconv" |
|
"time" |
|
|
|
"go-common/app/interface/main/activity/conf" |
|
"go-common/app/interface/main/activity/dao/bws" |
|
bwsmdl "go-common/app/interface/main/activity/model/bws" |
|
accapi "go-common/app/service/main/account/api" |
|
suitmdl "go-common/app/service/main/usersuit/model" |
|
suitrpc "go-common/app/service/main/usersuit/rpc/client" |
|
"go-common/library/ecode" |
|
"go-common/library/log" |
|
"go-common/library/sync/errgroup" |
|
"go-common/library/sync/pipeline/fanout" |
|
) |
|
|
|
const ( |
|
_accountBlocked = 1 |
|
_allType = 0 |
|
_dpType = 1 |
|
_gameType = 2 |
|
_clockinType = 3 |
|
_eggType = 4 |
|
_dp = "dp" |
|
_game = "game" |
|
_clockin = "clockin" |
|
_egg = "egg" |
|
_noAward = 0 |
|
_awardAlready = 2 |
|
_initLinkType = 5 |
|
) |
|
|
|
var ( |
|
_emptPoints = make([]*bwsmdl.Point, 0) |
|
_emptUserPoints = make([]*bwsmdl.UserPointDetail, 0) |
|
_emptyUserAchieves = make([]*bwsmdl.UserAchieveDetail, 0) |
|
) |
|
|
|
// Service struct |
|
type Service struct { |
|
c *conf.Config |
|
dao *bws.Dao |
|
accClient accapi.AccountClient |
|
suitRPC *suitrpc.Service2 |
|
// bws admin mids |
|
allowMids map[int64]struct{} |
|
awardMids map[int64]struct{} |
|
lotteryMids map[int64]struct{} |
|
lotteryAids map[int64]struct{} |
|
cache *fanout.Fanout |
|
} |
|
|
|
// New Service |
|
func New(c *conf.Config) (s *Service) { |
|
s = &Service{ |
|
c: c, |
|
dao: bws.New(c), |
|
suitRPC: suitrpc.New(c.RPCClient2.Suit), |
|
cache: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)), |
|
} |
|
var err error |
|
if s.accClient, err = accapi.NewClient(c.AccClient); err != nil { |
|
panic(err) |
|
} |
|
s.initMids() |
|
s.initLotteryAids() |
|
return |
|
} |
|
|
|
func (s *Service) initMids() { |
|
tmpMids := make(map[int64]struct{}, len(s.c.Rule.BwsMids)) |
|
tmpAward := make(map[int64]struct{}, len(s.c.Rule.BwsMids)+len(s.c.Rule.BwsAwardMids)) |
|
tmpLottery := make(map[int64]struct{}, len(s.c.Rule.BwsMids)+len(s.c.Rule.BwsLotteryMids)) |
|
for _, id := range s.c.Rule.BwsMids { |
|
tmpMids[id] = struct{}{} |
|
tmpAward[id] = struct{}{} |
|
tmpLottery[id] = struct{}{} |
|
} |
|
for _, id := range s.c.Rule.BwsAwardMids { |
|
tmpAward[id] = struct{}{} |
|
} |
|
for _, id := range s.c.Rule.BwsLotteryMids { |
|
tmpLottery[id] = struct{}{} |
|
} |
|
s.allowMids = tmpMids |
|
s.awardMids = tmpAward |
|
s.lotteryMids = tmpLottery |
|
} |
|
|
|
func (s *Service) initLotteryAids() { |
|
tmp := make(map[int64]struct{}, len(s.c.Rule.BwsLotteryAids)) |
|
for _, id := range s.c.Rule.BwsLotteryAids { |
|
tmp[id] = struct{}{} |
|
} |
|
s.lotteryAids = tmp |
|
} |
|
|
|
// User user info. |
|
func (s *Service) User(c context.Context, bid, mid int64, key string) (user *bwsmdl.User, err error) { |
|
var ( |
|
hp, keyID int64 |
|
ac *accapi.CardReply |
|
points, dps, games, clockins, eggs []*bwsmdl.UserPointDetail |
|
achErr, pointErr error |
|
) |
|
if key == "" { |
|
if key, err = s.midToKey(c, mid); err != nil { |
|
return |
|
} |
|
} else { |
|
if mid, keyID, err = s.keyToMid(c, key); err != nil { |
|
return |
|
} |
|
} |
|
user = new(bwsmdl.User) |
|
if mid != 0 { |
|
if ac, err = s.accCard(c, mid); err != nil { |
|
log.Error("User s.accCard(%d) error(%v)", mid, err) |
|
return |
|
} |
|
} |
|
if ac != nil && ac.Card != nil { |
|
user.User = &bwsmdl.UserInfo{ |
|
Mid: ac.Card.Mid, |
|
Name: ac.Card.Name, |
|
Face: ac.Card.Face, |
|
Key: key, |
|
} |
|
} else { |
|
user.User = &bwsmdl.UserInfo{ |
|
Name: strconv.FormatInt(keyID, 10), |
|
Key: key, |
|
} |
|
} |
|
group, errCtx := errgroup.WithContext(c) |
|
group.Go(func() error { |
|
if user.Achievements, achErr = s.userAchieves(errCtx, bid, key); achErr != nil { |
|
log.Error("User s.userAchieves(%d,%s) error(%v)", bid, key, achErr) |
|
} |
|
return nil |
|
}) |
|
group.Go(func() error { |
|
if points, pointErr = s.userPoints(errCtx, bid, key); pointErr != nil { |
|
log.Error("User s.userPoints(%d,%s) error(%v)", bid, key, pointErr) |
|
} |
|
return nil |
|
}) |
|
group.Wait() |
|
if len(user.Achievements) == 0 { |
|
user.Achievements = _emptyUserAchieves |
|
} |
|
user.Items = make(map[string][]*bwsmdl.UserPointDetail, 4) |
|
gidMap := make(map[int64]int64, len(points)) |
|
for _, v := range points { |
|
switch v.LockType { |
|
case _dpType: |
|
dps = append(dps, v) |
|
case _gameType: |
|
if v.Points == v.Unlocked { |
|
if _, ok := gidMap[v.Pid]; !ok { |
|
games = append(games, v) |
|
} |
|
gidMap[v.Pid] = v.Pid |
|
} |
|
case _clockinType: |
|
clockins = append(clockins, v) |
|
case _eggType: |
|
eggs = append(eggs, v) |
|
} |
|
hp += v.Points |
|
} |
|
user.User.Hp = hp |
|
if len(dps) == 0 { |
|
user.Items[_dp] = _emptUserPoints |
|
} else { |
|
user.Items[_dp] = dps |
|
} |
|
if len(games) == 0 { |
|
user.Items[_game] = _emptUserPoints |
|
} else { |
|
user.Items[_game] = games |
|
} |
|
if len(clockins) == 0 { |
|
user.Items[_clockin] = _emptUserPoints |
|
} else { |
|
user.Items[_clockin] = clockins |
|
} |
|
if len(eggs) == 0 { |
|
user.Items[_egg] = _emptUserPoints |
|
} else { |
|
user.Items[_egg] = eggs |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) accCard(c context.Context, mid int64) (ac *accapi.CardReply, err error) { |
|
var ( |
|
arg = &accapi.MidReq{Mid: mid} |
|
) |
|
if ac, err = s.accClient.Card3(c, arg); err != nil || ac == nil { |
|
log.Error("s.accRPC.Card3(%d) error(%v)", mid, err) |
|
err = ecode.AnswerAccCallErr |
|
} else if ac.Card.Silence == _accountBlocked { |
|
err = ecode.UserDisabled |
|
} |
|
return |
|
} |
|
|
|
// Binding binding by mid |
|
func (s *Service) Binding(c context.Context, loginMid int64, p *bwsmdl.ParamBinding) (err error) { |
|
var ( |
|
achieves *bwsmdl.Achievements |
|
users *bwsmdl.Users |
|
checkMid int64 |
|
) |
|
if _, err = s.accCard(c, loginMid); err != nil { |
|
log.Error("s.accCard(%d) error(%v)", loginMid, err) |
|
return |
|
} |
|
if checkMid, _, err = s.keyToMid(c, p.Key); err != nil { |
|
return |
|
} |
|
if checkMid != 0 { |
|
err = ecode.ActivityKeyBindAlready |
|
return |
|
} |
|
if users, err = s.dao.UsersMid(c, loginMid); err != nil { |
|
err = ecode.ActivityKeyFail |
|
return |
|
} |
|
if users != nil && users.Key != "" { |
|
err = ecode.ActivityMidBindAlready |
|
return |
|
} |
|
if err = s.dao.Binding(c, loginMid, p); err != nil { |
|
log.Error("s.dao.Binding mid(%d) key(%s) error(%v)", loginMid, p.Key, err) |
|
return |
|
} |
|
if s.c.Rule.NeedInitAchieve { |
|
if achieves, err = s.dao.Achievements(c, p.Bid); err != nil { |
|
log.Error("s.dao.Achievements error(%v)", err) |
|
err = ecode.ActivityAchieveFail |
|
return |
|
} |
|
if achieves == nil || len(achieves.Achievements) == 0 { |
|
err = ecode.ActivityNoAchieve |
|
return |
|
} |
|
for _, achieve := range achieves.Achievements { |
|
if achieve.LockType == _initLinkType { |
|
s.addAchieve(c, loginMid, achieve, p.Key) |
|
break |
|
} |
|
} |
|
var userAchieves []*bwsmdl.UserAchieveDetail |
|
if userAchieves, err = s.userAchieves(c, p.Bid, p.Key); err != nil { |
|
log.Error("Binding add suit key(%s) mid(%d) %+v", p.Key, loginMid, err) |
|
err = nil |
|
} else { |
|
for _, v := range userAchieves { |
|
if v.LockType == _initLinkType { |
|
continue |
|
} |
|
if suitID := v.SuitID; suitID != 0 { |
|
log.Warn("Binding suit mid(%d) suitID(%d) expire(%d)", loginMid, suitID, s.c.Rule.BwsSuitExpire) |
|
s.cache.Do(c, func(c context.Context) { |
|
arg := &suitmdl.ArgGrantByMids{Mids: []int64{loginMid}, Pid: suitID, Expire: s.c.Rule.BwsSuitExpire} |
|
if e := s.suitRPC.GrantByMids(c, arg); e != nil { |
|
log.Error("Binding s.suit.GrantByMids(%d,%d) error(%v)", loginMid, suitID, e) |
|
} |
|
}) |
|
} |
|
if _, ok := s.lotteryAids[v.Aid]; ok { |
|
lotteryAid := v.Aid |
|
log.Warn("Binding lottery mid(%d) achieve id(%d) expire(%d)", loginMid, lotteryAid, s.c.Rule.BwsSuitExpire) |
|
s.cache.Do(c, func(c context.Context) { |
|
s.dao.AddLotteryMidCache(c, lotteryAid, loginMid) |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
s.dao.DelCacheUsersKey(c, p.Key) |
|
s.dao.DelCacheUsersMid(c, loginMid) |
|
return |
|
} |
|
|
|
func (s *Service) isAdmin(mid int64) bool { |
|
if _, ok := s.allowMids[mid]; ok { |
|
return true |
|
} |
|
return false |
|
} |
|
|
|
func (s *Service) midToKey(c context.Context, mid int64) (key string, err error) { |
|
var users *bwsmdl.Users |
|
if users, err = s.dao.UsersMid(c, mid); err != nil { |
|
err = ecode.ActivityKeyFail |
|
return |
|
} |
|
if users == nil || users.Key == "" { |
|
err = ecode.ActivityNotBind |
|
return |
|
} |
|
key = users.Key |
|
return |
|
} |
|
|
|
func (s *Service) keyToMid(c context.Context, key string) (mid, keyID int64, err error) { |
|
var users *bwsmdl.Users |
|
if users, err = s.dao.UsersKey(c, key); err != nil { |
|
err = ecode.ActivityKeyFail |
|
return |
|
} |
|
if users == nil || users.Key == "" { |
|
err = ecode.ActivityKeyNotExists |
|
return |
|
} |
|
if users.Mid > 0 { |
|
mid = users.Mid |
|
} |
|
keyID = users.ID |
|
return |
|
} |
|
|
|
func today() string { |
|
return time.Now().Format("20060102") |
|
}
|
|
|