登陆流程:
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.同步信息