| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- package purchase
- import (
- "fmt"
- "math/rand"
- "sync"
- "time"
- "bet24.com/log"
- "bet24.com/servers/common"
- "bet24.com/servers/coreservice/serviceconfig"
- item "bet24.com/servers/micros/item_inventory/proto"
- cash "bet24.com/servers/micros/money/proto"
- mail "bet24.com/servers/micros/userservices/proto"
- )
- type purchaseMgr struct {
- sn int // 序号
- numbers [][]int // 抽奖码
- index int // 索引
- user_list map[int]*userPurchase // 用户列表
- beginTime time.Time // 开始时间
- endTime time.Time // 结束时间
- luckNumber int // 中奖码
- status int // 状态(0=空闲 1=活动中 3=派奖 2=结束)
- lock *sync.RWMutex
- }
- type userPurchase struct {
- UserId int // 用户id
- Numbers []int // 号码
- }
- func newPurchaseMgr() *purchaseMgr {
- mgr := new(purchaseMgr)
- mgr.user_list = make(map[int]*userPurchase)
- mgr.lock = &sync.RWMutex{}
- mgr.load()
- go mgr.refresh()
- log.Debug("purchase manager running")
- return mgr
- }
- func (this *purchaseMgr) load() {
- // log.Debug("purchase.load 开始加载数据")
- // 从数据库拉取未结束的活动数据
- sn, beginTime, endTime, luckNumber, status := sysInfo()
- if sn <= 0 {
- log.Debug("purchase.load not data")
- return
- }
- // 获取用户数据
- userList := userInfo(sn)
- index := len(userList)
- numbers := this.initNumbers(userList)
- this.lock.Lock()
- defer this.lock.Unlock()
- this.sn = sn
- this.beginTime = beginTime
- this.endTime = endTime
- this.luckNumber = luckNumber
- this.status = status
- this.user_list = userList
- this.index = index
- this.numbers = numbers
- //log.Debug("purchase.load 加载数据 data ok ==> sn=%d beginTime=%s endTime=%s luckNumber=%d status=%d index=%d numbers=%v",
- // this.sn, this.beginTime, this.end, this.luckNumber, this.status, this.index, this.numbers)
- }
- func (this *purchaseMgr) refresh() {
- ticker := time.NewTicker(2 * time.Second)
- go func(t *time.Ticker) {
- for {
- select {
- case <-t.C:
- this.check()
- }
- }
- }(ticker)
- }
- func (this *purchaseMgr) check() {
- // 派奖中(什么都不处理)
- if this.status == STATUS_PRIZE {
- return
- }
- // 活动中
- if this.status == STATUS_ACTIVITY {
- // 当期还没结束
- if this.getNow().After(this.beginTime) && this.getNow().Before(this.endTime) {
- return
- }
- // 结束
- this.end()
- return
- }
- // 是否有效期
- if !this.isValid() {
- return
- }
- // 开启活动
- this.open()
- return
- }
- func (this *purchaseMgr) getNow() time.Time {
- // 转换成相同的格式
- now, _ := time.Parse(common.Layout, time.Now().Format(common.Layout))
- return now
- }
- // 是否有效
- func (this *purchaseMgr) isValid() bool {
- // 开始时间
- start, err := time.Parse(common.Layout, fmt.Sprintf("%s 00:00:00", time.Now().Format("2006-01-02")))
- if err != nil {
- log.Error("purchaseMgr startTime fail %v", err)
- return false
- }
- // log.Debug("isValid start = %v", start)
- if serviceconfig.Server.PurchaseCfg.BeginHour == "" {
- return false
- }
- beginHour, err := time.ParseDuration(serviceconfig.Server.PurchaseCfg.BeginHour)
- if err != nil {
- log.Error("purchaseMgr beginHour fail %v", err)
- return false
- }
- // log.Debug("isValid beginHour = %v", beginHour)
- start = start.Add(beginHour)
- // log.Debug("isValid ==> start = %v", start)
- // 结束时间
- end, err := time.Parse(common.Layout, fmt.Sprintf("%s 00:00:00", time.Now().Format("2006-01-02")))
- if err != nil {
- log.Error("purchaseMgr endTime fail %v", err)
- return false
- }
- // log.Debug("isValid end = %v", end)
- if serviceconfig.Server.PurchaseCfg.EndHour == "" {
- return false
- }
- endHour, err := time.ParseDuration(serviceconfig.Server.PurchaseCfg.EndHour)
- if err != nil {
- log.Error("purchaseMgr endHour fail %v", err)
- return false
- }
- // log.Debug("isValid endHour = %v", endHour)
- end = end.Add(endHour)
- // log.Debug("isValid ==> end = %v", end)
- // 不在活动时间段内
- if this.getNow().Before(start) || this.getNow().After(end) {
- //log.Debug("purchaseMgr.isValid 不在活动时间段内 start=%v end=%v this.getNow()=%v ==> %+v",
- // start, end, this.getNow(), this)
- return false
- }
- // log.Debug("purchaseMgr.isValid 活动有效期")
- return true
- }
- // 开启
- func (this *purchaseMgr) open() {
- duration, err := time.ParseDuration(serviceconfig.Server.PurchaseCfg.Duration)
- if err != nil {
- log.Error("open duration fail %v", err)
- return
- }
- this.lock.Lock()
- this.sn++
- this.numbers = this.initNumbers(nil)
- this.index = 0
- this.user_list = make(map[int]*userPurchase, 0)
- this.beginTime = this.getNow()
- this.endTime = this.getNow().Add(duration)
- this.luckNumber = 0
- this.status = STATUS_ACTIVITY
- this.lock.Unlock()
- // 写数据(开启,活动中状态)
- go open(this.sn, this.beginTime, this.endTime, this.luckNumber, this.status)
- //log.Debug("purchasemgr.open 已开启 sn=%d beginTime=%s endTime=%s status=%d numbers=%v index=%d",
- // this.sn, this.beginTime, this.endTime, this.status, this.numbers, this.index)
- return
- }
- // 初始化
- func (this *purchaseMgr) initNumbers(list map[int]*userPurchase) [][]int {
- var numbers [][]int
- for i := 1; i <= serviceconfig.Server.PurchaseCfg.MaxNumber; i++ {
- flag := false
- // 已经存在的抽奖码排除
- for _, j := range list {
- for _, v := range j.Numbers {
- // 该抽奖码已存在
- if v == i {
- flag = true
- break
- }
- }
- if flag {
- break
- }
- }
- if flag {
- continue
- }
- var items []int
- items = append(items, i, 0)
- numbers = append(numbers, items)
- }
- count := len(numbers)
- // 打乱顺序
- for i := count - 1; i > 0; i-- {
- j := rand.Intn(i)
- numbers[i], numbers[j] = numbers[j], numbers[i]
- }
- // 加在头部
- for _, v := range list {
- for _, k := range v.Numbers {
- var items []int
- items = append(items, k, v.UserId)
- numbers = append([][]int{items}, numbers...)
- }
- }
- return numbers
- }
- // 结束
- func (this *purchaseMgr) end() {
- if serviceconfig.Server.PurchaseCfg.MaxNumber <= 0 {
- return
- }
- // 生成随机号码
- index := rand.Intn(serviceconfig.Server.PurchaseCfg.MaxNumber)
- this.lock.Lock()
- this.status = STATUS_PRIZE
- this.luckNumber = this.numbers[index][0]
- userId := this.numbers[index][1]
- sn := this.sn
- luckNumber := this.luckNumber
- this.lock.Unlock()
- // 写数据(派奖状态)
- update(this.sn, this.luckNumber, this.status)
- // 邮件派奖
- this.sendPrize(userId, sn, luckNumber)
- this.lock.Lock()
- this.status = STATUS_END
- this.lock.Unlock()
- // 写数据(结束状态)
- go update(this.sn, this.luckNumber, this.status)
- log.Debug("purchasemgr.end sn=%d status=%d luckNumber=%d userId=%d", this.sn, this.status, this.luckNumber, userId)
- return
- }
- // 邮件派奖
- func (this *purchaseMgr) sendPrize(userId, sn, luckNumber int) {
- for _, v := range this.user_list {
- if v.UserId == userId && v.UserId > 0 {
- var items []item.ItemPack
- items = append(items, item.ItemPack{
- ItemId: serviceconfig.Server.PurchaseCfg.ItemId,
- Count: serviceconfig.Server.PurchaseCfg.AwardAmount,
- })
- // 发送中奖通知
- mail.SendSysMail(v.UserId, &mail.SysMail{
- Id: 0,
- Title: serviceconfig.Server.PurchaseCfg.SuccessTitle,
- Content: fmt.Sprintf(serviceconfig.Server.PurchaseCfg.SuccessContent, sn, serviceconfig.Server.PurchaseCfg.AwardAmount),
- Status: 0,
- SourceName: "100K购",
- Crdate: common.GetTimeStamp(),
- Tools: items,
- })
- continue
- }
- // 发送未中奖通知
- mail.SendSysMail(v.UserId, &mail.SysMail{
- Id: 0,
- Title: serviceconfig.Server.PurchaseCfg.FailTitle,
- Content: fmt.Sprintf(serviceconfig.Server.PurchaseCfg.FailContent, sn, luckNumber),
- Status: 0,
- SourceName: "100K购",
- Crdate: common.GetTimeStamp(),
- Tools: nil,
- })
- }
- return
- }
- // 投注(返回操作结果\抽奖码)
- func (this *purchaseMgr) bet(userId int, ipAddress string) (int, int) {
- this.lock.RLock()
- // 活动还没开启
- if this.status != STATUS_ACTIVITY {
- this.lock.RUnlock()
- return 11, 0
- }
- // 判断是否有空闲
- if this.index >= serviceconfig.Server.PurchaseCfg.MaxNumber {
- this.lock.RUnlock()
- return 12, 0
- }
- this.lock.RUnlock()
- // 扣除金币
- if !cash.ReduceMoney(userId, serviceconfig.Server.PurchaseCfg.GoldFee, common.LOGTYPE_PURCHASE, "100K购", fmt.Sprintf("100K购第%d期", this.sn), ipAddress) {
- log.Release("purchasemgr.bet userId[%d] bet[%d] not enough gold", userId, serviceconfig.Server.PurchaseCfg.GoldFee)
- return 13, 0
- }
- this.lock.Lock()
- number := this.numbers[this.index][0]
- this.numbers[this.index][1] = userId
- this.index++
- this.lock.Unlock()
- this.addUser(userId, number)
- // 写数据
- go bet(userId, this.sn, number)
- return 1, number
- }
- // 记录用户
- func (this *purchaseMgr) addUser(userId, number int) {
- if userId <= 0 || number <= 0 {
- log.Release("purchasemgr.addUser userId[%d] number[%d] 无效数据", userId, number)
- return
- }
- this.lock.RLock()
- info, ok := this.user_list[userId]
- this.lock.RUnlock()
- if !ok {
- info = &userPurchase{
- UserId: userId,
- Numbers: nil,
- }
- this.lock.Lock()
- this.user_list[userId] = info
- this.lock.Unlock()
- }
- info.Numbers = append(info.Numbers, number)
- return
- }
- // 获取当前信息(期数\元宝数量\倒计时\状态\消耗金币)
- func (this *purchaseMgr) getSysInfo() (int, int, int64, int, int) {
- this.lock.RLock()
- defer this.lock.RUnlock()
- return this.sn, serviceconfig.Server.PurchaseCfg.AwardAmount,
- this.endTime.Sub(this.getNow()).Milliseconds() / 1000, this.status,
- serviceconfig.Server.PurchaseCfg.GoldFee
- }
- // 获取用户抽奖码信息
- func (this *purchaseMgr) getUserInfo(userId int) []int {
- this.lock.RLock()
- info, ok := this.user_list[userId]
- this.lock.RUnlock()
- if !ok {
- return nil
- }
- return info.Numbers
- }
- // 小红点提示
- func (this *purchaseMgr) checkTip() bool {
- this.lock.RLock()
- defer this.lock.RUnlock()
- return this.status == STATUS_ACTIVITY
- }
|