package handler import ( "bet24.com/log" "bet24.com/servers/common" //"bet24.com/servers/coreservice/limiteditems" item "bet24.com/servers/micros/item_inventory/proto" notification "bet24.com/servers/micros/notification/proto" "encoding/json" "strconv" "sync" "time" ) const DELAY_REMOVE = 300 // 300秒后删除用户 const DELAY_CHECK = 60 // 每分钟检查一次 var inventorymgr *inventory func getInventoryManager() *inventory { if inventorymgr == nil { inventorymgr = newInventory() } return inventorymgr } type inventory struct { lock *sync.RWMutex userInventory map[int]*user_inventory lockRemove *sync.RWMutex userRemove map[int]int64 } func newInventory() *inventory { ret := new(inventory) ret.lock = &sync.RWMutex{} ret.userInventory = make(map[int]*user_inventory) ret.lockRemove = &sync.RWMutex{} ret.userRemove = make(map[int]int64) go ret.checkRemoveUser() return ret } func (this *inventory) checkRemoveUser() { time.AfterFunc(DELAY_CHECK*time.Second, this.checkRemoveUser) var toRemove []int latestRemoveTime := time.Now().Unix() - DELAY_REMOVE this.lockRemove.RLock() for k, v := range this.userRemove { if v < latestRemoveTime { toRemove = append(toRemove, k) } } this.lockRemove.RUnlock() if len(toRemove) == 0 { return } this.lockRemove.Lock() for _, v := range toRemove { delete(this.userRemove, v) } this.lockRemove.Unlock() for _, v := range toRemove { this.destroyUser(v) } } func (this *inventory) onUserEnter(userId int, ipAddress string) *user_inventory { this.lockRemove.Lock() delete(this.userRemove, userId) this.lockRemove.Unlock() this.lock.RLock() ui, ok := this.userInventory[userId] this.lock.RUnlock() if ok { return ui } ui = newUserInventory(userId, ipAddress) this.lock.Lock() this.userInventory[userId] = ui this.lock.Unlock() return ui } func (this *inventory) onUserExit(userId int) { this.lockRemove.Lock() this.userRemove[userId] = time.Now().Unix() this.lockRemove.Unlock() } func (this *inventory) destroyUser(userId int) { this.lock.RLock() s, _ := this.userInventory[userId] this.lock.RUnlock() if s == nil { return } s.destructor() this.lock.Lock() delete(this.userInventory, userId) this.lock.Unlock() } func (this *inventory) consume(userId int, itemId int, bullet int, count int, isGift int) (bool, string) { this.lock.RLock() ui, ok := this.userInventory[userId] this.lock.RUnlock() if !ok { ui = this.onUserEnter(userId, "") if ui != nil { return ui.consume(itemId, bullet, count, bullet, isGift) } log.Debug("inventory.consume userId[%d] not exist", userId) return false, "user not exist" } return ui.consume(itemId, bullet, count, bullet, isGift) } func (this *inventory) sell(userId, itemId, count, logType int) (bool, string) { this.lock.RLock() ui, ok := this.userInventory[userId] this.lock.RUnlock() if !ok { ui = this.onUserEnter(userId, "") if ui != nil { return ui.sell(itemId, count, logType) } log.Debug("inventory.sell userId[%d] not exist", userId) return false, "user not exist" } return ui.sell(itemId, count, logType) } func (this *inventory) consumeBulk(userId int, items []item.ItemPack, logType int) bool { this.lock.RLock() ui, ok := this.userInventory[userId] this.lock.RUnlock() if !ok { ui = this.onUserEnter(userId, "") if ui != nil { return ui.consumeBulk(items, logType) } log.Debug("inventory.consume userId[%d] not exist", userId) return false } return ui.consumeBulk(items, logType) } func (this *inventory) consumeLottery(userId, count int) (bool, string) { this.lock.RLock() ui, ok := this.userInventory[userId] this.lock.RUnlock() if !ok { ui = this.onUserEnter(userId, "") if ui != nil { return ui.consumeLottery(count) } log.Debug("inventory.consumeLottery userId[%d] not exist", userId) return false, "user not exist" } return ui.consumeLottery(count) } func (this *inventory) getUser(userId int, forceCreate bool) *user_inventory { this.lock.RLock() ret, ok := this.userInventory[userId] this.lock.RUnlock() if !ok { if forceCreate { return this.onUserEnter(userId, "") } return nil } return ret } func (this *inventory) addItemsWithExpireTime(userId int, items []item.ItemPack, desc string, logType int, expireTime int) bool { user := this.getUser(userId, false) toRemove := false if user == nil { user = newUserInventory(userId, "127.0.0.1") toRemove = true } ret := user.addItemsWithExpireTime(items, logType, expireTime) if toRemove { // 用户没有进来,不需要保存 user.destructor() } return ret } func (this *inventory) addItems(userId int, items []item.ItemPack, desc string, logType int) bool { // log.Debug("iventorymgr.addItems userId=%d items=%+v desc=%s", userId, items, desc) user := this.getUser(userId, false) toRemove := false if user == nil { user = newUserInventory(userId, "127.0.0.1") toRemove = true } var itemIds []int for _, v := range items { //v.Count = limiteditems.AddItem(userId, v.ItemId, v.Count) user.addItem(v, logType) itemIds = append(itemIds, v.ItemId) } //通知客户端 d, _ := json.Marshal(notification.NotificationInventory{ItemIds: itemIds, Action: Inventory_Add}) notification.AddNotification(userId, notification.Notification_Inventory, string(d)) if toRemove { // 用户没有进来,不需要保存 user.destructor() } return true } func (this *inventory) getUserItems(userId int) []*item.UserItem { user := this.getUser(userId, true) if user == nil { log.Debug("inventory.getUserItems userId[%d] not exist", userId) return nil } return user.getItemList() } func (this *inventory) getItemCount(userId int, itemId int) int { user := this.getUser(userId, true) if user == nil { log.Debug("inventory.getItemCount userId[%d] not exist", userId) return 0 } return user.getItemCount(itemId) } // 获取抽奖券 func (this *inventory) getUserLottery(userId int) *item.UserItem { user := this.getUser(userId, true) if user == nil { log.Debug("inventory.getUserLottery userId[%d] not exist", userId) return nil } return user.getLottery() } // 赠送 func (this *inventory) gift(userId, toUserId, itemId, count int) (bool, string) { // 先扣减 retCode, msg := this.consume(userId, itemId, common.LOGTYPE_TRANSFER_CONSUME, count, 1) if !retCode { return retCode, msg } var items []item.ItemPack items = append(items, item.ItemPack{ ItemId: itemId, Count: count, }) // 加道具 retCode = this.addItems(toUserId, items, "赠送", common.LOGTYPE_TRANSFER_ADD) return retCode, "成功" } func (iv *inventory) dumpSys(param string) { log.Release("-------------------------------") log.Release("inventory.dumpSys %s", param) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() if param == "" { d, _ := json.Marshal(getItemManager().getItems()) log.Release(string(d)) } else { var itemId int var err error if itemId, err = strconv.Atoi(param); err != nil { log.Release("atoi error %v", err) return } d, _ := json.Marshal(getItemManager().getItem(itemId)) log.Release(string(d)) } } func (iv *inventory) dumpUser(param string) { log.Release("-------------------------------") log.Release("inventory.dumpUser %s", param) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() if param == "all" { for k, v := range iv.userInventory { log.Release("%d:%d", k, v.userId) } return } var userId int var err error if userId, err = strconv.Atoi(param); err != nil { log.Release("atoi error %v", err) return } si := iv.getUserItems(userId) if si == nil { log.Release("user %d has no items", userId) return } d, _ := json.Marshal(si) log.Release(string(d)) } func (this *inventory) reduceItemByAdmin(opUserID int, opUserName string, userId, itemId, count int) (bool, string) { toRemove := false user := this.getUser(userId, false) if user == nil { user = newUserInventory(userId, "127.0.0.1") toRemove = true } ok, msg := user.reduceItemByAdmin(opUserID, opUserName, itemId, count) if toRemove { // 用户没有进来,不需要保存 user.destructor() } return ok, msg } func (this *inventory) checkDecortaionType(itemId int, t int, userId int) bool { userItem := this.getUser(userId, true) if userItem == nil { log.Release("inventory.checkDecortaionType userItem not found %d", userId) return false } // 有没有? if userItem.getItemCount(itemId) == 0 { log.Release("inventory.checkDecortaionType user[%d] do not have [%d]", userId, itemId) return false } return getItemManager().checkDecortaionType(itemId, t) }