IM TeamTalk流程分析


登陆流程:
1.用户名密码校验

30分钟内密码错误次数,hash_map<string, list<uint32_t> > g_hmLimits;
用list保存每次错误的时间,每次触发登陆的时候将超过30分钟的给剔除。 判断30分钟内密码错误次数是否大于10,返回。

抽象接口
class CLoginStrategy
{
public:
    virtual bool doLogin(const std::string& strName, const std::string& strPass, IM::BaseDefine::UserInfo& user) = 0;
};
根据用户名和密码查询User的消息填写到user

用户名密码校验 CommandID 流程 
[Client]--->CID_LOGIN_REQ_USERLOGIN----->[MSG_SERVER]---->CID_OTHER_VALIDATE_REQ---->[DB_PROXY_SERVER]
[Client]<---CID_LOGIN_RES_USERLOGIN<-----[MSG_SERVER]<----CID_OTHER_VALIDATE_RSP<----[DB_PROXY_SERVER]

2.在线状态设置
enum UserStatType {
  USER_STATUS_ONLINE = 1,
  USER_STATUS_OFFLINE = 2,
  USER_STATUS_LEAVE = 3
};
pMsgConn->SendUserStatusUpdate(IM::BaseDefine::USER_STATUS_ONLINE);
{
    if (!m_bOpen) {
        return;
    }
    
    CImUser* pImUser = CImUserManager::GetInstance()->GetImUserById(GetUserId());
    if (!pImUser) {
        return;
    }
    
    // 只有上下线通知才通知LoginServer
    if (user_status == ::IM::BaseDefine::USER_STATUS_ONLINE) {
        IM::Server::IMUserCntUpdate msg;
        msg.set_user_action(USER_CNT_INC);
        msg.set_user_id(pImUser->GetUserId());
        CImPdu pdu;
        pdu.SetPBMsg(&msg);
        pdu.SetServiceId(SID_OTHER);
        pdu.SetCommandId(CID_OTHER_USER_CNT_UPDATE);
        send_to_all_login_server(&pdu);
        
        IM::Server::IMUserStatusUpdate msg2;
        msg2.set_user_status(::IM::BaseDefine::USER_STATUS_ONLINE);
        msg2.set_user_id(pImUser->GetUserId());
        msg2.set_client_type((::IM::BaseDefine::ClientType)m_client_type);
        CImPdu pdu2;
        pdu2.SetPBMsg(&msg2);
        pdu2.SetServiceId(SID_OTHER);
        pdu2.SetCommandId(CID_OTHER_USER_STATUS_UPDATE);
        send_to_all_route_server(&pdu2);
    } else if (user_status == ::IM::BaseDefine::USER_STATUS_OFFLINE) {
        IM::Server::IMUserCntUpdate msg;
        msg.set_user_action(USER_CNT_DEC);
        msg.set_user_id(pImUser->GetUserId());
        CImPdu pdu;
        pdu.SetPBMsg(&msg);
        pdu.SetServiceId(SID_OTHER);
        pdu.SetCommandId(CID_OTHER_USER_CNT_UPDATE);
        send_to_all_login_server(&pdu);
        
        IM::Server::IMUserStatusUpdate msg2;
        msg2.set_user_status(::IM::BaseDefine::USER_STATUS_OFFLINE);
        msg2.set_user_id(pImUser->GetUserId());
        msg2.set_client_type((::IM::BaseDefine::ClientType)m_client_type);
        CImPdu pdu2;
        pdu2.SetPBMsg(&msg2);
        pdu2.SetServiceId(SID_OTHER);
        pdu2.SetCommandId(CID_OTHER_USER_STATUS_UPDATE);
        send_to_all_route_server(&pdu2);
    }
}
        
login_server更新数量每个msg_server中用户的数量
void CLoginConn::_HandleUserCntUpdate(CImPdu* pPdu)
{
    map<uint32_t, msg_serv_info_t*>::iterator it = g_msg_serv_info.find(m_handle);
    if (it != g_msg_serv_info.end()) {
        msg_serv_info_t* pMsgServInfo = it->second;
        IM::Server::IMUserCntUpdate msg;
        msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength());

        uint32_t action = msg.user_action();
        if (action == USER_CNT_INC) {    // msg_server收到client登录后通知login_server上线加一
            pMsgServInfo->cur_conn_cnt++;
            g_total_online_user_cnt++;
        } else {                        // 下线减一
            pMsgServInfo->cur_conn_cnt--;
            g_total_online_user_cnt--;
        }

        log("%s:%d, cur_cnt=%u, total_cnt=%u ", pMsgServInfo->hostname.c_str(),
            pMsgServInfo->port, pMsgServInfo->cur_conn_cnt, g_total_online_user_cnt);
    }
}


3.路由状态更新
pdu2.SetCommandId(CID_OTHER_USER_STATUS_UPDATE);
send_to_all_route_server(&pdu2);
void CRouteConn::_HandleUserStatusUpdate(CImPdu* pPdu)
{
    IM::Server::IMUserStatusUpdate msg;
    CHECK_PB_PARSE_MSG(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()));

    uint32_t user_status = msg.user_status();
    uint32_t user_id = msg.user_id();
    uint32_t client_type = msg.client_type();
    log("HandleUserStatusUpdate, status=%u, uid=%u, client_type=%u ", user_status, user_id, client_type);

    _UpdateUserStatus(user_id, user_status, client_type);
    
    //用于通知客户端,同一用户在pc端的登录情况
    CUserInfo* pUser = GetUserInfo(user_id);
    if (pUser)
    {
        IM::Server::IMServerPCLoginStatusNotify msg2;
        msg2.set_user_id(user_id);
        if (user_status == IM::BaseDefine::USER_STATUS_OFFLINE)
        {
            msg2.set_login_status(IM_PC_LOGIN_STATUS_OFF);
        }
        else
        {
            msg2.set_login_status(IM_PC_LOGIN_STATUS_ON);
        }
        CImPdu pdu;
        pdu.SetPBMsg(&msg2);
        pdu.SetServiceId(SID_OTHER);
        pdu.SetCommandId(CID_OTHER_LOGIN_STATUS_NOTIFY);
        
        if (user_status == USER_STATUS_OFFLINE)
        {
            //pc端下线且无pc端存在,则给msg_server发送一个通知
            if (CHECK_CLIENT_TYPE_PC(client_type) && !pUser->IsPCClientLogin())
            {
                _BroadcastMsg(&pdu);
            }
        }
        else
        {
            //只要pc端在线,则不管上线的是pc还是移动端,都通知msg_server
            if (pUser->IsPCClientLogin())
            {
                _BroadcastMsg(&pdu);
            }
        }
    }
    
    //状态更新的是pc client端,则通知给所有其他人
    if (CHECK_CLIENT_TYPE_PC(client_type))
    {
        IM::Buddy::IMUserStatNotify msg3;
        IM::BaseDefine::UserStat* user_stat = msg3.mutable_user_stat();
        user_stat->set_user_id(user_id);
        user_stat->set_status((IM::BaseDefine::UserStatType)user_status);
        CImPdu pdu2;
        pdu2.SetPBMsg(&msg3);
        pdu2.SetServiceId(SID_BUDDY_LIST);
        pdu2.SetCommandId(CID_BUDDY_LIST_STATUS_NOTIFY);
        
        //用户存在
        if (pUser)
        {
            //如果是pc客户端离线,但是仍然存在pc客户端,则不发送离线通知
            //此种情况一般是pc客户端多点登录时引起
            if (USER_STATUS_OFFLINE == user_status && pUser->IsPCClientLogin())
            {
                return;
            }
            else
            {
                _BroadcastMsg(&pdu2);
            }
        }
        else//该用户不存在了,则表示是离线状态
        {
            _BroadcastMsg(&pdu2);
        }
    }
}

4.旧客户端账号下线
// 只支持一个WINDOWS/MAC客户端登陆,或者一个ios/android登录
bool CImUser::KickOutSameClientType(uint32_t client_type, uint32_t reason, CMsgConn* pFromConn)
{
    for (map<uint32_t, CMsgConn*>::iterator it = m_conn_map.begin(); it != m_conn_map.end(); it++)
    {
        CMsgConn* pMsgConn = it->second;
        
        //16进制位移计算
        if ((((pMsgConn->GetClientType() ^ client_type) >> 4) == 0) && (pMsgConn != pFromConn)) {
            HandleKickUser(pMsgConn, reason);
            break;
        }
    }
    return true;
}

5.通知好友
6.同步信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值