#! -*- coding:utf-8 -*-
# Author: qianyong
# Created: 2016.06.30 19.43
from freetime.util import log as ftlog
from poker.entity.dao import daobase
from cars.entity import const
from cars.entity import carsconf
from cars.entity.util import UtilFunc
import time
class KingDay(object):
''''''
# 30, winchips,
# {userId: 132, purl: "http://asdfsaf", name: "zhangsan", winChips: 1234}
_dayRanks = []
# dayRank
_dateForDayRank = ''
# redis
_lastCheckedRanksAt = 0
# 30redis
CHECK_REDIS_RANKS_PERIOD = 30 * 60
@classmethod
def initialize(cls):
''', timer'''
UtilFunc.callLater(cls.CHECK_REDIS_RANKS_PERIOD, cls._loopCheckRedisRanksPeriod)
@classmethod
def addWinChip(cls, userId, deltaChip, now):
''', , '''
today = cls._todayDate(now)
# ,
dayData = UtilFunc.getDayData(userId, today)
dayData['winChipsForKing'] += deltaChip
UtilFunc.setDayData(userId, dayData, today)
userDayWinChips = dayData['winChipsForKing']
# ,
dayRanks = cls._getLocalDayRanks(today)
if len(dayRanks) >= cls._maxRanksCount() and dayRanks[-1]['winChips'] >= userDayWinChips:
return
# redis, redis
daobase.executeRankCmd('ZADD', cls._dayKey(today), -userDayWinChips, userId)
#
cls._updateLocalDayRanks(userId, userDayWinChips, today)
return userDayWinChips
@classmethod
def getTodayGameRanks(cls, now):
'''20'''
today = cls._todayDate(now)
ranks = cls._getLocalDayRanks(today)
maxCount = carsconf.getKingConf().get('today', {}).get('game_count', 1)
return ranks[:maxCount]
@classmethod
def getYesterdayRanks(cls, now, count=None):
'''20. redis'''
yesterday = cls._todayDate(now - const.ONE_DAY_SEC)
if count is None:
count = cls._maxRanksCount()
dayRanks = []
parts = daobase.executeRankCmd('ZRANGE', cls._dayKey(yesterday), 0, count - 1, 'WITHSCORES')
if not parts:
parts = []
for i in xrange(len(parts) / 2):
userId = int(parts[i * 2])
winChips = -int(parts[i * 2 + 1])
user = cls._buildUser(userId, winChips)
dayRanks.append(user)
return dayRanks
@classmethod
def getYesterdayTop(cls, now):
''', , None redis'''
ranks = cls.getYesterdayRanks(now, 1)
if len(ranks) > 0:
return ranks[0]
else:
return None
@classmethod
def setExpireRemoteRank(cls, now):
'''redisrank24'''
today = cls._todayDate(now)
daobase.executeRankCmd('EXPIRE', cls._dayKey(today), 24 * 3600)
@classmethod
def getUserTodayWinChips(cls, userId, now):
'''rediswinchips'''
today = cls._todayDate(now)
data = UtilFunc.getDayData(userId, today)
return data['winChipsForKing']
@classmethod
def _buildUser(cls, userId, winChips):
'''user'''
name, purl = UtilFunc.getUserNameAndPurl(userId)
return {
"userId": userId,
"winChips": winChips,
"name": name,
"purl": purl
}
@classmethod
def _dayKey(cls, date):
'''key'''
return 'kingrank:%s:%s' % (const.GAME_ID, date)
@classmethod
def _todayDate(cls, now=None):
''''''
if now is None:
now = time.time()
return time.strftime("%Y%m%d", time.localtime(now))
@classmethod
def _getLocalDayRanks(cls, today):
'''
dayRank
:param today:
:return: dayRank
'''
# , redis
if today != cls._dateForDayRank:
del cls._dayRanks[:]
count = cls._maxRanksCount()
parts = daobase.executeRankCmd('ZRANGE', cls._dayKey(today), 0, count - 1, 'WITHSCORES')
if not parts:
parts = []
for i in xrange(len(parts) / 2):
userId = int(parts[i * 2])
winChips = -int(parts[i * 2 + 1])
user = cls._buildUser(userId, winChips)
cls._dayRanks.append(user)
cls._dateForDayRank = today
return cls._dayRanks
@classmethod
def _updateLocalDayRanks(cls, userId, winChips, today):
'''dayrank'''
count = cls._maxRanksCount()
dayRanks = cls._getLocalDayRanks(today)
#
index = cls._findUserInDayRanks(userId, dayRanks)
if index >= 0:
dayRanks[index]['winChips'] = winChips
else:
if len(dayRanks) < count:
dayRanks.append(cls._buildUser(userId, winChips))
else:
dayRanks[-1] = cls._buildUser(userId, winChips)
#
dayRanks.sort(cmp=lambda a, b: cmp(a['winChips'], b['winChips']), reverse=True)
@classmethod
def _findUserInDayRanks(cls, userId, dayRank):
'''dayrank, -1'''
for i in xrange(len(dayRank)):
if dayRank[i]['userId'] == userId:
return i
return -1
@classmethod
def _maxRanksCount(cls):
''''''
dayConf = carsconf.getKingConf().get('today', {})
return max(dayConf.get('game_count', 1), dayConf.get('bi_count', 1))
@classmethod
def _loopCheckRedisRanksPeriod(cls):
now = int(time.time())
#
today = cls._todayDate(now)
countInRedis = daobase.executeRankCmd('ZCOUNT', cls._dayKey(today), '-inf', '+inf')
if not countInRedis:
countInRedis = 0
countInRedis = int(countInRedis)
ftlog.info('_loopCheckRedisRanksPeriod king ranks total length', countInRedis)
# ,
maxCount = cls._maxRanksCount()
if countInRedis > maxCount * 2:
daobase.executeRankCmd('ZREMRANGEBYRANK', cls._dayKey(today), maxCount, -1)
# check, , BI
if UtilFunc.isAcrossTwoDays(now, cls._lastCheckedRanksAt):
biCount = carsconf.getKingConf().get('today', {}).get('bi_count', 1)
yesterday = cls._todayDate(now - const.ONE_DAY_SEC)
parts = daobase.executeRankCmd('ZRANGE', cls._dayKey(yesterday), 0, biCount, 'WITHSCORES')
if not parts:
parts = []
# BI
ftlog.info('King.Ranks.Yesterday:', parts)
# ,
cls.setExpireRemoteRank(now)
cls._lastCheckedRanksAt = now
# ,
UtilFunc.callLater(cls.CHECK_REDIS_RANKS_PERIOD, cls._loopCheckRedisRanksPeriod)