继续上篇已经分析了android端代码,本篇将主要分析kpush服务端如何为连接的客户端分配用户信息,并为其分配tcp server。
上文中提到客户端的pushservice中会通过http post请求http://demo.kpush.cn/server/alloc,以获取用户及消息服务器ip/port信息。那么我们接下来看看kpush服务端关于该流程的相关代码。
如果想找到相关代码,但是我们目前对整个项目目录结构不太熟悉该怎么办呢?其实很容易的,我们先找到/server/alloc路由,搜索源代码可以发现在kpush/web/views/frontend.py文件中有对该路由做处理:alloc_server,该函数代码如下:
@bp.route('/server/alloc', methods=['POST'])
def alloc_server():
"""
# 方便测试
if not request.json_data:
return jsonify(
ret=proto.RET_INVALID_PARAMS
)
"""
appinfo = get_appinfo_by_appkey(request.json_data['appkey'])
web_logger.debug("appinfo: %s", appinfo)
if appinfo is None:
# 报错
jsonify(
ret=proto.RET_INVALID_PARAMS
)
return
user = create_or_update_user(dict(
appid=appinfo['appid'],
channel=request.json_data['channel'],
device_id=request.json_data['device_id'],
device_name=request.json_data.get('device_name'),
os=request.json_data.get('os'),
os_version=request.json_data.get('os_version'),
sdk_version=request.json_data.get('sdk_version'),
))
server_list = current_app.config['SERVER_LIST']
# 取模
server = server_list[user['uid'] % len(server_list)]
return current_app.response_class(pack_data(
dict(
ret=0,
user=dict(
uid=user['uid'],
key=user['key'],
),
server=dict(
host=server['outer_host'],
port=server['outer_port'],
)
)
), mimetype='application/json')
仔细分下该段代码,我们可以发现该段代码主要完成了三个功能:
1. 根据post上来的相关数据创建或更新对应的用户信息,主要包含uid和key(还记得这两个数据是用来干嘛的吗?客户端会用这两个数据执行登录操作)
2. 根据uid对服务列表个数取模,为该客户端分配一个tcp server
3. 把用户信息和tcp服务器信息封装成json数据,并返回到客户端
现在我们回顾下上篇的内容,客户端会通过http post获取用户和tcp服务端ip,然后通过ferry连接上该tcp服务器,并使用uid和key进行登录。到此我们知道服务端是如何处理该请求,并返回相关的信息了。但是在上段函数中还有一个函数我们还没有去分析:create_or_update_user,根据函数名就可以知道该函数主要功能就是完成上述的第一个功能,该函数具体代码如下:
def create_or_update_user(user_info):
"""
返回或者创建user
"""
user_table = kit.mongo_client.get_default_database()[current_app.config['MONGO_TB_USER']]
user = user_table.find_one(dict(
appid=user_info['appid'],
device_id=user_info['device_id'],
))
if user is None:
new_user_info = dict(
uid=alloc_autoid("user"),
key=uuid.uuid4().hex,
)
new_user_info.update(user_info)
# 没有这个用户
user_table.insert(new_user_info)
else:
# 更新字段, 要用 $set 才会只更新指定的字段
user_table.update({
'_id': user['_id'],
}, {
"$set": user_info,
})
return user_table.find_one(dict(
appid=user_info['appid'],
device_id=user_info['device_id'],
))
该函数处理流程是:根据appid和deviceid,查询数据库是是否存在对应的记录,如果存在该记录则把设备详细信息更新到数据库中,如果不存在则对最新的一个uid加1形成新的uid,并生成一个uuid作为key,该uid和key就是新用户的登录名和密码,然后在把该用户信息插入到数据库中。
至此,为客户端创建用户信息,并分配tcp服务器的相关代码已经分析完毕,下一篇我们将分析消息推送流程相关代码。