kpush源码解析---服务端(alloc server)

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


posted @ 2015-05-14 18:02  菩提本无树  阅读(548)  评论(0编辑  收藏  举报