pay/tools/pay_backend.py
aozhiwei cb9f63c389 1
2019-08-23 15:00:49 +08:00

192 lines
6.4 KiB
Python

# -*- coding: utf-8 -*-
import os
import sys
import json
import time
import datetime
import hashlib
import binascii
import pymysql
import traceback
import urllib.request
import tornado.ioloop
import tornado.web
mysql_cluster_json = json.loads(open('../config/pay_backend.mysql.cluster.json', 'r').read())
notifyapi_json = json.loads(open('../config/pay_backend.notifyapi.json', 'r').read())
last_idx = 0
confirmed_order_list = []
def info(msg):
print(str(datetime.datetime.now()) + '[INFO] ' + msg, flush = True)
def getMysqlConn(accountid):
hash_code = binascii.crc32(accountid.encode())
assert(hash_code >= 0)
mysql_conf = mysql_cluster_json[hash_code % len(mysql_cluster_json)]
return pymysql.connect(host = mysql_conf['host'],
port = mysql_conf['port'],
user = mysql_conf['user'],
passwd = mysql_conf['passwd'],
db = 'paydb',
charset = 'utf8'
)
def md5Sign(params, secret, timestamp, connstr = '&', secret_connstr = ':'):
params_str = ''
for key in sorted(params.keys()):
params_str = params_str + key + '=' + str(params[key]) + connstr
if params_str != '' and connstr != '':
params_str = params_str[0:-1]
str1 = params_str + secret_connstr + str(timestamp) + secret
print(str1)
try:
m5 = hashlib.md5()
m5.update(str1.encode('utf-8'))
return m5.hexdigest()
except Exception as e:
info('md5Sign error: ' + str(e))
def urlencodeParams(params):
return urllib.parse.urlencode(params)
params_str = ''
for key in sorted(params.keys()):
params_str = params_str + key + '=' + urllib.urlencode(str(params[key])) + '&'
return params_str
def getDaySeconds(time_val, incdays):
time_zone = 8
dayseconds = int((time_val + time_zone * 3600)/3600/24 + incdays) * 3600 * 24 - 3600 * time_zone;
info(dayseconds)
return dayseconds
def fetchConfirmedOrderList():
global last_idx
global confirmed_order_list
try:
conn = getMysqlConn('')
cursor = conn.cursor()
cursor.execute('SELECT idx, orderid '
'FROM confirmed_order WHERE idx>%d AND status=0;' % last_idx)
rows = cursor.fetchall();
for row in rows:
confirmed_order_list.append({
'idx' : int(row[0]),
'orderid': row[1]
})
last_idx = int(row[0])
except Exception as e:
print(e)
return
def confirmOneOrder(orderid):
try:
conn = getMysqlConn('')
cursor = conn.cursor()
cursor.execute('UPDATE orderinfo SET status=1, confirmtime=%d '
'WHERE orderid="%s";' %
(
time.time(),
conn.escape_string(orderid))
)
conn.commit()
cursor.execute('UPDATE confirmed_order SET status=1, confirm_time=%d '
'WHERE orderid="%s";' %
(
time.time(),
conn.escape_string(orderid))
)
conn.commit()
except Exception as e :
info('confirOneOrder orderid:' + orderid + ' error:' + str(e))
traceback.print_exc(file=sys.stdout)
def sendOneOrder(conf, idx, orderid):
global notifyapi_json
try:
conn = getMysqlConn('')
cursor = conn.cursor()
cursor.execute('SELECT sp_pay_result, accountid, itemid, price, orderid, gameid, status '
'FROM orderinfo WHERE orderid="%s";' % conn.escape_string(orderid))
row = cursor.fetchone()
if (not row) or (row[0] != 1):
return True
info(row[4])
if row[6] == 0:
timestamp = time.time()
params = {
'account_id' : row[1],
'orderid' : row[4],
'itemid' : row[2],
'itemnum': 1,
'amount' : row[3],
}
secret = 'fc38349c5d084e920925e614c420be9f'
md5signstr = md5Sign(params, secret, timestamp)
url = notifyapi_json[str(row[5])]['notify_url'] + '&timestamp=' + str(timestamp) + '&sign=' + md5signstr + \
'&' + urlencodeParams(params)
req = urllib.request.Request(url)
data = urllib.request.urlopen(req).read()
info(str(data))
jsonobj = json.loads(data)
if jsonobj['errcode'] != 0:
return False
confirmOneOrder(orderid)
info('sendNotify end')
return True
except Exception as e:
print('sendOneOrder error:' + e)
traceback.print_exc(file=sys.stdout)
return False
def sendNotify(conf, sendtime):
try:
if len(confirmed_order_list) <= 0:
fetchConfirmedOrderList();
handled_cout = 0
while len(confirmed_order_list) > 0 and handled_cout < 50:
confirmed_order = confirmed_order_list[0]
if sendOneOrder(conf, confirmed_order['idx'], confirmed_order['orderid']):
confirmed_order_list.pop(0)
handled_cout += 1
else:
break
except Exception as e:
info('sendNotify error: ' + str(e))
traceback.print_exc(file=sys.stdout)
#进入下一次循环
if len(confirmed_order_list) > 0:
tornado.ioloop.IOLoop.current().call_at(time.time() + 1,
lambda : sendNotify(conf, sendtime))
else:
tornado.ioloop.IOLoop.current().call_at(time.time() + sendtime,
lambda : sendNotify(conf, sendtime))
class SelfCheckingHandler(tornado.web.RequestHandler):
def get(self):
self.write(json.dumps({
'errcode': 0,
'errmsg': '',
'healthy': 1,
'max_rundelay': 10
},
separators=(',', ':')))
def make_app():
return tornado.web.Application([
(r"/webapp/index[\.]php", SelfCheckingHandler),
])
if __name__ == "__main__":
info('start!')
conf = json.loads(open('../config/pay_backend.json', 'r').read())
app = make_app()
app.listen(conf['listen_port'])
tornado.ioloop.IOLoop.current().call_at(time.time(),
lambda : sendNotify(conf, conf['notifytime']))
tornado.ioloop.IOLoop.current().start()