Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: junewu/Tools
base: c51bc543fd
...
head fork: junewu/Tools
compare: e4d0457e45
  • 2 commits
  • 37 files changed
  • 0 commit comments
  • 1 contributor
Showing with 3,103 additions and 0 deletions.
  1. +1 −0  README.md
  2. +93 −0 account.py
  3. +195 −0 ams.py
  4. +120 −0 balance.py
  5. +47 −0 check.py
  6. +62 −0 config.py
  7. +97 −0 dbutils.py
  8. +530 −0 eventsocket.py
  9. +263 −0 fs_client.py
  10. +52 −0 handlers/BalanceHandler.py
  11. BIN  handlers/BalanceHandler.pyc
  12. +69 −0 handlers/BaseHandler.py
  13. BIN  handlers/BaseHandler.pyc
  14. +59 −0 handlers/CallHandler.py
  15. BIN  handlers/CallHandler.pyc
  16. +49 −0 handlers/LoginHandler.py
  17. +45 −0 handlers/RechargeHandler.py
  18. BIN  handlers/RechargeHandler.pyc
  19. +215 −0 handlers/RegisterHandler.py
  20. BIN  handlers/RegisterHandler.pyc
  21. +92 −0 handlers/ServiceHandler.py
  22. +13 −0 handlers/__init__.py
  23. BIN  handlers/__init__.pyc
  24. +8 −0 modules/__init__.py
  25. BIN  modules/__init__.pyc
  26. +127 −0 modules/call.py
  27. BIN  modules/call.pyc
  28. +4 −0 modules/register.py
  29. BIN  modules/register.pyc
  30. +180 −0 myLogger.py
  31. +52 −0 recharge.py
  32. +307 −0 register.py
  33. +15 −0 requirements.txt
  34. +1 −0  templates/json.html
  35. +308 −0 tool.py
  36. +75 −0 webapp.py
  37. +24 −0 worker.py
View
1  README.md
@@ -0,0 +1 @@
+## Nothing
View
93 account.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+import dbutils
+import balance
+import datetime
+import time
+import tool
+import config
+import ams
+import check
+import traceback
+
+
+class Account:
+ """tool_dict contains a query connection of the database connection pool, and a update connection of
+ the database connection pool"""
+ def __init__(self, logger, tool_dict):
+ self.logger = logger
+ self.tool_dict = tool_dict
+
+ def get_bind_relation(self, uid):#获得绑定关系
+ dbHandler = dbutils.DBHandler(self.logger, self.tool_dict['read_conn'])
+ try:
+ sql = 'SELECT uid, caller FROM KC_DB.`T_ImsiBindAccount` WHERE uid = %s'
+ rs = dbHandler.query_one(sql, [uid])
+ return rs if rs else ['', '']
+ except:
+ self.logger.error(u'Account.get_bind_mobile() 查询异常:%s' % traceback.format_exc())
+
+ def remove_bind_relation(self, uid):#删除绑定关系
+ dbHandler = dbutils.DBHandler(self.logger, self.tool_dict['read_conn'])
+ try:
+ sql = "DELETE FROM KC_DB.`T_ImsiBindAccount` WHERE uid = %s" % uid
+ return dbHandler.single_update(sql, [uid])
+ except:
+ self.logger.error(u'Account.remove_bind_relation() 执行异常:%s' % traceback.format_exc())
+
+ def login(self, account, md5psw, version_no, os_type, ip='', bid='kc', pform='', psystem='', ptype='', cversion='',
+ callback=None):#登录
+ self.logger.info(u"收到登录请求:帐号/手机号码==%s,版本==%s,版本号==%s,产品==%s" % (account, os_type, version_no, bid))
+ result = {}
+ try:
+ if not callback:
+ callback = tool.return_values
+ if not account or len(md5psw) != 32:
+ result['result'], result['reason'] = "100004", u'账号密码验证失败'
+ return callback(result)
+ #检查是用手机号码还是帐号登录的
+ login_type = 'mobile' if check.is_mobile(account) == 1 else 'kc'
+ # phone = account if login_type == 'mobile' else ''
+ # res = ams.login(login_type, account, md5psw, 'mobile', ip, bid, pform, psystem, ptype, cversion)
+ job = self.tool_dict['queue'].enqueue(ams.login, login_type, account, md5psw, 'mobile', ip, bid, pform,
+ psystem, ptype, cversion)
+ #####################################################################################
+ time.sleep(2)
+ res = job.result
+ if res['code'] == '2':
+ self.logger.info(u"帐号不存在:%s" % account)
+ result['result'], result['reason'] = "100008", u'帐号不存在'
+ return callback(result)
+ elif res['code'] == '10':
+ self.logger.info(u"登录失败,账号密码错误:%s" % account)
+ result['result'], result['reason'] = "100004", u'账号密码验证失败'
+ return callback(result)
+ elif res['code'] == '0':#登录成功
+ uid, phone, password = ams.getInfo(login_type, account, bid)
+ caller = self.get_bind_relation(account)[1]
+ caller = phone if not caller else caller
+ msg, uid_list, calltime = '', [], 0
+ first_login = res.get('first', 0)
+ if int(first_login) == 1 or uid in uid_list:
+ msg = config.FirstLoginMsg % (datetime.date.today() + datetime.timedelta(days=7)).strftime("%Y-%m-%d")
+ elif version_no >= '1.4.2':
+ balance_info = balance.Balance(self.logger, self.tool_dict).get_balance_2(uid, bid)
+ msg = config.NormalLoginMsg % balance_info
+ calltime = balance_info['calltime']
+ self.logger.info(u"登录成功:KC号==%s,手机==%s,版本==%s,版本号==%s" % (uid, phone, os_type, version_no))
+ result = {'result': '0', 'mobile': phone, 'kcid': uid, 'caller': caller, 'msg': msg, 'first': first_login,
+ 'calltime': str(calltime), 'reason': u'登录成功'}
+ return callback(result)
+ else:
+ self.logger.warn(u"%s登录失败,AMS返回码:%s" % (account, res['code']))
+ result['result'], result['reason'] = '999998', u'未知错误,错误码:%s' % res['code']
+ return callback(result)
+ except:
+ result["result"], result["reason"] = "999999", u"服务器繁忙,请稍后再试"
+ self.logger.error(u'Account.login() 发生错误:%s' % traceback.format_exc())
+ finally:
+ self.logger.info(u'登录结果:%s' % result)
View
195 ams.py
@@ -0,0 +1,195 @@
+#!/usr/local/bin/python
+#coding=utf-8
+import urllib2, httplib, urllib
+import logging, traceback, datetime, random
+import config, tool
+
+logger = tool.mylog(__name__)
+
+
+def rc4(data, key):
+ x = 0
+ box = range(256)
+ for i in range(256):
+ x = (x + box[i] + ord(key[i % len(key)])) % 256
+ box[i], box[x] = box[x], box[i]
+ x = 0
+ y = 0
+ out = []
+ for char in data:
+ x = (x + 1) % 256
+ y = (y + box[x]) % 256
+ box[x], box[y] = box[y], box[x]
+ out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256]))
+ return ''.join(out)
+
+
+def hex2str(s):
+ '''16进制转字符串'''
+ if s[:2] == '0x' or s[:2] == '0X':
+ s = s[2:]
+ res = ""
+ for i in range(0, len(s), 2):
+ hex_dig = s[i:i + 2]
+ res += (chr(int(hex_dig, base=16)))
+ return res
+
+
+def str2hex(string):
+ '''字符串转16进制'''
+ res = ""
+ for s in string:
+ hex_dig = hex(ord(s))[2:]
+ if len(hex_dig) == 1:
+ hex_dig = "0" + hex_dig
+ res += hex_dig
+ return res
+
+
+def getAmsResp(amsFunc, params,timeout=10):
+ try:
+ #httpConn = httplib.HTTPConnection(AMS_HOST, AMS_PORT)
+ #httpConn.request("POST", amsFunc, params + "&" + getAmsSign(),{"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"})
+ #f = httpConn.getresponse()
+ url = "http://" + config.AMS_HOST + ":" + str(config.AMS_PORT) + amsFunc + "?" + params + "&" + getAmsSign()
+ res = tool.http_get(url,timeout)
+ # f = urllib2.urlopen(url)
+ # res = f.read()
+ # f.close()
+ logger.info(u"AMS URL:%s;结果:%s" % (url, res))
+ return urlCode2Dict(res)
+ except:
+ logger.error("getAmsResp Fail: %s %s" % (url, traceback.format_exc()))
+ return {"code": "9999"}
+
+
+def urlCode2Dict(result):
+ '''ams返回url串转换成dict'''
+ return dict(x.split('=') for x in result.split('&'))
+
+
+def getRand():
+ n = datetime.datetime.now().strftime("%H%M%S")
+ m = str(random.randint(1000, 9999))
+ return n + m
+
+
+def getAmsSign():
+ macdate = datetime.datetime.now().strftime("%Y%m%d")
+ macrand = getRand()
+ mac = tool.md5_password(config.LOCALHOST + macdate + macrand + config.MAC_KEY)
+ mac_dict = {"macip": config.LOCALHOST, \
+ "macdate": macdate, \
+ "macrand": macrand, \
+ "mac": mac}
+ return urllib.urlencode(mac_dict)
+
+
+def info(accounttype, account, brandid='kc'):
+ '''查询kc/手机/密码'''
+ param = urllib.urlencode({"accounttype": accounttype, \
+ "account": account, "bid": brandid})
+ return getAmsResp("/ams2/info.act", param,timeout=40)
+
+
+def login(loginType, account, password, loginfrom, ip, brandid='kc', pform='', psystem='', ptype='', cversion=''):
+ '''登录认证'''
+ param = urllib.urlencode({"loginType": loginType, \
+ "account": account, \
+ "password": password, \
+ "from": loginfrom, \
+ "ip": ip, \
+ "bid": brandid, \
+ "pform": pform, \
+ "psystem": psystem, \
+ "ptype": ptype, \
+ "cversion": cversion
+ })
+ return getAmsResp("/ams2/login.act", param,timeout=30)
+
+
+def choose(ip):
+ '''选号'''
+ return getAmsResp("/ams2/choose.act", "ip=%s" % ip)
+
+
+def kcreg(uid, password, random, invitedby, invitedflag, regfrom):
+ '''注册'''
+ return getAmsResp("/ams2/kcreg.act", "uid=%s&password=%s&random=%s&invitedby=%s&invitedflag=%s&from=%s" % uid,
+ password, random, invitedby, invitedflag, regfrom)
+
+
+def automobilereg(number, invitedby, invitedflag, regfrom, ip, ext='', brandid='kc'):
+ '''自动注册'''
+ return getAmsResp("/ams2/automobilereg.act", "number=%s&invitedby=%s&invitedflag=%s&from=%s&ip=%s&ext=%s&bid=%s"
+ % (number, invitedby, invitedflag, regfrom, ip, ext, brandid),timeout=40)
+
+
+def mobilereg(number, invitedby, invitedflag, regfrom, ip, ext='', brandid='kc'):
+ '''短信注册'''
+ return getAmsResp("/ams2/mobilereg.act", "number=%s&invitedby=%s&invitedflag=%s&from=%s&ip=%s&ext=%s&bid=%s"
+ % (number, invitedby, invitedflag, regfrom, ip, ext, brandid),timeout=40)
+
+
+def unbind(number, uid, password):
+ '''绑定请求'''
+ return getAmsResp("/ams2/unbind.act", "number=%s&uid=%s&password=%s" % (number, uid, password),timeout=40)
+
+
+def bindapply(number, uid, password, brandid='kc'):
+ '''绑定请求'''
+ return getAmsResp("/ams2/bindapply.act", "number=%s&uid=%s&password=%s&bid=%s" %
+ (number, uid, password, brandid),timeout=40)
+
+
+def bindsubmit(uid, number, verifyCode, brandid='kc'):
+ '''提交绑定'''
+ return getAmsResp("/ams2/bindsubmit.act", "number=%s&uid=%s&verifyCode=%s&bid=%s" %
+ (number, uid, verifyCode, brandid),timeout=40)
+
+
+def delacctnotify(accounts):
+ '''APS删除账户通知'''
+ return getAmsResp("/ams2/delacctnotify.act", "from=APS&accounts=%s" % accounts)
+
+
+def changepwd(uid, oldpwd, newpwd):
+ '''修改密码'''
+ return getAmsResp("/ams2/changepassword.act", "uid=%s&oldpassword=%s&newpassword=%s" % (uid, oldpwd, newpwd))
+
+
+def check_pwd(type, account, md5pwd):
+ if not account or account == 'null' or not account.isdigit():
+ return {"result": 1}
+ if len(str(account)) == 11 and str(account)[0] == '1':
+ type = 'mobile'
+ res = info(type, account)
+ if 'code' in res and str(res['code']) == '0':
+ pwd = res['password']
+ phone = res['number']
+ uid = res['uid']
+ if tool.md5_password(rc4(hex2str(pwd), config.AMS_KEY)) == md5pwd:
+ return {"result": 0, "kcid": uid, "phone": phone}
+ else:
+ return {"result": 2}
+ return {"result": 1}
+
+
+def getInfo(account_type, account, brandid='kc'):
+ kcid, mobile, password = '', '', ''
+ if not account or account == 'null' or not str(account).isdigit():
+ return kcid, mobile, password
+ if len(str(account)) == 11 and str(account)[0] == '1':
+ account_type = 'mobile'
+ res = info(account_type, account, brandid)
+ if 'code' in res and str(res['code']) == '0':
+ kcid = res['uid']
+ mobile = res['number']
+ password = rc4(hex2str(res['password']), config.AMS_KEY)
+ return kcid, mobile, password
+
+
+if __name__ == '__main__':
+ #print automobilereg('13430789767', '9646', '1', 'mobile', '1.1.1.1')
+ pass
+
View
120 balance.py
@@ -0,0 +1,120 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+import random
+import ujson as json
+import config
+import tool
+import check
+
+
+class Balance:
+ """tool_dict contains a connection of the database connection pool"""
+ def __init__(self, logger, tool_dict):
+ self.logger = logger
+ self.tool_dict = tool_dict
+
+ def can_call(self, uid):
+ sign = tool.md5_password("%s%s" % (uid, config.kckey))
+ url = config.balance_url % (config.chkfee_server, uid, sign)
+ self.logger.info(u"查询用户余额url:%s" % url)
+ return json.loads(tool.http_get(url))
+
+ #查询余额
+ def get_balance(self, uid, newclient=False, bid='kc'):
+ ordersn = ''
+ result = {'result': '-11'}
+ #results = '{"result" : "-1","reason":"%s"}' % u'获取失败,请稍后重试'
+ reason= u'获取失败,请稍后重试'
+ results = {"result": "-1", "reason": reason}
+ for i in range(0, 18):
+ ordersn += '%s' % random.randint(1, 9)
+ sign = tool.md5_password("ordersn=%s&uid=%s&key=%s" %(ordersn,uid,config.kckey))
+ url = "http://%s/user_wallet?ordersn=%s&uid=%s&sign=%s&bid=%s" %(config.chkfee_server,ordersn,uid,sign,bid)
+ self.logger.info("balance: %s" % url)
+ #print url
+ result = tool.http_get(url,timeout=20)
+ #log.info(result)
+
+ if result:
+ results = json.loads(result)
+ if int(results['result']) == 0:
+ del results['willactive']
+ results['valid_date'] = results['valid_date'][:10]
+ results['calltime'] = int(results['balance'])/10
+ results['balance'] = '%.2f' % (float(results['balance'])/100)
+ results['display_vaild_date'] = '%s' % (results.get('display_vaild_date',''))
+ else:
+ return '{"result":"%s"}' % results['result']
+
+ if newclient:
+ results['return_string'] = u"账号:%s\\n" % uid
+ results['return_string'] += u"总账户余额:%s\\n" % results['balance']
+ results['return_string'] += u"账户有效期:%s\\n" % results['valid_date']
+
+ if results['display_vaild_date']:
+ results['return_string'] += u"去电显号有效期:%s\\n" % results['display_vaild_date']
+ else:
+ results['return_string'] += u"去电显号有效期:您没有开通此项业务\\n"
+ results['phone'] = check.get_bind_mobile(uid)
+ results['packagelist'] = []
+ return results
+
+ def get_balance_2(self, uid, bid='kc', callback=None):
+ results = {'result': '500', 'reason': 'server error'}
+ if not callback:
+ callback = tool.return_values
+ try:
+ ordersn = ''
+
+ for i in range(0, 18):
+ ordersn += '%s' % random.randint(1, 9)
+ sign = tool.md5_password("ordersn=%s&uid=%s&key=%s" % (ordersn, uid, config.kckey))
+ url = "http://%s/user_wallet?ordersn=%s&uid=%s&sign=%s" % (config.chkfee_server, ordersn, uid, sign)
+ #log.info(u"balance: %s" % url)
+ #log.info(url)
+ result = tool.http_get(url,timeout=20)
+ results = json.loads(result)
+ #log.info(results)
+ if 'result' in results and int(results['result']) == 0:
+ if int(results['balance']) <= 0:
+ results['calltime'] = 0
+ else:
+ if bid in ['uu']:
+ results['calltime'] = int(results['balance'])/12
+ else:
+ results['calltime'] = int(results['balance'])/8
+
+ results['valid_date'] = results['valid_date'][:10]
+ results['balance'] = '%.2f' % (float(results['balance']) / 100)
+ results['balance_info'] = u"账户余额%(balance)s元,可通话%(calltime)s分钟" % results
+ else:
+ results['balance_info'] = u"余额为0"
+ results['valid_date'] = ''
+ results['calltime'] = 0
+ results['result'] = 0
+ #balance_info = u"账户余额%(balance)s元,可通话%(calltime)s分钟" % results
+
+ if uid in TESTCALLTIME:
+ results['calltime'] = TESTCALLTIME[uid]
+ except:
+ pass
+ return callback(results)
+
+ #查询余额
+ def query_balance(self, uid, md5psw, newclient, bid, callback=None):
+ if not callback:
+ callback = tool.return_values
+ res = {}
+ #验证用户名密码
+ uid = check.check_uid_pwd(str(uid), md5psw)
+ if uid == -1:
+ res['result'], res['reason'] = '-2', u'号码或者密码错误'
+ return callback(res)
+ #查询用户余额 res = self.get_balance(uid, newclient, bid)
+ job = self.tool_dict['queue'].enqueue(self.get_balance, uid, newclient, bid)
+ res = job.result
+ return callback(res)
View
47 check.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+import ujson as json
+import ams
+import tool
+import re
+
+
+#验证md5加密字符串,md5string 用户传的md5串 ,check_string 明文字符串
+#返回说明 返回-1:两个字符串不匹配 1:验证成功
+def check_key(md5string, check_string):
+ # log.info("请求验证码错误:实际==%s 客户端==%s" % (check_key, md5string))
+ return -1 if md5string != tool.md5_password(check_string) else 1
+
+
+#密码校验
+def check_uid_pwd(uid, md5pwd):
+ _type = "mobile" if len(uid) == 11 and uid[0] == '1' else 'kc'
+ _uid, phone, password = ams.getInfo(_type, str(uid))
+ #print password
+ if not password or check_key(md5pwd, password) == -1:
+ return -1
+ else:
+ return {"uid": _uid, "mobile": phone, "password": password}
+
+
+#检测是否是手机号 返回1:是手机号 -1:不是手机号
+def is_mobile(phone):
+ #取号码后11位
+ #mobile = phone[-11:]
+ if len(phone) != 11:
+ return - 1
+ else:
+ regex = ur'(?:1|1|1)[0-9]{10}'
+ return 1 if re.match(regex, phone) else -1
+
+
+#获取用户绑定kc的手机号码
+def get_bind_mobile(uid):
+ if uid:
+ _type = "mobile" if len(uid) == 11 and uid[0] == '1' else 'kc'
+ res = ams.info(_type, str(uid))
+ return res['number'] if res['code'] == '0' else ''
View
62 config.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+import MySQLdb.cursors
+
+
+#生产环境
+isDebug = True
+
+#运行端口
+server_port = 9999
+
+#数据库连接配置
+# KC_DB = {"host":"192.168.1.199","user":"root","passwd":"cnhawk.org","db":"KC_DB","charset":"utf8"}
+# KC_DB_FIELD_DICT = {"host":"192.168.1.199","user":"root","passwd":"cnhawk.org","db":"KC_DB","charset":"utf8",'cursorclass':MySQLdb.cursors.DictCursor}
+# KC_DB_BACK = {"host":"192.168.1.199","user":"root","passwd":"cnhawk.org","db":"KC_DB","charset":"utf8"}
+DB_mobile = {"host": "192.168.1.199", "user": "root", "passwd": "cnhawk.org", "db": "mobile", "charset": "utf8",
+ 'cursorclass': MySQLdb.cursors.DictCursor}
+
+#sentry client key
+raven_client = 'http://a5fe8f10b9584cc9aadfa4859ff2b822:3d144177e4ed4b2cb878e1e327aa824f@sentry.shengqianliao.com/3'
+
+#手机客户端http请求验证密钥
+key = "hc_call@5tshow.com"
+push_key = "6RxaD|-Vp=@w }j!PGsaD#7o-ecgroWN rt9>3JF7EY%|9YSxSPxx!jY,G;%r8-["
+
+is_use_hu_gateway = True
+
+#新回拨KEY
+NEW_CB_KEY = 'keepc'
+
+'''bc系统接口配置'''
+#余额查询接口访问密码
+kckey = "guoling!@#456"
+
+#查询余额专用wallet
+chkfee_server = "127.0.0.1:9998"
+
+#AMS配置信息
+AMS_KEY = "1bb762f7ce24ceee"
+AMS_HOST = "hcsql.com"
+# AMS_HOST = "localhost"
+AMS_PORT = 8080
+MAC_KEY = "0859db5b7b8ae8fe4b0d344af4d11199"
+LOCALHOST = "113.11.199.87"
+
+FirstLoginMsg = u"恭喜您,注册成功!您将获赠最长60分钟的免费通话时长,有效期至%s,快去体验吧!"
+NormalLoginMsg = u"谢谢你再次使用!您还有通话时长%(calltime)s分钟,有效期至%(valid_date)s"
+
+"""API URL"""
+#新回拨接口URL
+new_cb_url1 = "http://121.14.118.31:8888/callback?sn=%s&kcid=%s&caller=%s&called=%s&ref=%s&display=%s&resv=%s&sign=%s&brand=%s"
+new_cb_url2 = "http://121.14.118.31:8888/callback?sn=%s&kcid=%s&caller=%s&called=%s&ref=%s&display=%s&resv=%s&sign=%s&brand=%s"
+new_cb_url3 = "http://121.14.118.31:8888/callback?sn=%s&kcid=%s&caller=%s&called=%s&ref=%s&display=%s&resv=%s&sign=%s&brand=%s"
+new_cb_url4 = "http://121.14.118.31:8888/callback?sn=%s&kcid=%s&caller=%s&called=%s&ref=%s&display=%s&resv=%s&sign=%s&brand=%s"
+new_cb_url5 = "http://121.14.118.31:8888/callback?sn=%s&kcid=%s&caller=%s&called=%s&ref=%s&display=%s&resv=%s&sign=%s&brand=%s"
+
+#查询余额
+balance_url = "http://%s/can_call_2?uid=%s&sign=%s"
View
97 dbutils.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+import traceback
+
+
+class DBHandler:
+
+ def __init__(self, logger, db_conn):
+ self.conn = db_conn
+ self.cursor = db_conn.cursor()
+ self.logger = logger
+
+ #查询唯一记录
+ def query_one(self, sql, param=None):
+ conn, cursor = self.conn, self.cursor
+ try:
+ if conn and cursor and sql:
+ self.logger.info(sql % tuple(param)) if param else self.logger.info(sql)
+ cursor.execute(sql, param) if param else cursor.execute(sql)
+ return cursor.fetchone()
+ else:
+ self.logger.info(u'数据库连接或为sql语句空,或参数错误')
+ except:
+ self.logger.error(u'dbHandler.query_one() 查询异常:%s' % traceback.format_exc())
+
+ #查询指定数量的记录
+ def query_many(self, sql, num, param=None):
+ conn, cursor = self.conn, self.cursor
+ try:
+ if conn and cursor and sql:
+ self.logger.info(sql % tuple(param)) if param else self.logger.info(sql)
+ cursor.execute(sql, param) if param else cursor.execute(sql)
+ return cursor.fetchmany(num)
+ else:
+ print(u'数据库连接或为sql语句空,或参数错误')
+ except:
+ print(u'dbHandler.query_many() 查询异常:%s' % traceback.format_exc())
+
+ #查询所有记录
+ def query_all(self, sql, param=None):
+ conn, cursor = self.conn, self.cursor
+ try:
+ if conn and cursor and sql:
+ self.logger.info(sql % tuple(param)) if param else self.logger.info(sql)
+ cursor.execute(sql, param) if param else cursor.execute(sql)
+ return cursor.fetchall()
+ else:
+ print(u'数据库连接或为sql语句空,或参数错误')
+ except:
+ print(u'dbHandler.query_all() 查询异常:%s' % traceback.format_exc())
+
+ #执行单条insert、update、delete语句
+ def single_update(self, sql, param):
+ conn, cursor = self.conn, self.cursor
+ try:
+ if conn and cursor and sql and param:
+ conn.begin()
+ self.logger.info(sql % tuple(param)) if param else self.logger.info(sql)
+ return cursor.execute(sql, param)
+ else:
+ print(u'数据库连接或为sql语句空,或参数错误')
+ except:
+ print(u'dbHandler.single_update() sql语句执行发生异常:%s' % traceback.format_exc())
+
+ #执行批量insert、update、delete语句
+ def batch_update(self, sql, param):
+ conn, cursor = self.conn, self.cursor
+ try:
+ if conn and cursor and sql and isinstance(param, list):
+ conn.begin()
+ self.logger.info(sql % tuple(param)) if param else self.logger.info(sql)
+ return cursor.executemany(sql, param)
+ else:
+ print(u'数据库连接或为sql语句空,或参数错误')
+ except:
+ print(u'dbHandler.batch_update() sql语句执行发生异常:%s' % traceback.format_exc())
+
+ #关闭游标,释放连接
+ def close(self):
+ if self.cursor:
+ self.cursor.close()
+ if self.conn:
+ self.conn.close()
+
+ #提交事务
+ def commit(self):
+ if self.conn:
+ self.conn.commit()
+
+ #事务回滚
+ def rollback(self):
+ if self.conn:
+ self.conn.rollback()
View
530 eventsocket.py
@@ -0,0 +1,530 @@
+# coding: utf-8
+#
+# Twisted protocol for the FreeSWITCH's Event Socket
+#
+# Version: MPL 1.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+
+"Twisted protocol for the FreeSWITCH Event Socket"
+
+import types
+import string
+import re, urllib
+from cStringIO import StringIO
+from twisted.python import log
+from twisted.protocols import basic
+from twisted.internet import defer, reactor, protocol
+
+__version__ = "0.1.4"
+
+class EventError(Exception):
+ pass
+
+class AuthError(Exception):
+ pass
+
+class _O(dict):
+ """Translates dictionary keys to instance attributes"""
+ def __setattr__(self, k, v):
+ dict.__setitem__(self, k, v)
+
+ def __delattr__(self, k):
+ dict.__delitem__(self, k)
+
+ def __getattribute__(self, k):
+ try:
+ return dict.__getitem__(self, k)
+ except KeyError:
+ return dict.__getattribute__(self, k)
+
+class EventSocket(basic.LineReceiver):
+ delimiter = "\n"
+
+ def __init__(self):
+ self.__ctx = None
+ self.__rawlen = None
+ self.__io = StringIO()
+ self.__crlf = re.compile(r"[\r\n]+")
+ self.__rawresponse = [
+ "api/response",
+ "text/disconnect-notice",
+ ]
+
+ def send(self, cmd):
+ if isinstance(cmd, types.UnicodeType):
+ cmd = cmd.encode("utf-8")
+ self.transport.write(cmd+"\n\n")
+
+ def rawSend(self, stuff):
+ if isinstance(stuff, types.UnicodeType):
+ stuff = stuff.encode('utf-8')
+ self.transport.write(stuff)
+
+ def sendmsg(self, name, arg=None, uuid="", lock=False):
+ if isinstance(name, types.UnicodeType):
+ name = name.encode("utf-8")
+ if isinstance(arg, types.UnicodeType):
+ arg = arg.encode("utf-8")
+
+ self.transport.write("sendmsg %s\ncall-command: execute\n" % uuid)
+ self.transport.write("execute-app-name: %s\n" % name)
+ if arg:
+ self.transport.write("execute-app-arg: %s\n" % arg)
+ if lock is True:
+ self.transport.write("event-lock: true\n")
+
+ self.transport.write("\n\n")
+
+ def processLine(self, ev, line):
+ try:
+ k, v = self.__crlf.sub("", line).split(":", 1)
+ k = k.replace("-", "_").strip()
+ v = urllib.unquote(v.strip())
+ ev[k] = v
+ except:
+ pass
+
+ def parseEvent(self, isctx=False):
+ ev = _O()
+ self.__io.reset()
+
+ for line in self.__io:
+ if line == "\n":
+ break
+ self.processLine(ev, line)
+
+ if not isctx:
+ rawlength = ev.get("Content_Length")
+ if rawlength:
+ ev.rawresponse = self.__io.read(int(rawlength))
+
+ self.__io.reset()
+ self.__io.truncate()
+ return ev
+
+ def readRawResponse(self):
+ self.__io.reset()
+ chunk = self.__io.read(int(self.__ctx.Content_Length))
+ self.__io.reset()
+ self.__io.truncate()
+ return _O(rawresponse=chunk)
+
+ def dispatchEvent(self, ctx, event):
+ ctx.data = _O(event.copy())
+ reactor.callLater(0, self.eventReceived, _O(ctx.copy()))
+ self.__ctx = self.__rawlen = None
+
+ def eventReceived(self, ctx):
+ pass
+
+ def lineReceived(self, line):
+ if line:
+ self.__io.write(line+"\n")
+ else:
+ ctx = self.parseEvent(True)
+ rawlength = ctx.get("Content_Length")
+ if rawlength:
+ self.__ctx = ctx
+ self.__rawlen = int(rawlength)
+ self.setRawMode()
+ else:
+ self.dispatchEvent(ctx, _O())
+
+ def rawDataReceived(self, data):
+ if self.__rawlen is None:
+ rest = ""
+ else:
+ data, rest = data[:self.__rawlen], data[self.__rawlen:]
+ self.__rawlen -= len(data)
+
+ self.__io.write(data)
+ if self.__rawlen == 0:
+ if self.__ctx.get("Content_Type") in self.__rawresponse:
+ self.dispatchEvent(self.__ctx, self.readRawResponse())
+ else:
+ self.dispatchEvent(self.__ctx, self.parseEvent())
+ self.setLineMode(rest)
+
+class EventProtocol(EventSocket):
+ def __init__(self):
+ EventSocket.__init__(self)
+
+ # our internal event queue
+ self.__EventQueue = []
+
+ # callbacks by event's content-type
+ self.__EventCallbacks = {
+ "auth/request": self.authRequest,
+ "api/response": self._apiResponse,
+ "command/reply": self._commandReply,
+ "text/event-plain": self._plainEvent,
+ "text/disconnect-notice": self.onDisconnect,
+ }
+
+ def __protocolSend(self, name, args=""):
+ deferred = defer.Deferred()
+ self.__EventQueue.append((name, deferred))
+ self.send("%s %s" % (name, args))
+ return deferred
+
+ def __protocolSendRaw(self, name, args=""):
+ deferred = defer.Deferred()
+ self.__EventQueue.append((name, deferred))
+ self.rawSend("%s %s" % (name, args))
+ return deferred
+
+ def __protocolSendmsg(self, name, args=None, uuid="", lock=False):
+ deferred = defer.Deferred()
+ self.__EventQueue.append((name, deferred))
+ self.sendmsg(name, args, uuid, lock)
+ return deferred
+
+ def eventReceived(self, ctx):
+ #log.msg("GOT EVENT: %s\n" % repr(ctx), logLevel=logging.DEBUG)
+ content_type = ctx.get("Content_Type", None)
+ if content_type:
+ method = self.__EventCallbacks.get(content_type, None)
+ if callable(method):
+ return method(ctx)
+ else:
+ return self.unknownContentType(content_type, ctx)
+
+ def authRequest(self, ctx):
+ pass
+
+ def onDisconnect(self, ctx):
+ pass
+
+ def _apiResponse(self, ctx):
+ cmd, deferred = self.__EventQueue.pop(0)
+ if cmd == "api":
+ deferred.callback(ctx)
+ else:
+ deferred.errback(EventError("apiResponse on '%s': out of sync?" % cmd))
+
+ def _commandReply(self, ctx):
+ cmd, deferred = self.__EventQueue.pop(0)
+ if ctx.Reply_Text.startswith("+OK"):
+ deferred.callback(ctx)
+ elif cmd == "auth":
+ deferred.errback(AuthError("invalid password"))
+ else:
+ deferred.errback(EventError(ctx))
+
+ def _plainEvent(self, ctx):
+ name = ctx.data.get("Event_Name")
+ if name:
+ evname = "on" + string.capwords(name, "_").replace("_", "")
+
+ method = getattr(self, evname, None)
+ if callable(method):
+ return method(ctx.data)
+ else:
+ return self.unboundEvent(ctx.data, evname)
+
+ def unknownContentType(self, content_type, ctx):
+ log.err("[eventsocket] unknown Content-Type: %s" % content_type,
+ logLevel=log.logging.DEBUG)
+
+ def unboundEvent(self, ctx, evname):
+ log.err("[eventsocket] unbound Event: %s" % evname,
+ logLevel=log.logging.DEBUG)
+
+ # EVENT SOCKET COMMANDS
+ def api(self, args):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#api"
+ return self.__protocolSend("api", args)
+
+ def sendevent(self, name, args=dict(),body=None):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#sendevent"
+ parsed_args = [name]
+ for k,v in args.iteritems():
+ parsed_args.append('%s: %s' % (k, v))
+ parsed_args.append('')
+ if body:
+ parsed_args.append(body)
+ return self.__protocolSendRaw("sendevent", '\n'.join(parsed_args))
+
+ def bgapi(self, args):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#bgapi"
+ return self.__protocolSend("bgapi", args)
+
+ def exit(self):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#exit"
+ return self.__protocolSend("exit")
+
+ def eventplain(self, args):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#event"
+ return self.__protocolSend('eventplain', args)
+
+ def eventjson(self, args):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#event"
+ return self.__protocolSend('eventjson', args)
+
+ def event(self, args):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#event"
+ return self.__protocolSendmsg("event", args, lock=True)
+
+ def linger(self, args=None):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#event"
+ return self.__protocolSend("linger", args)
+
+ def filter(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#filter
+
+ The user might pass any number of values to filter an event for. But, from the point
+ filter() is used, just the filtered events will come to the app - this is where this
+ function differs from event().
+
+ >>> filter('Event-Name MYEVENT')
+ >>> filter('Unique-ID 4f37c5eb-1937-45c6-b808-6fba2ffadb63')
+ """
+ return self.__protocolSend('filter', args)
+
+ def filter_delete(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#filter_delete
+
+ >>> filter_delete('Event-Name MYEVENT')
+ """
+ return self.__protocolSend('filter delete', args)
+
+ def verbose_events(self):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_verbose_events
+
+ >>> verbose_events()
+ """
+ return self.__protocolSendmsg('verbose_events', lock=True)
+
+ def auth(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#auth
+
+ This method is allowed only for Inbound connections."""
+ return self.__protocolSend("auth", args)
+
+ def connect(self):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket_Outbound#Using_Netcat"
+ return self.__protocolSend("connect")
+
+ def myevents(self):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#event"
+ return self.__protocolSend("myevents")
+
+ def answer(self):
+ "Please refer to http://wiki.freeswitch.org/wiki/Event_Socket_Outbound#Using_Netcat"
+ return self.__protocolSendmsg("answer", lock=True)
+
+ def bridge(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Event_Socket_Outbound
+
+ >>> bridge("{ignore_early_media=true}sofia/gateway/myGW/177808")
+ """
+ return self.__protocolSendmsg("bridge", args, lock=True)
+
+ def hangup(self, reason=""):
+ """Hangup may be used by both Inbound and Outbound connections.
+
+ When used by Inbound connections, you may add the extra `reason`
+ argument. Please refer to http://wiki.freeswitch.org/wiki/Event_Socket#hangup
+ for details.
+
+ When used by Outbound connections, the `reason` argument must be ignored.
+
+ Please refer to http://wiki.freeswitch.org/wiki/Event_Socket_Outbound for
+ details.
+ """
+ return self.__protocolSendmsg("hangup", reason, lock=True)
+
+ def sched_api(self, args):
+ "Please refer to http://wiki.freeswitch.org/wiki/Mod_commands#sched_api"
+ return self.__protocolSendmsg("sched_api", args, lock=True)
+
+ def ring_ready(self):
+ "Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_ring_ready"
+ return self.__protocolSendmsg("ring_ready")
+
+ def record_session(self, filename):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_record_session
+
+ >>> record_session("/tmp/dump.gsm")
+ """
+ return self.__protocolSendmsg("record_session", filename, lock=True)
+
+ def read(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_read
+
+ >>> read("0 10 $${base_dir}/sounds/en/us/callie/conference/8000/conf-pin.wav res 10000 #")
+ """
+ return self.__protocolSendmsg("read", args, lock=True)
+
+ def bind_meta_app(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_bind_meta_app
+
+ >>> bind_meta_app("2 ab s record_session::/tmp/dump.gsm")
+ """
+ return self.__protocolSendmsg("bind_meta_app", args, lock=True)
+
+ def wait_for_silence(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_wait_for_silence
+
+ >>> wait_for_silence("200 15 10 5000")
+ """
+ return self.__protocolSendmsg("wait_for_silence", args, lock=True)
+
+ def sleep(self, milliseconds):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_sleep
+
+ >>> sleep(5000)
+ >>> sleep("5000")
+ """
+ return self.__protocolSendmsg("sleep", milliseconds, lock=True)
+
+ def vmd(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Mod_vmd
+
+ >>> vmd("start")
+ >>> vmd("stop")
+ """
+ return self.__protocolSendmsg("vmd", args, lock=True)
+
+ def set(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_set
+
+ >>> set("ringback=${us-ring}")
+ """
+ return self.__protocolSendmsg("set", args, lock=True)
+
+ def set_global(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_set_global
+
+ >>> set_global("global_var=value")
+ """
+ return self.__protocolSendmsg("set_global", args, lock=True)
+
+ def unset(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_unset
+
+ >>> unset("ringback")
+ """
+ return self.__protocolSendmsg("unset", args, lock=True)
+
+ def start_dtmf(self):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_start_dtmf
+
+ >>> start_dtmf()
+ """
+ return self.__protocolSendmsg("start_dtmf", lock=True)
+
+ def stop_dtmf(self):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_stop_dtmf
+
+ >>> stop_dtmf()
+ """
+ return self.__protocolSendmsg("stop_dtmf", lock=True)
+
+ def start_dtmf_generate(self):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_start_dtmf_generate
+
+ >>> start_dtmf_generate()
+ """
+ return self.__protocolSendmsg("start_dtmf_generate", "true", lock=True)
+
+ def stop_dtmf_generate(self):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_stop_dtmf_generate
+
+ >>> stop_dtmf_generate()
+ """
+ return self.__protocolSendmsg("stop_dtmf_generate", lock=True)
+
+ def queue_dtmf(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_queue_dtmf
+
+ Enqueue each received dtmf, that'll be sent once the call is bridged.
+
+ >>> queue_dtmf("0123456789")
+ """
+ return self.__protocolSendmsg("queue_dtmf", args, lock=True)
+
+ def flush_dtmf(self):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_flush_dtmf
+
+ >>> flush_dtmf()
+ """
+ return self.__protocolSendmsg("flush_dtmf", lock=True)
+
+ def play_fsv(self, filename):
+ """Please refer to http://wiki.freeswitch.org/wiki/Mod_fsv
+
+ >>> play_fsv("/tmp/video.fsv")
+ """
+ return self.__protocolSendmsg("play_fsv", filename, lock=True)
+
+ def record_fsv(self, filename):
+ """Please refer to http://wiki.freeswitch.org/wiki/Mod_fsv
+
+ >>> record_fsv("/tmp/video.fsv")
+ """
+ return self.__protocolSendmsg("record_fsv", filename, lock=True)
+
+ def playback(self, filename, terminators=None, lock=True):
+ """Please refer to http://wiki.freeswitch.org/wiki/Mod_playback
+
+ The optional argument `terminators` may contain a string with
+ the characters that will terminate the playback.
+
+ >>> playback("/tmp/dump.gsm", terminators="#8")
+
+ In this case, the audio playback is automatically terminated
+ by pressing either '#' or '8'.
+ """
+ self.set("playback_terminators=%s" % terminators or "none")
+ return self.__protocolSendmsg("playback", filename, lock=lock)
+
+ def transfer(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_transfer
+
+ >>> transfer("3222 XML default")
+ """
+ return self.__protocolSendmsg("transfer", args, lock=True)
+
+ def conference(self, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Mod_conference#API_Reference
+
+ >>> conference("myconf")
+ """
+ return self.__protocolSendmsg("conference", args, lock=True)
+
+ def att_xfer(self, url):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_att_xfer
+
+ >>> att_xfer("user/1001")
+ """
+ return self.__protocolSendmsg("att_xfer", url, lock=True)
+
+ def send_break(self):
+ return self.__protocolSendmsg("break", lock=True)
+
+ def endless_playback(self, filename):
+ """Please refer to http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_endless_playback
+
+ >>> endless_playback("/tmp/dump.gsm")
+ """
+ return self.__protocolSendmsg("endless_playback", filename, lock=True)
+
+ def execute(self, command, args):
+ """Please refer to http://wiki.freeswitch.org/wiki/Event_Socket_Library#execute
+
+ >>> execute('voicemail', 'default $${domain} 1000')
+ """
+ return self.__protocolSendmsg(command, args, lock=True)
+
+
+__all__ = ['EventError', 'AuthError', 'EventSocket', 'EventProtocol']
View
263 fs_client.py
@@ -0,0 +1,263 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+# coding: utf-8
+
+__author__ = "Sokos Lee (cnhawkwing@gmail.com)"
+__copyright__ = "Copyright (c) 2013 SokosLee.com"
+
+import sys
+sys.path.append("../")
+
+import eventsocket
+from twisted.python import log
+from twisted.internet import defer, reactor, protocol
+import functools
+import threading
+import config
+import redis
+import time
+import ujson
+
+unique_uuid = {}
+fs_ip = '211.155.86.239'
+#fs_ip = 'hcsql.com'
+#fs_ip = '127.0.0.1'
+fs_password = "sokoslee.com"
+fs_port = 8021
+
+redisConn = redis.StrictRedis(host='127.0.0.1', port=6379, db=0)
+
+def async_function(func):
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ my_thread = threading.Thread(target=func, args=args, kwargs=kwargs)
+ my_thread.start()
+ return wrapper
+
+class MyProtocol(eventsocket.EventProtocol):
+ def __init__(self):
+ self.job_uuid = {}
+ eventsocket.EventProtocol.__init__(self)
+
+ @defer.inlineCallbacks
+ def authRequest(self, ev):
+ # Try to authenticate in the eventsocket (Inbound)
+ # Please refer to http://wiki.freeswitch.org/wiki/Mod_event_socket#auth
+ # for more information.
+ try:
+ yield self.auth(self.factory.password)
+ except eventsocket.AuthError, e:
+ self.factory.continueTrying = False
+ self.factory.ready.errback(e)
+
+ # Set the events we want to get.
+ yield self.eventplain("BACKGROUND_JOB CHANNEL_HANGUP CHANNEL_HANGUP")
+
+ # Tell the factory that we're ready. Pass the protocol
+ # instance as argument.
+ self.factory.ready.callback(self)
+
+ def make_call(self, ext, context):
+ def _success(ev, data):
+ print('ev : data')
+ print(ev, data)
+ self.job_uuid[ev.Job_UUID] = data
+
+ def _failure(error, deferred):
+ print(redisConn.get('call_count'))
+ print('error : deferred')
+ print(error, deferred)
+ deferred.errback(error)
+
+ deferred = defer.Deferred()
+ d = self.bgapi("originate %s %s" % (ext, context))
+ d.addCallback(_success, (deferred, ext, context))
+ d.addErrback(_failure, deferred)
+
+ return deferred
+
+ def show_channels_count(self):
+ def _success(ev, data):
+ self.job_uuid[ev.Job_UUID] = data
+ print(ev, data)
+
+ def _failure(error, deferred):
+ print(redisConn.get('call_count'))
+ deferred.errback(error)
+
+ deferred = defer.Deferred()
+ d = self.bgapi("show channels count as json")
+ d.addCallback(_success, (deferred, '', ''))
+ d.addErrback(_failure, deferred)
+
+ return deferred
+
+ def onChannelHangup(self, ev):#CHANNEL_HANGUP
+ # if redisConn:
+ # call_count = redisConn.get('call_count')
+ # if not call_count or call_count < 1:
+ # call_count = 0
+ # else:
+ # call_count -= 1
+ # redisConn.set('call_count',int(call_count))
+ pass
+
+ def onBackgroundJob(self, ev):
+ data = self.job_uuid.pop(ev.Job_UUID, None)
+ if data:
+ print(data)
+ print(ev)
+ if 'row' not in ev.rawresponse:
+ response, content = ev.rawresponse.split()
+ if response == "+OK":
+ unique_uuid[content] = data
+ else:
+ d, ext, context = data
+ d.errback(Exception("cannot make call to %s: %s" % (ext, content)))
+ else:
+ unique_uuid[ev.Job_UUID] = data
+ if redisConn:
+ _ev = ujson.loads(str(ev.rawresponse))
+
+ redisConn.set('call_count',int(_ev['row_count']) * 2)
+ print(redisConn.get('call_count'))
+ d, ext, context = data
+ d.errback(Exception(redisConn.get('call_count')))
+ #raise Exception(redisConn.get('call_count'))
+
+ def onChannelHangup(self, ev):
+ data = unique_uuid.pop(ev.Unique_ID, None)
+ if data:
+ print(redisConn.get('call_count'))
+ d, ext, context = data
+ start_usec = float(ev.Caller_Channel_Answered_Time)
+ end_usec = float(ev.Event_Date_Timestamp)
+ duration = (end_usec - start_usec) / 1000000.0
+ d.callback("%s hang up: %s (call duration: %0.2f)" % \
+ (ext, ev.Hangup_Cause, duration))
+
+
+class MyFactory(protocol.ReconnectingClientFactory):
+ maxDelay = 15
+ protocol = MyProtocol
+
+ def __init__(self, password):
+ self.ready = defer.Deferred()
+ self.password = password
+
+
+factory = MyFactory(password=fs_password)
+reactor.connectTCP(fs_ip, fs_port, factory)
+
+#@async_function
+def make_call(caller, called, caller_uid, gateway, fee=0.12):
+ try:
+ @defer.inlineCallbacks
+ def run(caller, called, caller_uid, gateway):
+ # Wait for the connection to be established
+ try:
+ client = yield factory.ready
+ except Exception, e:
+ log.err("cannot connect: %s" % e)
+ defer.returnValue(None)
+
+ # Place the call
+ try:
+ # Don't forget to replace ext with your own destination number.
+ # You may also place the call to an eventsocket (Outbound) server,
+ # like our server.tac using:
+ # context="'&socket(127.0.0.1:8888 async full)'")
+ log.msg('Begin Make Call')
+
+ ext = "{uid=%s,cdr_caller=%s,cdr_called=%s,billing_reason=common,mynibble_rate=%s," \
+ "mynibble_increment=60,mynibble_account=%s,call_timeout=40," \
+ "nibble_selfrate=%s,mynibble_extension=%s,bill_destination=%s,instant_ringback=true," \
+ "domain_name=%s,origination_caller_id_number=%s,sched_hangup='+4500 allotted_timeout'," \
+ "continue_on_fail=false,transfer_ringback=/usr/local/freeswitch/sounds/calling.wav," \
+ "hangup_after_bridge=true,bridge_early_media=true," \
+ "origination_caller_id_name=%s,origi*_caller_id_number=1111," \
+ "effective_caller_id_number=222,ignore_early_media=true}sofia/gateway/%s/%s " \
+ " " \
+ % (caller_uid, caller, called, fee, caller_uid, fee, caller_uid, fee, fs_ip,
+ caller_uid, caller_uid,gateway , caller)
+ #ringback=/usr/local/freeswitch/sounds/calling.wav,
+
+ log.msg('before_bridge: %s %s %s %s %s' % (caller, called, caller_uid, gateway, fee))
+
+ context = " &bridge([originate_timeout=40]" \
+ "sofia/gateway/%s/%s)" % (gateway, called)
+
+ if context:
+ result = yield client.make_call(
+ ext=ext,
+ context=context)
+ else:
+ result = yield client.make_call(ext=ext)
+ log.msg(result)
+ log.msg('After Make Call')
+ except Exception, e:
+ #print(e)
+ log.err(e)
+
+ run(caller, called, caller_uid, gateway).addCallback(lambda ign: reactor.stop())
+ reactor.run()
+
+ except Exception, e:
+ log.err(e)
+ finally:
+ pass
+ # if redisConn:
+ # call_count = redisConn.get('call_count')
+ # if not call_count or call_count < 1:
+ # call_count = 0
+ # else:
+ # call_count -= 2
+ # redisConn.set('call_count',int(call_count))
+
+def show_channels_count():
+ try:
+ @defer.inlineCallbacks
+ def run():
+ client = None
+ # Wait for the connection to be established
+ try:
+ client = yield factory.ready
+ except Exception, e:
+ log.err("cannot connect: %s" % e)
+ defer.returnValue(None)
+
+ # Place the call
+ try:
+ if client:
+ result = yield client.show_channels_count()
+ print(result)
+ except Exception, e:
+ print(e)
+ log.err(e)
+
+ run().addCallback(lambda ign: reactor.stop())
+ reactor.run()
+
+ except Exception, e:
+ log.err(e)
+ finally:
+ pass
+
+
+
+# {billing_reason=common,mynibble_rate=100,mynibble_increment=60,mynibble_account=5001,nibble_selfrate=100,mynibble_extension=5001,bill_destination=1000,domain_name=192.168.1.199,origination_caller_id_number=1000,origination_caller_id_name=1000}user/1000 &bridge(user/1002)
+# {origi*_caller_id_number=1111,effective_caller_id_number=222,ignore_early_media=true}sofia/gateway/gw1/0153XXXXXX
+if __name__ == "__main__":
+ log.startLogging(sys.stdout)
+ caller = '013480718600' # 015889631135(壮欧) 013530980182(晓阳) 015875555285(阿东) 015914090951(周礼)
+ called = '013719183834' # 013798390704(世忠) 013480718600(卫斌) 015815568412(小谢) 013502869446(孙总)
+ caller_uid = '546605'
+ gateway = 'gwhu'#h323 gwhu
+ print(len(sys.argv))
+ if len(sys.argv) < 2:
+ #make_call(caller, called, caller_uid, gateway)
+ #pass
+ show_channels_count()
+ else:
+ #make_call('013719183834', '013530980182', caller_uid, gateway)
+ pass
View
52 handlers/BalanceHandler.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+# coding: utf-8
+
+__author__ = "Sokos Lee (cnhawkwing@gmail.com)"
+__copyright__ = "Copyright (c) 2012 SokosLee.com"
+
+import tornado
+import tornado.web
+import tornado.gen
+from handlers.BaseHandler import BaseHandler
+import traceback
+import tool
+import ujson as json
+import balance
+import config
+import dbutils
+
+
+class BalanceHandler(BaseHandler):#账户
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):
+ # kcid , pwd, sign, newclient
+ result, logger, query, update = {}, self.logger, self.query_conn, self.update_conn
+ try:
+ uid = self.get_argument('kcid', None)
+ pwd = self.get_argument('pwd', None)
+ newclient = self.get_argument('newclient', '')
+ sign = self.get_argument('sign', None)
+ if uid and pwd and sign:
+ if tool.check_key(sign, uid+config.key) != 1:
+ result['result'], result['reason'] = '100002', u'验证失败'
+ else:
+ tool_dict = {'redis_conn': self.redis_conn, 'queue': self.make_queue('balance_queue'),
+ 'read_conn': query, 'write_conn': update}
+ result = yield tornado.gen.Task(balance.Balance(logger, tool_dict).query_balance, uid, pwd, newclient, self.bid)
+ else:
+ result['result'], result['reason'] = '100001', u'参数缺失'
+
+ except:
+ result["result"], result["reason"] = "999999", u"服务器繁忙,请稍后再试"
+ logger.error(u"BalanceHandler发生错误:%s" % (traceback.format_exc()))
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ finally:
+ dbutils.DBHandler(logger, query).close()
+ dbutils.DBHandler(logger, update).close()
+ logger.info(result)
+ self.finish(json.dumps(result))
+
+ def post(self):
+ pass
View
BIN  handlers/BalanceHandler.pyc
Binary file not shown
View
69 handlers/BaseHandler.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+# coding: utf-8
+
+__author__ = "Sokos Lee (cnhawkwing@gmail.com)"
+__copyright__ = "Copyright (c) 2012 SokosLee.com"
+
+
+import traceback
+from raven.contrib.tornado import SentryMixin
+import tornado
+import tornado.web
+import redis
+import rq
+
+
+class BaseHandler(SentryMixin, tornado.web.RequestHandler):
+ def prepare(self):
+ try:
+ brand_id = self.get_argument('brandid', 'kc')
+ self.bid = 'kc' if brand_id == 'ld' else brand_id
+ self.httpHeaders = self.request.headers
+ except:
+ self.bid = 'kc'
+ finally:
+ self.base_domain = self.request.protocol + '://' + self.request.host
+
+ @property
+ def redis_conn(self):
+ return redis.Redis(connection_pool=self.application.redis_pool)
+
+ def make_queue(self, queue_name='default'):
+ conn = self.redis_conn
+ queue = rq.Queue(queue_name, connection=conn)
+ return queue.from_queue_key(queue_key=queue.key, connection=conn)
+
+ @property
+ def query_conn(self):
+ return self.application.read_pool.connection()
+
+ @property
+ def update_conn(self):
+ return self.application.write_pool.connection()
+
+ @property
+ def logger(self):
+ return self.application.logger
+
+ def write_error(self, status_code, **kwargs):
+ if self.settings.get("debug") and "exc_info" in kwargs:
+ exc_info = kwargs["exc_info"]
+ trace_info = ''.join(["%s<br/>" % line for line in traceback.format_exception(*exc_info)])
+ request_info = ''.join(["<strong>%s</strong>: %s<br/>" %
+ (k, self.request.__dict__[k]) for k in self.request.__dict__.keys()])
+ error = exc_info[1]
+
+ self.set_header('Content-Type', 'text/html')
+ self.finish("""<html>
+ <title>%s</title>
+ <body>
+ <h2>Error</h2>
+ <p>%s</p>
+ <h2>Traceback</h2>
+ <p>%s</p>
+ <h2>Request Info</h2>
+ <p>%s</p>
+ </body>
+ </html>""" % (error, error,
+ trace_info, request_info))
View
BIN  handlers/BaseHandler.pyc
Binary file not shown
View
59 handlers/CallHandler.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+# coding: utf-8
+
+__author__ = "Sokos Lee (cnhawkwing@gmail.com)"
+__copyright__ = "Copyright (c) 2012 SokosLee.com"
+
+
+import tornado
+import tornado.web
+import tornado.gen
+from modules import call
+from handlers.BaseHandler import BaseHandler
+import ujson as json
+import traceback
+import dbutils
+import config
+import tool
+
+
+class CallHandler(BaseHandler):#拨打
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):
+ # kcid, pwd, called_number, v, pv, sign
+ res, logger, query, update = {}, self.logger, self.query_conn, self.update_conn
+ try:
+ uid, passwd = self.get_argument('kcid', None), self.get_argument('pwd', None)
+ version_no, os_type = self.get_argument('v', None), self.get_argument('pv', None)
+ callee_no, sign = self.get_argument('called_number', None), self.get_argument('sign', None)
+ if uid and passwd and version_no and os_type and callee_no and sign:
+ check = tool.check_key(sign, uid+config.key)
+ if check != 1:
+ res["result"], res["reason"] = "100002", u"验证失败"
+ elif not callee_no.isdigit():
+ res["result"], res["reason"] = "100003", u"手机号码格式错误"
+ else:
+ tool_dict = {'redis_conn': self.redis_conn, 'queue': self.make_queue('call_queue'),
+ 'read_conn': query, 'write_conn': update}
+ res = yield tornado.gen.Task(call.Call(logger, tool_dict).call_back, uid, passwd, callee_no,
+ os_type, version_no, self.bid, self.base_domain)
+ else:
+ res["result"], res["reason"] = "100001", u"参数缺失"
+ except:
+ res["result"], res["reason"] = "999999", u"服务器繁忙,请稍后再试"
+ logger.error(u'CallHandler发生错误:%s' % traceback.format_exc())
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ finally:
+ dbutils.DBHandler(logger, query).close()
+ dbutils.DBHandler(logger, update).close()
+ logger.info(res)
+ self.finish(json.dumps(res))
+
+ def post(self, kcid, md5psw, called, phone_version, version):
+ pass
+
+
+
+
View
BIN  handlers/CallHandler.pyc
Binary file not shown
View
49 handlers/LoginHandler.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+from handlers.BaseHandler import BaseHandler
+import tornado
+import tornado.web
+import tornado.gen
+import tool
+import ujson as json
+import config
+import traceback
+import account
+import dbutils
+
+
+class LoginHandler(BaseHandler):
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):
+ result, logger, query, update = {}, self.logger, self.query_conn, self.update_conn
+ try:
+ account_id = self.get_argument('account', '')
+ pwd = self.get_argument('pwd', '')
+ version_no = self.get_argument('v', '')
+ os_type = self.get_argument('pv', '')
+ sign = self.get_argument('sign', None)
+ if sign and account_id and pwd and version_no and os_type:
+ if tool.check_key(sign, account_id+config.key) == 1:
+ tool_dict = {'redis_conn': self.redis_conn, 'queue': self.make_queue('login_queue'),
+ 'read_conn': query, 'write_conn': update}
+ result = yield tornado.gen.Task(account.Account(logger, tool_dict).login, account_id, pwd,
+ version_no, os_type, self.request.remote_ip, self.bid, 'mobile',
+ os_type, '', version_no)
+ else:
+ result['result'], result['reason'] = '100002', u'验证失败'
+ else:
+ result['result'], result['reason'] = '100001', u'参数缺失'
+ except:
+ result["result"], result["reason"] = "999999", u"服务器繁忙,请稍后再试"
+ logger.error(u"LoginHandler发生错误:%s" % traceback.format_exc())
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ finally:
+ dbutils.DBHandler(logger, query).close()
+ dbutils.DBHandler(logger, update).close()
+ logger.info(result)
+ self.finish(json.dumps(result))
View
45 handlers/RechargeHandler.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+# coding: utf-8
+
+__author__ = "Sokos Lee (cnhawkwing@gmail.com)"
+__copyright__ = "Copyright (c) 2012 SokosLee.com"
+
+from handlers.BaseHandler import BaseHandler
+import tornado
+import tornado.web
+import tornado.gen
+import tool
+import recharge
+import traceback
+import ujson as json
+import config
+
+
+class RechargeHandler(BaseHandler):#充值
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):
+ result, logger = {"result": "500", "reason": u"server error"}, self.logger
+ # src, kcid, paytype, goodstype, money, cardno, cardpwd, sign, pv, v, buynum
+ try:
+ src, uid = self.get_argument('src', ''), self.get_argument('kcid', None)
+ paytype, money = self.get_argument('paytype', ''), self.get_argument('money', '100')
+ cardno, cardpwd = self.get_argument('cardno', ''), self.get_argument('cardpwd', '')
+ sign, buynum = self.get_argument('sign', None), self.get_argument('buynum', '')
+ pv, v = self.get_argument('pv', ''), self.get_argument('v', '')
+ goodstype = 2
+
+ if (not uid) or sign != tool.md5_password(uid+config.key):
+ result['result'], result['reason'] = '-6', u'验证失败'
+ buynum = 1 if not buynum else buynum
+ recharge_obj = recharge.Recharge(logger, self.redis_conn, self.make_queue)
+ result = yield tornado.gen.Task(recharge_obj.pay, src, uid, paytype, goodstype, money, cardno, cardpwd, pv, v, buynum)
+ except:
+ logger.error(u" proc exception: %s" % traceback.format_exc())
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ logger.info(result)
+ self.finish(json.dumps(result))
+
+ def post(self):
+ pass
View
BIN  handlers/RechargeHandler.pyc
Binary file not shown
View
215 handlers/RegisterHandler.py
@@ -0,0 +1,215 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+# coding: utf-8
+#coding=utf-8
+
+__author__ = "Sokos Lee (cnhawkwing@gmail.com)"
+__copyright__ = "Copyright (c) 2012 SokosLee.com"
+
+from handlers.BaseHandler import BaseHandler
+import tornado
+import tornado.web
+import tornado.gen
+import register
+import ujson as json
+import tool
+from urllib2 import unquote
+import traceback
+import dbutils
+import config
+
+
+class RegHandler(BaseHandler): #手动注册
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):
+ #phone, invite, v, pv, sign, **args
+ result, phone, logger, query, update = {}, '', self.logger, self.query_conn, self.update_conn
+ try:
+ phone = self.get_argument('phone')
+ invite = self.get_argument('invite', '')
+ version_no = self.get_argument('v', '')
+ os_type = self.get_argument('pv', '')
+ sign = self.get_argument('sign', None)
+ client = self.get_argument('client', '')
+ imsi = self.get_argument('imsi', None)
+ device_id = self.get_argument('device_id', None)
+ inviteby = self.get_argument('inviteby', '1')
+ if (not phone) or (not sign):
+ result['result'], result['reason'] = '100001', u'参数缺失'
+ else:
+ if tool.check_key(sign, phone+config.key) != 1:
+ result['result'], result['reason'] = '100002', u'验证失败'
+ else:
+ if invite.find("(") != -1:
+ invite = invite.replace('(', '').replace(')', '')
+ elif invite.find("[") != -1:
+ invite = invite.replace('[', '').replace(']', '')
+ #print(check_string)
+ phone = phone.replace('+860', '')
+ phone = phone.replace('+86', '')
+ phone = phone.replace('+', '')
+ #print(phone)
+ if not phone.isdigit() or tool.mobile_process(phone) == '-1':
+ result['result'], result['reason'] = '100003', u'手机号码格式错误'
+ else:
+ tool_dict = {'redis_conn': self.redis_conn, 'queue': self.make_queue('reg_queue'),
+ 'read_conn': query, 'write_conn': update}
+ result = yield tornado.gen.Task(register.Register(logger, tool_dict).register, phone, invite,
+ os_type, version_no, client, self.request.remote_ip, self.bid,
+ imsi=imsi, device_id=device_id, base_domain=self.base_domain)
+ except:
+ result["result"], result["reason"] = "999999", u"服务器繁忙,请稍后再试"
+ logger.error(u"RegHandler发生错误 mobile==%s%s" % (phone, traceback.format_exc()))
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ finally:
+ dbutils.DBHandler(logger, query).close()
+ dbutils.DBHandler(logger, update).close()
+ logger.info(result)
+ self.finish(json.dumps(result))
+
+ def post(self):
+ pass
+
+
+class AutoRegHandler(BaseHandler): #自动注册
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):
+ result, phone, logger, query, update = {}, '', self.logger, self.query_conn, self.update_conn
+ try:
+ phone = self.get_argument('phone', '')
+ invite = self.get_argument('invite', '')
+ v = self.get_argument('v', '')
+ pv = self.get_argument('pv', '')
+ sign = self.get_argument('sign')
+ client = self.get_argument('client', '')
+ sn = self.get_argument('sn', '')
+ imsi = self.get_argument('imsi', None)
+ device_id = self.get_argument('device_id', None)
+ if (not phone) or (not sign):
+ result['result'], result['reason'] = '100001', u'参数缺失'
+ else:
+ if tool.check_key(sign, sn+phone+config.key) != 1:
+ result['result'], result['reason'] = '100002', u'验证失败'
+ else:
+ if invite.find("(") != -1:
+ invite = invite.split("(")[0]
+ elif invite.find("[") != -1:
+ invite = invite.split("[")[0]
+ tool_dict = {'redis_conn': self.redis_conn, 'queue': self.make_queue('reg_queue'),
+ 'read_conn': query, 'write_conn': update}
+ result = yield tornado.gen.Task(register.Register(logger, tool_dict).auto_register, phone, invite,
+ v, pv, client, bid=self.bid, imsi=imsi, device_id=device_id,
+ base_domain=self.base_domain)
+ # if pv in ['spread', 'mtk']:
+ # pass
+ except:
+ result["result"], result["reason"] = "999999", u"服务器繁忙,请稍后再试"
+ logger.error(u"AutoRegHandler发生错误 mobile==%s%s" % (phone, traceback.format_exc()))
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ finally:
+ dbutils.DBHandler(logger, query).close()
+ dbutils.DBHandler(logger, update).close()
+ logger.info(result)
+ self.finish(json.dumps(result))
+
+ def post(self):
+ pass
+
+
+class WapRegHandler(BaseHandler): #WAP注册
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):
+ result, phone, logger, query, update = {}, '', self.logger, self.query_conn, self.update_conn
+ try:
+ self.brandid = self.get_argument('_b', None) #品牌
+ #phone = self.get_argument('phone',None)#phone
+ invite = self.get_argument('_p', None)#项目ID
+ target = self.get_argument('_t', '')#跳转目标
+ timestamp = self.get_argument('_tm', None)#unix时间戳
+ sign = self.get_argument('_s', None)#验证串
+ uus = self.get_argument('uus', None)
+
+ if (not uus) or (not self.brandid) or (not invite) or (not target) or (not timestamp) or (not sign):
+ result['result'], result['reason'] = '100001', u'参数缺失'
+ else:
+ isTrue, phone, ua = tool.getPhoneByCMWap(uus)
+ if (not isTrue) or (not phone):
+ if 'HTTP_X_UP_CALLING_LINE_ID' in self.httpHeaders:#联通手机访问
+ phone = self.httpHeaders['HTTP_X_UP_CALLING_LINE_ID']
+ isTrue = True
+ elif 'HTTP_X_UP_SUBNO' in self.httpHeaders:
+ phone = self.httpHeaders['HTTP_X_UP_SUBNO']
+ isTrue = True
+ if (not isTrue) or (not phone) or (not phone.isdigit()):#手机号码获取失败
+ result['result'], result['reason'] = '100001', u'参数缺失'
+ else:
+ phone = tool.number_deal(phone)
+ v, pv, client, imsi, device_id = '', '', '', '', ''
+ _target = unquote(target).split('_')
+ if len(_target) >= 5:
+ v = _target[0]
+ pv = _target[1]
+ client = _target[2]
+ imsi = _target[3]
+ device_id = _target[4]
+ if tool.check_key(sign, self.brandid+invite+target+timestamp+config.key) != 1:
+ result['result'], result['reason'] = '100002', u'验证失败'
+ else:
+ self.brandid = 'kc' if self.brandid in ['1'] else 'uu'
+ tool_dict = {'redis_conn': self.redis_conn, 'queue': self.make_queue('reg_queue'),
+ 'read_conn': query, 'write_conn': update}
+ result = yield tornado.gen.Task(register.Register(logger, tool_dict).auto_register, phone,
+ invite, v, pv, client, brandid=self.bid, imsi=imsi,
+ device_id=device_id, base_domain=self.base_domain)
+ except:
+ result["result"], result["reason"] = "999999", u"服务器繁忙,请稍后再试"
+ logger.error(u"WapRegHandler发生错误 mobile==%s%s" % (phone, traceback.format_exc()))
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ finally:
+ dbutils.DBHandler(logger, query).close()
+ dbutils.DBHandler(logger, update).close()
+ logger.info(result)
+ self.finish(json.dumps(result))
+
+ def post(self):
+ pass
+
+
+#查询短信注册
+class SmsRegInfoHandler(BaseHandler):
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):
+ result, phone, logger, query, update = {}, '', self.logger, self.query_conn, self.update_conn
+ try:
+ invite = self.get_argument('invite', None)
+ imsi = self.get_argument('imsi', None)
+ sign = self.get_argument('sign', None)
+ v = self.get_argument('v', '')
+ pv = self.get_argument('pv', '')
+
+ if (not invite) or (not imsi) or (not sign):
+ result['result'], result['reason'] = '100001', u'参数缺失'
+ else:
+ logger.info(u"查询短信注册信息:invite==%s,imsi==%s,v==%s,pv==%s,sign==%s" % (invite, imsi, v, pv, sign))
+ if tool.check_key(sign, imsi+config.key) != 1:
+ result['result'], result['reason'] = '100002', u'验证失败'
+ else:
+ tool_dict = {'redis_conn': self.redis_conn, 'queue': self.make_queue('reg_queue'),
+ 'read_conn': query, 'write_conn': update}
+ result = yield tornado.gen.Task(register.Register(logger, tool_dict).sms_reg_info, imsi, invite, self.bid)
+ except:
+ result["result"], result["reason"] = "999999", u"服务器繁忙,请稍后再试"
+ logger.error(u"SmsRegInfoHandler发生错误 mobile==%s%s" % (phone, traceback.format_exc()))
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ finally:
+ dbutils.DBHandler(logger, query).close()
+ dbutils.DBHandler(logger, update).close()
+ logger.info(result)
+ self.finish(json.dumps(result))
+
+ def post(self):
+ pass
View
BIN  handlers/RegisterHandler.pyc
Binary file not shown
View
92 handlers/ServiceHandler.py
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+# coding: utf-8
+
+__author__ = "Sokos Lee (cnhawkwing@gmail.com)"
+__copyright__ = "Copyright (c) 2012 SokosLee.com"
+
+
+from handlers.BaseHandler import BaseHandler
+import tornado.web
+import tornado.gen
+import ujson as json
+import tool
+import traceback
+import callshow
+import mobile_binder
+import config
+
+
+class CallShowHandler(BaseHandler):
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self): #uid,pwd,operate,sign
+ logger, result = self.logger, {"result": "500", "reason": u"server error"}
+ try:
+ uid = self.get_argument('uid', None)
+ pwd = self.get_argument('pwd', None)
+ operate = self.get_argument('operate', None)
+ sign = self.get_argument('sign', None)
+ if (not uid) or (not pwd) or (not operate) or (not sign):
+ result['result'], result['reason'] = '403', u'验证失败'
+ else:
+ logger.info(u'收到去电显号操作请求:uid==%s,operate==%s' % (uid, operate))
+ #验证url请求
+ if sign != tool.md5_password(uid+pwd+operate+config.key):
+ result['result'], result['reason'] = '403', u'验证失败'
+ else:
+ callshow_obj = callshow.call_show(logger, self.make_queue)
+ result = yield tornado.gen.Task(callshow_obj.open, uid, pwd, operate)
+ except:
+ logger.error(u" proc exception: %s" % traceback.format_exc())
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ logger.info(result)
+ self.finish(json.dumps(result))
+
+ def post(self, kcid, md5psw, called, phone_version, version):
+ pass
+
+
+class VIPHandler(BaseHandler):#VIP
+ def get(self):
+ pass
+ def post(self):
+ pass
+
+
+class SysMsgHandler(BaseHandler):#系统公告
+ def get(self):
+ # queue = self.application.queue
+ # job = queue.enqueue_call(func=None, args=(), timeout=300)
+ # time.sleep(1)
+ # print job.result
+ pass
+
+ def post(self):
+ pass
+
+
+class BindHandler(BaseHandler): #帐号绑定
+ @tornado.web.asynchronous
+ @tornado.gen.engine
+ def get(self):# kcid, pwd, code, sign
+ logger, result = self.logger, {"result": "500", "reason": u"server error"}
+ try:
+ uid = self.get_argument('kcid')
+ pwd = self.get_argument('pwd')
+ code = self.get_argument('code', '')
+ sign = self.get_argument('sign')
+ if tool.check_key(sign, uid+config.key) != 1:
+ result['result'], result['reason'] = '-6', u'验证失败'
+ else:
+ bind_obj = mobile_binder.binder(logger, self.make_queue)
+ result = yield tornado.gen.Task(bind_obj.submit_bind_relations, uid, pwd, code, self.bid)
+ except:
+ logger.error(u"\n proc exception: \n%s" % traceback.format_exc())
+ yield tornado.gen.Task(self.captureException, exc_info=True)
+ logger.info(result)
+ self.finish(json.dumps(result))
+
+
+ def post(self):
+ pass
View
13 handlers/__init__.py
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+from .CallHandler import *
+from .RegisterHandler import *
+# from .LoginHandler import *
+# from .BaseHandler import *
+# from .BalanceHandler import *
+# from .RechargeHandler import *
+# from .ServiceHandler import *
View
BIN  handlers/__init__.pyc
Binary file not shown
View
8 modules/__init__.py
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+from .call import *
+from .register import *
View
BIN  modules/__init__.pyc
Binary file not shown
View
127 modules/call.py
@@ -0,0 +1,127 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+__author__ = 'Aurora Wu (wuxy91@gmail.com)'
+__copyright__ = "Copyright (c) 2013 aurorawu.com"
+
+
+'''手机软件打电话接口'''
+import traceback
+import balance
+import check
+import tool
+import config
+import account
+from fs_client import make_call
+
+
+class Call:
+ """tool_dict contains a connection of the redis connection pool, a call queue, a query connection of
+ the database connection pool, and a update connection of the database connection pool"""
+ def __init__(self, logger, tool_dict):
+ self.logger = logger
+ self.tool_dict = tool_dict
+
+ def call_back(self, uid, md5_passwd, callee, os_type, version, bid, base_domain=None, callback=None):
+ logger, redis_conn, res = self.logger, self.tool_dict['redis_conn'], {}
+ if not callback:
+ callback = tool.return_values
+ logger.info(u'收到回拨请求:uid==%s,被叫号码==%s,手机操作系统==%s,产品==%s,版本号==%s' % (uid, callee, os_type, bid, version))
+ '''检测该uid是否已经在呼叫队列里'''
+ if redis_conn and redis_conn.get(uid) == '1':
+ logger.info(u'当前呼叫已存在队列中,故丢弃。uid==%s' % uid)
+ res['result'], res['calltime'], res['reason'] = '100010', '0', u'呼叫请求重复提交'
+ return callback(res)
+ if redis_conn:#该uid不在呼叫队列里,添加该uid的呼叫到队列里
+ redis_conn.setex(uid, '1', 10)
+ '''当前呼叫队列里没有该uid'''
+ # 1、检测被叫号码格式是否有效
+ can_call = tool.number_deal(callee)
+ if can_call == '-1':
+ logger.info(u'uid==%s:呼叫%s被叫号格式验证失败' % (uid, callee))
+ res['result'], res['calltime'], res['reason'] = '100003', '0', u'被叫号码格式错误'
+ return callback(res)
+ # 2、验证用户密码是否正确
+ user = check.check_uid_pwd(uid, md5_passwd)
+ if user == '-1':
+ logger.info(u'uid==%s:呼叫%s用户密码验证失败' % (uid, callee))
+ res['result'], res['calltime'], res['reason'] = '100004', '0', u'账号密码验证失败'
+ return callback(res)
+ # 3、查询该uid的余额是否可以打电话
+ balance_obj = balance.Balance(self.logger, self.tool_dict)
+ can_call = balance_obj.can_call(uid)
+ if int(can_call['result']) != 1:
+ logger.info(u"uid==%s:余额不足,呼叫%s失败" % (uid, callee))
+ res['result'], res['calltime'], res['reason'] = '100005', '0', u'余额不足'
+ return callback(res)
+ # 4、设置是否显号的参数
+ is_show = '1' if int(can_call['show_number']) == 1 else '0'
+ # 5、查询用户绑定的手机号码
+ account_obj = account.Account(self.logger, self.tool_dict)
+ caller = account_obj.get_bind_relation(uid)[1]
+ caller = user['mobile'] if not caller else caller