package limiteditems import ( "encoding/json" "os" "strconv" "sync" "time" "bet24.com/log" platformconfig "bet24.com/servers/micros/platformconfig/proto" ) var mgr *manager const config_key = "limiteditems_config" type itemGained struct { ItemId int Count int } type limitedInfo struct { ItemId int Count int } type manager struct { lock *sync.RWMutex userItems map[int][]itemGained isDirty bool limitedConf []limitedInfo lastCheckDay int } func getManager() *manager { if mgr == nil { mgr = new(manager) mgr.ctor() } return mgr } func (m *manager) ctor() { log.Release("limiteditems.manager.run()") m.lock = &sync.RWMutex{} m.userItems = make(map[int][]itemGained) m.readConf() m.lastCheckDay = time.Now().Day() m.loadUserItemsFromRedis() } func (m *manager) readConf() { time.AfterFunc(refresh_config_sec*time.Second, m.readConf) configString := platformconfig.GetConfig(config_key) if configString == "" { data, err := os.ReadFile("fishconf/limiteditems.json") if err != nil { log.Release("limiteditems.manager.loadData read limiteditems failed") return } configString = string(data) if configString != "" { platformconfig.SetConfig(config_key, configString) } } m.lock.Lock() defer m.lock.Unlock() err := json.Unmarshal([]byte(configString), &m.limitedConf) if err != nil { log.Release("limiteditems.manager.loadData Unmarshal failed err:%v", err) } } func (m *manager) dump(param1, param2 string) { if param1 == "" { m.dumpSys() return } m.dumpUser(param1) } func (m *manager) addItem(userId int, itemId int, count int) int { m.lock.RLock() if len(m.limitedConf) == 0 { m.lock.RUnlock() return count } limitedCount := 0 for _, v := range m.limitedConf { if v.ItemId == itemId { limitedCount = v.Count break } } m.lock.RUnlock() if 0 == limitedCount { return count } m.checkDayRefresh() userGained := m.getUserGained(userId) added := false for i := 0; i < len(userGained); i++ { if userGained[i].ItemId == itemId { itemCount := userGained[i].Count added = true if itemCount+count > limitedCount { count = limitedCount - userGained[i].Count if count < 0 { count = 0 } } userGained[i].Count += count break } } // 之前没有 if !added { if count > limitedCount { count = limitedCount } userGained = append(userGained, itemGained{ItemId: itemId, Count: count}) } m.lock.Lock() m.userItems[userId] = userGained m.lock.Unlock() m.isDirty = true return count } func (m *manager) checkDayRefresh() { nowDay := time.Now().Day() if nowDay == m.lastCheckDay { return } m.lastCheckDay = nowDay // 清理数据 m.lock.Lock() m.userItems = make(map[int][]itemGained) m.lock.Unlock() m.isDirty = true } func (m *manager) getUserGained(userId int) []itemGained { m.lock.RLock() defer m.lock.RUnlock() ret, ok := m.userItems[userId] if !ok { return []itemGained{} } return ret } func (m *manager) dumpSys() { log.Release("-------------------------------") log.Release("manager.dumpSys") defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() m.lock.RLock() defer m.lock.RUnlock() if len(m.limitedConf) == 0 { log.Release(" no limited items active") return } for _, v := range m.limitedConf { log.Release(" itemId:%d count:%d", v.ItemId, v.Count) } } func (m *manager) dumpUser(userIdStr string) { log.Release("-------------------------------") log.Release("manager.dumpUser[%s]", userIdStr) defer func() { log.Release("+++++++++++++++++++++++++++++++") log.Release("") }() userId, err := strconv.Atoi(userIdStr) if err != nil { log.Release(" atoi error %v", err) return } gained := m.getUserGained(userId) if len(gained) == 0 { log.Release(" user has no gained") return } for _, v := range gained { log.Release(" ItemId[%d],gained[%d]", v.ItemId, v.Count) } }