game2003api/tools/rankserver/game2003rank.py
aozhiwei 71ad855736 1
2019-10-12 17:29:27 +08:00

245 lines
7.5 KiB
Python

# -*- coding: utf-8 -*-
#!/usr/bin/python
import pymysql
import hashlib
import json
import urllib.request
import base64
import tornado.ioloop
import tornado.web
import time
import datetime
import redis
import os
import functools
CONFIG_DIR = ''
def IsOnlineEnv():
return os.getenv("SERVER_ENV");
if (IsOnlineEnv()):
CONFIG_DIR = '/var/data/conf_test/game2003api_rankserver/config'
else:
CONFIG_DIR = '../config'
def info(msg):
print(str(datetime.datetime.now()) + '[INFO] ' + msg)
def take_pass(elem):
return elem[3]
def take_coin_num(elem):
return elem[4]
def safeDiv(a, b):
if b == 0:
return 0
else:
return a / b
def getRedis():
redis_conf = json.loadsmysql_conf = json.loads(open(CONFIG_DIR + '/rankserver.redis.cluster.json', 'r').read())
for conf in redis_conf:
r = redis.Redis(host = conf['host'],
port = conf['port'],
password = conf['passwd'],
charset = 'utf8'
)
return r;
def getDaySeconds(time_val, incdays):
time_zone = 8
dayseconds = int((time_val + time_zone * 3600)/3600/24 + incdays) * 3600 * 24 - 3600 * time_zone;
return dayseconds
#数据去重
def delRepeatData(row, data_list):
temp_list = []
for data in data_list:
if data[0] == row[0]:
temp_list.append(data)
for temp_data in temp_list:
data_list.remove(temp_data)
#刷新通关数据
def refreshData(row, pass_list):
pass_list.append((row[0], row[1].decode('utf-8'), row[2], row[3], row[4]))
pass_list.sort(key=take_pass, reverse=True)
if (len(pass_list) > 50):
del pass_list[50:]
#刷新金币数据
def refreshCoinData(row, coin_list):
coin_list.append((row[0], row[1].decode('utf-8'), row[2], row[3], row[4]))
coin = sorted(coin_list, key=functools.cmp_to_key(customCmp), reverse = True)
if (len(coin) > 50):
del coin[50:]
#字符串排序
def customCmp(a, b):
if len(a) < len(b):
return -1
elif len(a) > len(b):
return 1
#endif
if a < b:
return -1
elif a > b:
return 1
else:
return 0
#更新排行榜
def updateRank(r, pass_list, coin_list):
pass_list.sort(key=take_pass, reverse=True)
pass_rank = []
for pass_index in range(min(50, len(pass_list))):
pass_rank.append(pass_list[pass_index])
r.set("game2003api:pass_rank", json.dumps(pass_rank))
coin = sorted(coin_list, key=functools.cmp_to_key(customCmp), reverse = True)
coin_rank = []
for coin_index in range(min(50, len(coin))):
coin_rank.append(coin[coin_index])
r.set("game2003api:coin_rank", json.dumps(coin_rank))
def internalDayReadMysqlData():
mysql_conf = json.loads(open(CONFIG_DIR + '/rankserver.mysql.cluster.json', 'r').read())
pass_list = []
coin_list = []
for conf in mysql_conf:
conn = pymysql.connect(host = conf['host'],
port = conf['port'],
user = conf['user'],
passwd = conf['passwd'],
db = 'gamedb2003_' + str(conf['instance_id']),
charset = 'utf8'
)
cursor = conn.cursor()
last_idx = 0
temp_idx = 0
while 1:
cursor.execute('SELECT accountid, user_name, avatar_url, pass, coin_num, idx'
' FROM user WHERE idx > %s LIMIT 0, 1000' % (last_idx))
has_data = False
for row in cursor:
has_data = True
#更新通关榜
refreshData(row, pass_list)
#更新金钱榜
refreshCoinData(row, coin_list)
temp_idx = int(row[5])
if (temp_idx > last_idx) :
last_idx = int(row[5])
if not has_data:
break
r = getRedis()
updateRank(r, pass_list, coin_list)
#每日定时读取mysql里的数据生成排行榜写入redis后php读取redis返回客户端显示
def dayReadMysqlData(rushtime):
internalDayReadMysqlData()
tornado.ioloop.IOLoop.current().call_at(getDaySeconds(time.time(), 1) + rushtime,
lambda : dayReadMysqlData(rushtime)
)
#每5分钟读取mysql里发生改变过的数据更新排行榜
def readMysqlData(rushtime):
mysql_conf = json.loads(open(CONFIG_DIR + '/rankserver.mysql.cluster.json', 'r').read())
r = getRedis()
pass_list_str = r.get("game2003api:pass_rank")
if (not pass_list_str):
pass_list = []
else:
pass_list = json.loads(pass_list_str)
coin_list_str = r.get("game2003api:coin_rank")
if (not coin_list_str):
coin_list = []
else:
coin_list = json.loads(coin_list_str)
for conf in mysql_conf:
conn = pymysql.connect(host = conf['host'],
port = conf['port'],
user = conf['user'],
passwd = conf['passwd'],
db = 'gamedb2003_' + str(conf['instance_id']),
charset = 'utf8'
)
cursor = conn.cursor()
last_idx = 0
temp_idx = 0
while 1:
cursor.execute('SELECT accountid, user_name, avatar_url, pass, coin_num, idx FROM user '
' WHERE idx > %s LIMIT 0, 1000' % (last_idx))
has_data = False
for row in cursor:
has_data = True
#更新击杀榜
delRepeatData(row, pass_list)
refreshData(row, pass_list)
temp_idx = int(row[5])
if (temp_idx > last_idx) :
last_idx = int(row[5])
if not has_data:
break
last_idx = 0
temp_idx = 0
while 1:
cursor.execute('SELECT accountid, user_name, avatar_url, pass, coin_num, idx FROM user '
' WHERE idx > %s LIMIT 0, 1000' % (last_idx))
has_data = False
for row in cursor:
has_data = True
#更新胜场榜
delRepeatData(row, coin_list)
refreshCoinData(row, coin_list)
temp_idx = int(row[5])
if (temp_idx > last_idx) :
last_idx = int(row[5])
if not has_data:
break
updateRank(r, pass_list, coin_list)
tornado.ioloop.IOLoop.current().call_later(rushtime,
lambda : readMysqlData(rushtime)
)
class SelfCheckingHandler(tornado.web.RequestHandler):
def get(self):
self.write(json.dumps({
'errcode': 0,
'errmsg': '',
'healthy': 1,
'max_rundelay': 10
}))
def make_app():
return tornado.web.Application([
(r"/webapp/index[\.]php", SelfCheckingHandler),
])
if __name__ == "__main__":
conf = json.loads(open(CONFIG_DIR + '/rankserver.json', 'r').read())
app = make_app()
app.listen(conf['listen_port'])
conf['rushtime'] = 300
tornado.ioloop.IOLoop.current().call_later(conf['rushtime'],
lambda : readMysqlData(conf['rushtime'])
)
conf['day_rushtime'] = 5 * 3600
tornado.ioloop.IOLoop.current().call_at(getDaySeconds(time.time(), 1) + conf['day_rushtime'],
lambda : dayReadMysqlData(conf['day_rushtime'])
)
tornado.ioloop.IOLoop.current().start()