继续上篇已经分析了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服务器的相关代码已经分析完毕,下一篇我们将分析消息推送流程相关代码。