| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- package match
- import (
- "sync"
- "time"
- "bet24.com/log"
- "bet24.com/servers/common"
- "bet24.com/servers/micros/guess/handler/team"
- pb "bet24.com/servers/micros/guess/proto"
- item "bet24.com/servers/micros/item_inventory/proto"
- money "bet24.com/servers/micros/money/proto"
- mail "bet24.com/servers/micros/userservices/proto"
- )
- const idle_seconds = 24 * 60 * 60 * 30 // 过期时长30天(秒)
- // 赛事
- type match struct {
- pb.Match
- lock *sync.RWMutex
- user_list map[int][]pb.UserBet
- endChan chan int
- }
- func newMatch(serialNumber string) *match {
- ret := new(match)
- ret.endChan = make(chan int)
- ret.lock = &sync.RWMutex{}
- ret.user_list = make(map[int][]pb.UserBet)
- ret.SerialNumber = serialNumber
- ret.loadData()
- ret.doCheck()
- return ret
- }
- func (this *match) loadData() {
- // 赛事信息
- m := trans_GetMatchInfo(this.SerialNumber)
- if m.SerialNumber == "" {
- log.Release("match.loadData GetMatchInfo serialNumber=%s is not exist", this.SerialNumber)
- return
- }
- // 球队
- teams := trans_GetMatchTeamList(m.SerialNumber)
- if teams == nil {
- log.Release("match.loadData GetMatchTeamList serialNumber=%s is empty", m.SerialNumber)
- return
- }
- // 球队信息
- for _, t := range teams {
- teamInfo := team.GetTeam(t.Id)
- teamInfo.Rid = t.Rid
- m.Teams = append(m.Teams, teamInfo)
- }
- // 投注信息
- m.Bets = trans_GetMatchBetList(m.SerialNumber)
- if m.Bets == nil {
- log.Release("match.loadData GetMatchBetList serialNumber=%s is empty", m.SerialNumber)
- return
- }
- this.Match = m
- // 获取用户投注
- user_list := trans_GetUserBetAmount(this.SerialNumber)
- this.lock.Lock()
- this.user_list = user_list
- this.lock.Unlock()
- }
- // 轮询检查
- func (this *match) doCheck() {
- ticker := time.NewTicker(1 * time.Second)
- go func(t *time.Ticker) {
- for {
- select {
- case <-this.endChan:
- t.Stop()
- return
- case <-t.C:
- this.checkEnd()
- }
- }
- }(ticker)
- }
- // 检查是否结束状态
- func (this *match) checkEnd() {
- //defer func() {
- // log.Debug("match.checkStatus %+v", this.Match)
- //}()
- // 非开启状态
- if this.Status != pb.MatchStatus_Open {
- close(this.endChan)
- return
- }
- // 还没结束
- if this.EndAt > common.GetTimeStamp() {
- return
- }
- // 修改结束状态
- this.Status = pb.MatchStatus_End
- // TODO:写入数据库
- go trans_UpdateMatchStatus(this.SerialNumber, this.Status)
- return
- }
- // 是否过期
- func (this *match) isExpire() bool {
- return this.EndAt+idle_seconds < common.GetTimeStamp()
- }
- // 是否游戏无效
- func (this *match) isInvalid() bool {
- return this.Status == pb.MatchStatus_Invalid
- }
- // 获取赛事
- func (this *match) getInfo() pb.Match {
- return this.Match
- }
- // 赛事类型(0=所有赛事 1=展示的赛事 2=正在进行的赛事 3=结束的赛事 4=预热的赛事
- func (this *match) getMatchType(matchType int) bool {
- // 无效状态
- if this.Status <= pb.MatchStatus_Invalid || this.Status >= pb.MatchStatus_Max {
- return false
- }
- ts := common.GetTimeStamp()
- switch matchType {
- case pb.MatchType_All: // 0=所有赛事
- return true
- case pb.MatchType_Show: // 1=展示的赛事
- if this.ShowStartAt <= ts && this.ShowEndAt >= ts {
- return true
- }
- case pb.MatchType_Bet: // 2=正在进行的赛事
- if this.ShowStartAt <= ts && this.ShowEndAt >= ts && this.StartAt < ts && this.EndAt >= ts {
- return true
- }
- case pb.MatchType_End: // 3=结束的赛事
- if this.Status == pb.MatchStatus_End || this.Status == pb.MatchStatus_Award {
- return true
- }
- case pb.MatchType_Preheat: // 4=预热的赛事
- if this.Status == pb.MatchStatus_Open && this.ShowStartAt > ts && this.StartAt > ts {
- return true
- }
- }
- return false
- }
- // 投注
- func (this *match) bet(userId, betId, amount int, ipAddress string) (ret pb.RetMsg) {
- // 先扣款
- if ok := money.ReduceMoney(userId, amount, common.LOGTYPE_GUESS_BET, "竞猜", "投注", ipAddress); !ok {
- ret.RetCode = 501
- ret.Message = "Insufficient gold coins, deduction failed"
- return
- }
- // 投注总额
- for i := 0; i < len(this.Match.Bets); i++ {
- if this.Match.Bets[i].Id != betId {
- continue
- }
- this.Match.Bets[i].Amount += amount
- // TODO: 投注记录
- go trans_AddBetRecord(userId, this.SerialNumber, betId, amount)
- // TODO:更新投注金额
- go trans_UpdateBetAmount(this.SerialNumber, betId, this.Match.Bets[i].Amount)
- break
- }
- // 添加用户投注
- this.addUserBet(userId, betId, amount)
- ret.RetCode = 1
- ret.Message = "success"
- return
- }
- // 添加用户投注
- func (this *match) addUserBet(userId, betId, amount int) {
- this.lock.RLock()
- bets, ok := this.user_list[userId]
- this.lock.RUnlock()
- if ok {
- var isExist bool
- for k, v := range bets {
- if v.BetId != betId {
- continue
- }
- isExist = true
- this.user_list[userId][k].BetAmount += amount
- break
- }
- if !isExist {
- this.user_list[userId] = append(this.user_list[userId], pb.UserBet{
- BetId: betId,
- BetAmount: amount,
- })
- }
- return
- }
- var list []pb.UserBet
- list = append(list, pb.UserBet{
- BetId: betId,
- BetAmount: amount,
- })
- this.lock.Lock()
- this.user_list[userId] = list
- this.lock.Unlock()
- return
- }
- // 获取用户投注
- func (this *match) getUserBet(userId int) []pb.UserBet {
- this.lock.RLock()
- bets, ok := this.user_list[userId]
- this.lock.RUnlock()
- if ok {
- return bets
- }
- return nil
- }
- // 设置结果
- func (this *match) setResult(betId int, result string, op pb.OpUser) (ret pb.RetMsg) {
- // 非结束状态
- if this.Status != pb.MatchStatus_End {
- ret.RetCode = 501
- ret.Message = "Unable to set result for non ending state"
- return
- }
- this.Result = result
- for i := 0; i < len(this.Bets); i++ {
- if this.Bets[i].Id != betId {
- continue
- }
- this.Bets[i].IsWin = true
- break
- }
- // TODO:存入数据库
- go trans_SetMatchResult(this.SerialNumber, betId, result, op)
- ret.RetCode = 1
- ret.Message = "success"
- return
- }
- // 派奖
- func (this *match) award(op pb.OpUser, cfg pb.GuessCfg) (ret pb.RetMsg) {
- // 非结束状态
- if this.Status != pb.MatchStatus_End {
- ret.RetCode = 501
- ret.Message = "Unable to distribute prizes until the end state"
- return
- }
- var bet pb.Bet
- for _, v := range this.Bets {
- if !v.IsWin {
- continue
- }
- bet = v
- break
- }
- // 投注项无效
- if bet.Id <= 0 {
- log.Release("match.award %+v is invalid", this.Match)
- ret.RetCode = 502
- ret.Message = "Invalid bonus betting item"
- return
- }
- // 派奖状态
- this.Status = pb.MatchStatus_Award
- // 设置为派奖状态
- if retCode := trans_UpdateMatchStatus(this.SerialNumber, this.Status); retCode != 1 {
- log.Release("match.award %+v is award", this.Match)
- ret.RetCode = 503
- ret.Message = "Rewards have been issued and cannot be issued repeatedly"
- return
- }
- // 获取当前赛事相应的投注id
- list := trans_GetBetSettleList(this.SerialNumber, bet.Id)
- users := make(map[int]struct{}, 0)
- for i := 0; i < len(list); i++ {
- // 已派过奖
- if list[i].ResultAmount > 0 {
- continue
- }
- // 计算派奖金额
- amount := int(float64(list[i].BetAmount) * bet.Odds)
- if amount <= 0 {
- continue
- }
- // 派奖金额
- list[i].ResultAmount = amount
- // TODO:存入数据库
- go trans_BetRecordAward(list[i].Rid, amount, op)
- var items []item.ItemPack
- items = append(items, item.ItemPack{
- ItemId: item.Item_Gold,
- Count: amount,
- })
- // 给道具
- item.AddItems(list[i].UserId, items, "竞猜派奖", common.LOGTYPE_GUESS_AWARD)
- users[list[i].UserId] = struct{}{}
- }
- for k := range users {
- // TODO:发送邮件通知
- go mail.SendSysMail(k, &mail.SysMail{
- Id: 0,
- Title: cfg.MailTitle,
- Content: cfg.MailContent,
- Status: 0,
- SourceName: cfg.MailSource,
- Crdate: common.GetTimeStamp(),
- Tools: nil,
- })
- }
- ret.RetCode = 1
- ret.Message = "success"
- return
- }
- // 获取投注选项
- func (this *match) getBetInfo(betId int) pb.Bet {
- for _, v := range this.Bets {
- if v.Id == betId {
- return v
- }
- }
- return pb.Bet{}
- }
- // 刷新球队信息
- func (this *match) refreshTeam(teamId int) {
- for i := 0; i < len(this.Teams); i++ {
- if this.Teams[i].Id != teamId {
- continue
- }
- teamInfo := team.GetTeam(teamId)
- this.Teams[i].Name = teamInfo.Name
- this.Teams[i].ShortName = teamInfo.ShortName
- this.Teams[i].Icon = teamInfo.Icon
- }
- }
- func (this *match) dump() {
- log.Debug("%+v", this.Match)
- log.Debug(" 投注信息:")
- for k, v := range this.user_list {
- log.Debug(" userId=%d ==> %+v", k, v)
- }
- }
|