全部业务概述
全部业务:
心跳包
注册
登录
获取好友列表
查找用户
加好友
更新用户信息
修改密码
创建群
获取指定群成员信息
聊天信息
群发信息
数据包
数据包的格式是:业务id加上序列号m_seq。
心跳包业务
心跳包业务。主要是看对方还在不在线,所以不需要写什么额外的数据,就是写一个简单的数据包。
数据包内容就是msg_type_heartbeart+m_seq,然后发送过去。
std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_heartbeart); writeStream.Write(m_seq); std::string dummy; writeStream.Write(dummy.c_str(), dummy.length()); writeStream.Flush(); LOG_INFO << "Response to client: cmd=1000" << ", sessionId=" << m_id; Send(outbuf);
注册业务
注册业务,先是解析发来的注册数据是否符合json数据格式,如果符合,就进一步注册。如果不符合,就不进行注册了。
然后根据注册的用户名,在UserManager里进行对所有用户进行查找,如果找到了相同的用户名。那么就终止注册,并返回已注册的信息;如果没有找到相同的用户名,那么就在UserManager中添加用户了,并发送成功注册的信息。
void ClientSession::OnRegisterResponse(const std::string& data, const std::shared_ptr<TcpConnection>& conn) { //{ "user": "13917043329", "nickname" : "balloon", "password" : "123" } Json::Reader JsonReader; Json::Value JsonRoot; if (!JsonReader.parse(data, JsonRoot)) { LOG_WARN << "invalid json: " << data << ", sessionId = " << m_id << ", client: " << conn->peerAddress().toIpPort(); return; } if (!JsonRoot["username"].isString() || !JsonRoot["nickname"].isString() || !JsonRoot["password"].isString()) { LOG_WARN << "invalid json: " << data << ", sessionId = " << m_id << ", client: " << conn->peerAddress().toIpPort(); return; } User u; u.username = JsonRoot["username"].asString(); u.nickname = JsonRoot["nickname"].asString(); u.password = JsonRoot["password"].asString(); std::string retData; User cachedUser; cachedUser.userid = 0; Singleton<UserManager>::Instance().GetUserInfoByUsername(u.username, cachedUser); if (cachedUser.userid != 0) retData = "{\"code\": 101, \"msg\": \"registered already\"}"; else { if (!Singleton<UserManager>::Instance().AddUser(u)) retData = "{\"code\": 100, \"msg\": \"register failed\"}"; else retData = "{\"code\": 0, \"msg\": \"ok\"}"; } std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_register); writeStream.Write(m_seq); writeStream.Write(retData.c_str(), retData.length()); writeStream.Flush(); LOG_INFO << "Response to client: cmd=msg_type_register" << ", userid=" << u.userid << ", data=" << retData; Send(outbuf); }
登录业务
登录业务先检查发送过来的数据是否符合json格式,如果不符合,就记录在日志上,然后直接返回。
如果符合json格式,就解析json格式,并解析出对应的用户名和密码。
然后在UserManager中去查询用户名,如果用户名不存在,就返回“未注册的”消息
如果用户名存在,就判断密码一不一样。如果密码不一样,就返回用户名或密码错误的消息
如果密码一样了,就返回ok的消息,并附带上各种用户信息。
登录成功后,要推送用户缓存的通知消息和聊天消息。同时给其他用户推送上线的消息
推送缓存消息是从<MsgCacheManager>中拿到缓存,然后再发送出去。
推送用户上线消息:先获得该用户的好友,如果这些好友在线的话。就获得好友对应的ClientSession,然后发送用户上线状态。
void ClientSession::OnLoginResponse(const std::string& data, const std::shared_ptr<TcpConnection>& conn) { //{"username": "13917043329", "password": "123", "clienttype": 1, "status": 1} Json::Reader JsonReader; Json::Value JsonRoot; if (!JsonReader.parse(data, JsonRoot)) { LOG_WARN << "invalid json: " << data << ", sessionId = " << m_id << ", client: " << conn->peerAddress().toIpPort(); return; } if (!JsonRoot["username"].isString() || !JsonRoot["password"].isString() || !JsonRoot["clienttype"].isInt() || !JsonRoot["status"].isInt()) { LOG_WARN << "invalid json: " << data << ", sessionId = " << m_id << ", client: " << conn->peerAddress().toIpPort(); return; } string username = JsonRoot["username"].asString(); string password = JsonRoot["password"].asString(); std::ostringstream os; User cachedUser; cachedUser.userid = 0; Singleton<UserManager>::Instance().GetUserInfoByUsername(username, cachedUser); if (cachedUser.userid == 0) { //TODO: 这些硬编码的字符应该统一放到某个地方统一管理 os << "{\"code\": 102, \"msg\": \"not registered\"}"; } else { if (cachedUser.password != password) os << "{\"code\": 103, \"msg\": \"incorrect password\"}"; else { //记录用户信息 m_userinfo.userid = cachedUser.userid; m_userinfo.username = username; m_userinfo.nickname = cachedUser.nickname; m_userinfo.password = password; m_userinfo.clienttype = JsonRoot["clienttype"].asInt(); m_userinfo.status = JsonRoot["status"].asInt(); os << "{\"code\": 0, \"msg\": \"ok\", \"userid\": " << m_userinfo.userid << ",\"username\":\"" << cachedUser.username << "\", \"nickname\":\"" << cachedUser.nickname << "\", \"facetype\": " << cachedUser.facetype << ", \"customface\":\"" << cachedUser.customface << "\", \"gender\":" << cachedUser.gender << ", \"birthday\":" << cachedUser.birthday << ", \"signature\":\"" << cachedUser.signature << "\", \"address\": \"" << cachedUser.address << "\", \"phonenumber\": \"" << cachedUser.phonenumber << "\", \"mail\":\"" << cachedUser.mail << "\"}"; } } //登录信息应答 std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_login); writeStream.Write(m_seq); writeStream.Write(os.str().c_str(), os.str().length()); writeStream.Flush(); LOG_INFO << "Response to client: cmd=msg_type_login, data=" << os.str() << ", userid=" << m_userinfo.userid; Send(outbuf); //推送通知消息 std::list<NotifyMsgCache> listNotifyCache; Singleton<MsgCacheManager>::Instance().GetNotifyMsgCache(m_userinfo.userid, listNotifyCache); for (const auto &iter : listNotifyCache) { Send(iter.notifymsg); } //推送聊天消息 std::list<ChatMsgCache> listChatCache; Singleton<MsgCacheManager>::Instance().GetChatMsgCache(m_userinfo.userid, listChatCache); for (const auto &iter : listChatCache) { Send(iter.chatmsg); } //给其他用户推送上线消息 std::list<User> friends; Singleton<UserManager>::Instance().GetFriendInfoByUserId(m_userinfo.userid, friends); IMServer& imserver = Singleton<IMServer>::Instance(); for (const auto& iter : friends) { //先看目标用户是否在线 std::shared_ptr<ClientSession> targetSession; imserver.GetSessionByUserId(targetSession, iter.userid); if (targetSession) targetSession->SendUserStatusChangeMsg(m_userinfo.userid, 1); } }
获取好友列表
根据用户id在UserManager中获得好友列表,然后把好友列表里每个用户的信息都转化成数据包,然后发送过去。
void ClientSession::OnGetFriendListResponse(const std::shared_ptr<TcpConnection>& conn) { std::list<User> friends; Singleton<UserManager>::Instance().GetFriendInfoByUserId(m_userinfo.userid, friends); std::string strUserInfo; bool userOnline = false; IMServer& imserver = Singleton<IMServer>::Instance(); for (const auto& iter : friends) { userOnline = imserver.IsUserSessionExsit(iter.userid); /* {"code": 0, "msg": "ok", "userinfo":[{"userid": 1,"username":"qqq, "nickname":"qqq, "facetype": 0, "customface":"", "gender":0, "birthday":19900101, "signature":", "address": "", "phonenumber": "", "mail":", "clienttype": 1, "status":1"]} */ ostringstream osSingleUserInfo; osSingleUserInfo << "{\"userid\": " << iter.userid << ",\"username\":\"" << iter.username << "\", \"nickname\":\"" << iter.nickname << "\", \"facetype\": " << iter.facetype << ", \"customface\":\"" << iter.customface << "\", \"gender\":" << iter.gender << ", \"birthday\":" << iter.birthday << ", \"signature\":\"" << iter.signature << "\", \"address\": \"" << iter.address << "\", \"phonenumber\": \"" << iter.phonenumber << "\", \"mail\":\"" << iter.mail << "\", \"clienttype\": 1, \"status\":" << (userOnline ? 1 : 0) << "}"; strUserInfo += osSingleUserInfo.str(); strUserInfo += ","; } //去掉最后多余的逗号 strUserInfo = strUserInfo.substr(0, strUserInfo.length() - 1); std::ostringstream os; os << "{\"code\": 0, \"msg\": \"ok\", \"userinfo\":[" << strUserInfo << "]}"; std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_getofriendlist); writeStream.Write(m_seq); writeStream.Write(os.str().c_str(), os.str().length()); writeStream.Flush(); LOG_INFO << "Response to client: cmd=msg_type_getofriendlist, data=" << os.str() << ", userid=" << m_userinfo.userid; Send(outbuf); }
查找用户业务
解析json格式跟前面是一样的
然后在UserManager里去查询是否有这个用户名,如果没有这个用户,就返回查询失败。如果有这个用户,就返回用户的信息。
void ClientSession::OnFindUserResponse(const std::string& data, const std::shared_ptr<TcpConnection>& conn) { //{ "type": 1, "username" : "zhangyl" } Json::Reader JsonReader; Json::Value JsonRoot; if (!JsonReader.parse(data, JsonRoot)) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } if (!JsonRoot["type"].isInt() || !JsonRoot["username"].isString()) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } string retData; //TODO: 目前只支持查找单个用户 string username = JsonRoot["username"].asString(); User cachedUser; if (!Singleton<UserManager>::Instance().GetUserInfoByUsername(username, cachedUser)) retData = "{ \"code\": 0, \"msg\": \"ok\", \"userinfo\": [] }"; else { //TODO: 用户比较多的时候,应该使用动态string char szUserInfo[256] = { 0 }; snprintf(szUserInfo, 256, "{ \"code\": 0, \"msg\": \"ok\", \"userinfo\": [{\"userid\": %d, \"username\": \"%s\", \"nickname\": \"%s\", \"facetype\":%d}] }", cachedUser.userid, cachedUser.username.c_str(), cachedUser.nickname.c_str(), cachedUser.facetype); retData = szUserInfo; } std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_finduser); writeStream.Write(m_seq); writeStream.Write(retData.c_str(), retData.length()); writeStream.Flush(); LOG_INFO << "Response to client: cmd=msg_type_finduser, data=" << retData << ", userid=" << m_userinfo.userid; Send(outbuf); }
操作好友反应
从json格式的数据里主要提前两个数据,第一个是targetuserid,第二个是type。targetuserid是被操作的userid,type是操作类型。
(1)如果 targetUserid >= GROUPID_BOUBDARY,就说明被操作的对象是群,而不是用户。比如加群或者退群。
如果type类型是4,则是退群,调用DeleteFriend(conn, targetUserid);
否则是加群 OnAddGroupResponse(targetUserid, conn);
(2)接下来就是targetUserid < GROUPID_BOUBDARY,就表示操作的对象是用户,而不是群。
如果type是4,就是删好友,调用DeleteFriend(conn, targetUserid);
type是1,就是加好友
type是3,就是应答加好友。
应答加好友,就会去建立两个用户之间的关系。提示当前用户加好友成功,提示对方加好友成功。
如果对方不在,就把这个消息先缓存起来。
void ClientSession::OnOperateFriendResponse(const std::string& data, const std::shared_ptr<TcpConnection>& conn) { Json::Reader JsonReader; Json::Value JsonRoot; if (!JsonReader.parse(data, JsonRoot)) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } if (!JsonRoot["type"].isInt() || !JsonRoot["userid"].isInt()) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } int type = JsonRoot["type"].asInt(); int32_t targetUserid = JsonRoot["userid"].asInt(); if (targetUserid >= GROUPID_BOUBDARY) { if (type == 4) { //退群 DeleteFriend(conn, targetUserid); return; } //加群直接同意 OnAddGroupResponse(targetUserid, conn); return; } char szData[256] = { 0 }; //删除好友 if (type == 4) { DeleteFriend(conn, targetUserid); return; } //发出加好友申请 if (type == 1) { //{"userid": 9, "type": 1, } snprintf(szData, 256, "{\"userid\":%d, \"type\":2, \"username\": \"%s\"}", m_userinfo.userid, m_userinfo.username.c_str()); } //应答加好友 else if (type == 3) { if (!JsonRoot["accept"].isInt()) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << "client: " << conn->peerAddress().toIpPort(); return; } int accept = JsonRoot["accept"].asInt(); //接受加好友申请后,建立好友关系 if (accept == 1) { int smallid = m_userinfo.userid; int greatid = targetUserid; //数据库里面互为好友的两个人id,小者在先,大者在后 if (smallid > greatid) { smallid = targetUserid; greatid = m_userinfo.userid; } if (!Singleton<UserManager>::Instance().MakeFriendRelationship(smallid, greatid)) { LOG_ERROR << "make relationship error: " << data << ", userid: " << m_userinfo.userid << "client: " << conn->peerAddress().toIpPort(); return; } } //{ "userid": 9, "type" : 3, "userid" : 9, "username" : "xxx", "accept" : 1 } snprintf(szData, 256, "{\"userid\": %d, \"type\": 3, \"username\": \"%s\", \"accept\": %d}", m_userinfo.userid, m_userinfo.username.c_str(), accept); //提示自己当前用户加好友成功 User targetUser; if (!Singleton<UserManager>::Instance().GetUserInfoByUserId(targetUserid, targetUser)) { LOG_ERROR << "Get Userinfo by id error, targetuserid: " << targetUserid << ", userid: " << m_userinfo.userid << ", data: "<< data << ", client: " << conn->peerAddress().toIpPort(); return; } char szSelfData[256] = { 0 }; snprintf(szSelfData, 256, "{\"userid\": %d, \"type\": 3, \"username\": \"%s\", \"accept\": %d}", targetUser.userid, targetUser.username.c_str(), accept); std::string outbufx; yt::BinaryWriteStream3 writeStream(&outbufx); writeStream.Write(msg_type_operatefriend); writeStream.Write(m_seq); writeStream.Write(szSelfData, strlen(szSelfData)); writeStream.Flush(); Send(outbufx); LOG_INFO << "Response to client: cmd=msg_type_addfriend, data=" << szSelfData << ", userid=" << m_userinfo.userid; } //提示对方加好友成功 std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_operatefriend); writeStream.Write(m_seq); writeStream.Write(szData, strlen(szData)); writeStream.Flush(); //先看目标用户是否在线 std::shared_ptr<ClientSession> targetSession; Singleton<IMServer>::Instance().GetSessionByUserId(targetSession, targetUserid); //目标用户不在线,缓存这个消息 if (!targetSession) { Singleton<MsgCacheManager>::Instance().AddNotifyMsgCache(targetUserid, outbuf); LOG_INFO << "userid: " << targetUserid << " is not online, cache notify msg, msg: " << outbuf; return; } targetSession->Send(outbuf); LOG_INFO << "Response to client: cmd=msg_type_addfriend, data=" << data << ", userid=" << targetUserid; }
删好友
删好友,先把两个人从好友关系表中剔除Singleton<UserManager>::Instance().ReleaseFriendRelationship
然后给主动删除方发送消息。
然后给被删除方发送删除好友消息,如果用户在线,就推送这个消息;否则先把消息缓存起来
如果是群的话,就给其他群成员推送群成员变动消息,如果是群成员不在线,那么就先缓存起来。
void ClientSession::DeleteFriend(const std::shared_ptr<TcpConnection>& conn, int32_t friendid) { int32_t smallerid = friendid; int32_t greaterid = m_userinfo.userid; if (smallerid > greaterid) { smallerid = m_userinfo.userid; greaterid = friendid; } if (!Singleton<UserManager>::Instance().ReleaseFriendRelationship(smallerid, greaterid)) { LOG_ERROR << "Delete friend error, friendid: " << friendid << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } User cachedUser; if (!Singleton<UserManager>::Instance().GetUserInfoByUserId(friendid, cachedUser)) { LOG_ERROR << "Delete friend - Get user error, friendid: " << friendid << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } char szData[256] = { 0 }; //发给主动删除的一方 //{"userid": 9, "type": 1, } snprintf(szData, 256, "{\"userid\":%d, \"type\":5, \"username\": \"%s\"}", friendid, cachedUser.username.c_str()); std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_operatefriend); writeStream.Write(m_seq); writeStream.Write(szData, strlen(szData)); writeStream.Flush(); Send(outbuf); LOG_INFO << "Send to client: cmd=msg_type_operatefriend, data=" << szData << ", userid=" << m_userinfo.userid; //发给被删除的一方 //删除好友消息 if (friendid < GROUPID_BOUBDARY) { outbuf.clear(); //先看目标用户是否在线 std::shared_ptr<ClientSession> targetSession; Singleton<IMServer>::Instance().GetSessionByUserId(targetSession, friendid); //仅给在线用户推送这个消息 if (targetSession) { memset(szData, 0, sizeof(szData)); snprintf(szData, 256, "{\"userid\":%d, \"type\":5, \"username\": \"%s\"}", m_userinfo.userid, m_userinfo.username.c_str()); outbuf.clear(); writeStream.Clear(); writeStream.Write(msg_type_operatefriend); writeStream.Write(m_seq); writeStream.Write(szData, strlen(szData)); writeStream.Flush(); targetSession->Send(outbuf); LOG_INFO << "Send to client: cmd=msg_type_operatefriend, data=" << szData << ", userid=" << friendid; } return; } //退群消息 //给其他在线群成员推送群信息发生变化的消息 std::list<User> friends; Singleton<UserManager>::Instance().GetFriendInfoByUserId(friendid, friends); IMServer& imserver = Singleton<IMServer>::Instance(); for (const auto& iter : friends) { //先看目标用户是否在线 std::shared_ptr<ClientSession> targetSession; imserver.GetSessionByUserId(targetSession, iter.userid); if (targetSession) targetSession->SendUserStatusChangeMsg(friendid, 3); } }
加群
先给群id和用户id建立关系MakeFriendRelationship
然后给用户发送消息
给群里的其他成员发送群信息变化消息
void ClientSession::OnAddGroupResponse(int32_t groupId, const std::shared_ptr<TcpConnection>& conn) { if (!Singleton<UserManager>::Instance().MakeFriendRelationship(m_userinfo.userid, groupId)) { LOG_ERROR << "make relationship error, groupId: " << groupId << ", userid: " << m_userinfo.userid << "client: " << conn->peerAddress().toIpPort(); return; } User groupUser; if (!Singleton<UserManager>::Instance().GetUserInfoByUserId(groupId, groupUser)) { LOG_ERROR << "Get group info by id error, targetuserid: " << groupId << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } char szSelfData[256] = { 0 }; snprintf(szSelfData, 256, "{\"userid\": %d, \"type\": 3, \"username\": \"%s\", \"accept\": 3}", groupUser.userid, groupUser.username.c_str()); std::string outbufx; yt::BinaryWriteStream3 writeStream(&outbufx); writeStream.Write(msg_type_operatefriend); writeStream.Write(m_seq); writeStream.Write(szSelfData, strlen(szSelfData)); writeStream.Flush(); Send(outbufx); LOG_INFO << "Response to client: cmd=msg_type_addfriend, data=" << szSelfData << ", userid=" << m_userinfo.userid; //给其他在线群成员推送群信息发生变化的消息 std::list<User> friends; Singleton<UserManager>::Instance().GetFriendInfoByUserId(groupId, friends); IMServer& imserver = Singleton<IMServer>::Instance(); for (const auto& iter : friends) { //先看目标用户是否在线 std::shared_ptr<ClientSession> targetSession; imserver.GetSessionByUserId(targetSession, iter.userid); if (targetSession) targetSession->SendUserStatusChangeMsg(groupId, 3); } }
更新用户信息业务
从json格式中解析数据,解析更新后用户的信息,然后把用户的信息更新到UserManager。
应答客户端,同时给其他在线好友推送个人信息发送改变消息
void ClientSession::OnUpdateUserInfoResponse(const std::string& data, const std::shared_ptr<TcpConnection>& conn) { Json::Reader JsonReader; Json::Value JsonRoot; if (!JsonReader.parse(data, JsonRoot)) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } if (!JsonRoot["nickname"].isString() || !JsonRoot["facetype"].isInt() || !JsonRoot["customface"].isString() || !JsonRoot["gender"].isInt() || !JsonRoot["birthday"].isInt() || !JsonRoot["signature"].isString() || !JsonRoot["address"].isString() || !JsonRoot["phonenumber"].isString() || !JsonRoot["mail"].isString()) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } User newuserinfo; newuserinfo.nickname = JsonRoot["nickname"].asString(); newuserinfo.facetype = JsonRoot["facetype"].asInt(); newuserinfo.customface = JsonRoot["customface"].asString(); newuserinfo.gender = JsonRoot["gender"].asInt(); newuserinfo.birthday = JsonRoot["birthday"].asInt(); newuserinfo.signature = JsonRoot["signature"].asString(); newuserinfo.address = JsonRoot["address"].asString(); newuserinfo.phonenumber = JsonRoot["phonenumber"].asString(); newuserinfo.mail = JsonRoot["mail"].asString(); ostringstream retdata; ostringstream currentuserinfo; if (!Singleton<UserManager>::Instance().UpdateUserInfo(m_userinfo.userid, newuserinfo)) { retdata << "{ \"code\": 104, \"msg\": \"update user info failed\" }"; } else { /* { "code": 0, "msg" : "ok", "userid" : 2, "username" : "xxxx", "nickname":"zzz", "facetype" : 26, "customface" : "", "gender" : 0, "birthday" : 19900101, "signature" : "xxxx", "address": "", "phonenumber": "", "mail":""} */ currentuserinfo << "\"userid\": " << m_userinfo.userid << ",\"username\":\"" << m_userinfo.username << "\", \"nickname\":\"" << newuserinfo.nickname << "\", \"facetype\": " << newuserinfo.facetype << ", \"customface\":\"" << newuserinfo.customface << "\", \"gender\":" << newuserinfo.gender << ", \"birthday\":" << newuserinfo.birthday << ", \"signature\":\"" << newuserinfo.signature << "\", \"address\": \"" << newuserinfo.address << "\", \"phonenumber\": \"" << newuserinfo.phonenumber << "\", \"mail\":\"" << newuserinfo.mail; retdata << "{\"code\": 0, \"msg\": \"ok\"," << currentuserinfo.str() << "\"}"; } std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_updateuserinfo); writeStream.Write(m_seq); writeStream.Write(retdata.str().c_str(), retdata.str().length()); writeStream.Flush(); //应答客户端 Send(outbuf); LOG_INFO << "Response to client: cmd=msg_type_updateuserinfo, data=" << retdata.str() << ", userid=" << m_userinfo.userid; //给其他在线好友推送个人信息发生改变消息 std::list<User> friends; Singleton<UserManager>::Instance().GetFriendInfoByUserId(m_userinfo.userid, friends); IMServer& imserver = Singleton<IMServer>::Instance(); for (const auto& iter : friends) { //先看目标用户是否在线 std::shared_ptr<ClientSession> targetSession; imserver.GetSessionByUserId(targetSession, iter.userid); if (targetSession) targetSession->SendUserStatusChangeMsg(m_userinfo.userid, 3); } }
改密码的业务
从json格式中解析出新密码和旧密码。先比较旧密码是否一致,如果旧密码一样才可以改新密码。如果旧密码不一样,那么就发送密码错误给客户端。只有旧密码正确才可以改新密码
Singleton<UserManager>::Instance().ModifyUserPassword(m_userinfo.userid, newPass)
void ClientSession::OnModifyPasswordResponse(const std::string& data, const std::shared_ptr<TcpConnection>& conn) { Json::Reader JsonReader; Json::Value JsonRoot; if (!JsonReader.parse(data, JsonRoot)) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } if (!JsonRoot["oldpassword"].isString() || !JsonRoot["newpassword"].isString()) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } string oldpass = JsonRoot["oldpassword"].asString(); string newPass = JsonRoot["newpassword"].asString(); string retdata; User cachedUser; if (!Singleton<UserManager>::Instance().GetUserInfoByUserId(m_userinfo.userid, cachedUser)) { LOG_ERROR << "get userinfo error, userid: " << m_userinfo.userid << ", data: " << data << ", client: " << conn->peerAddress().toIpPort(); return; } if (cachedUser.password != oldpass) { retdata = "{\"code\": 103, \"msg\": \"incorrect old password\"}"; } else { if (!Singleton<UserManager>::Instance().ModifyUserPassword(m_userinfo.userid, newPass)) { retdata = "{\"code\": 105, \"msg\": \"modify password error\"}"; LOG_ERROR << "modify password error, userid: " << m_userinfo.userid << ", data: " << data << ", client: " << conn->peerAddress().toIpPort(); } else retdata = "{\"code\": 0, \"msg\": \"ok\"}"; } std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_modifypassword); writeStream.Write(m_seq); writeStream.Write(retdata.c_str(), retdata.length()); writeStream.Flush(); //应答客户端 Send(outbuf); LOG_INFO << "Response to client: cmd=msg_type_modifypassword, data=" << data << ", userid=" << m_userinfo.userid; }
建群业务
从json格式中解析出群名
然后调用UserManager来添加群,AddGroup
创建成功后,该用户自动加群MakeFriendRelationship
之后应答两次。第一次是创建群成功,第二次是加群成功
void ClientSession::OnCreateGroupResponse(const std::string& data, const std::shared_ptr<TcpConnection>& conn) { Json::Reader JsonReader; Json::Value JsonRoot; if (!JsonReader.parse(data, JsonRoot)) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } if (!JsonRoot["groupname"].isString()) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } ostringstream retdata; string groupname = JsonRoot["groupname"].asString(); int32_t groupid; if (!Singleton<UserManager>::Instance().AddGroup(groupname.c_str(), m_userinfo.userid, groupid)) { LOG_WARN << "Add group error, data: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); retdata << "{ \"code\": 106, \"msg\" : \"create group error\"}"; } else { retdata << "{\"code\": 0, \"msg\": \"ok\", \"groupid\":" << groupid << ", \"groupname\": \"" << groupname << "\"}"; } //创建成功以后该用户自动加群 if (!Singleton<UserManager>::Instance().MakeFriendRelationship(m_userinfo.userid, groupid)) { LOG_ERROR << "join in group, errordata: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_creategroup); writeStream.Write(m_seq); writeStream.Write(retdata.str().c_str(), retdata.str().length()); writeStream.Flush(); //应答客户端,建群成功 Send(outbuf); LOG_INFO << "Response to client: cmd=msg_type_creategroup, data=" << retdata.str() << ", userid=" << m_userinfo.userid; //应答客户端,成功加群 { char szSelfData[256] = { 0 }; snprintf(szSelfData, 256, "{\"userid\": %d, \"type\": 3, \"username\": \"%s\", \"accept\": 1}", groupid, groupname.c_str()); std::string outbufx; yt::BinaryWriteStream3 writeStream(&outbufx); writeStream.Write(msg_type_operatefriend); writeStream.Write(m_seq); writeStream.Write(szSelfData, strlen(szSelfData)); writeStream.Flush(); Send(outbufx); LOG_INFO << "Response to client: cmd=msg_type_addfriend, data=" << szSelfData << ", userid=" << m_userinfo.userid; } }
获得群成员业务
其实获得群成员业务和获得好友列表业务是一样的。因为群就是userid
void ClientSession::OnGetGroupMembersResponse(const std::string& data, const std::shared_ptr<TcpConnection>& conn) { //{"groupid": 群id} Json::Reader JsonReader; Json::Value JsonRoot; if (!JsonReader.parse(data, JsonRoot)) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } if (!JsonRoot["groupid"].isInt()) { LOG_WARN << "invalid json: " << data << ", userid: " << m_userinfo.userid << ", client: " << conn->peerAddress().toIpPort(); return; } int32_t groupid = JsonRoot["groupid"].asInt(); std::list<User> friends; Singleton<UserManager>::Instance().GetFriendInfoByUserId(groupid, friends); std::string strUserInfo; bool userOnline = false; IMServer& imserver = Singleton<IMServer>::Instance(); for (const auto& iter : friends) { userOnline = imserver.IsUserSessionExsit(iter.userid); /* {"code": 0, "msg": "ok", "members":[{"userid": 1,"username":"qqq, "nickname":"qqq, "facetype": 0, "customface":"", "gender":0, "birthday":19900101, "signature":", "address": "", "phonenumber": "", "mail":", "clienttype": 1, "status":1"]} */ ostringstream osSingleUserInfo; osSingleUserInfo << "{\"userid\": " << iter.userid << ",\"username\":\"" << iter.username << "\", \"nickname\":\"" << iter.nickname << "\", \"facetype\": " << iter.facetype << ", \"customface\":\"" << iter.customface << "\", \"gender\":" << iter.gender << ", \"birthday\":" << iter.birthday << ", \"signature\":\"" << iter.signature << "\", \"address\": \"" << iter.address << "\", \"phonenumber\": \"" << iter.phonenumber << "\", \"mail\":\"" << iter.mail << "\", \"clienttype\": 1, \"status\":" << (userOnline ? 1 : 0) << "}"; strUserInfo += osSingleUserInfo.str(); strUserInfo += ","; } //去掉最后多余的逗号 strUserInfo = strUserInfo.substr(0, strUserInfo.length() - 1); std::ostringstream os; os << "{\"code\": 0, \"msg\": \"ok\", \"groupid\": " << groupid << ", \"members\":[" << strUserInfo << "]}"; std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_getgroupmembers); writeStream.Write(m_seq); writeStream.Write(os.str().c_str(), os.str().length()); writeStream.Flush(); LOG_INFO << "Response to client: cmd=msg_type_getgroupmembers, data=" << os.str() << ", userid=" << m_userinfo.userid; Send(outbuf); }
发送用户状态业务
void ClientSession::SendUserStatusChangeMsg(int32_t userid, int type) { string data; //用户上线 if (type == 1) { data = "{\"type\": 1, \"onlinestatus\": 1}"; } //用户下线 else if (type == 2) { data = "{\"type\": 2, \"onlinestatus\": 0}"; } //个人昵称、头像、签名等信息更改 else if (type == 3) { data = "{\"type\": 3}"; } std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_userstatuschange); writeStream.Write(m_seq); writeStream.Write(data.c_str(), data.length()); writeStream.Write(userid); writeStream.Flush(); Send(outbuf); LOG_INFO << "Send to client: cmd=msg_type_userstatuschange, data=" << data << ", userid=" << m_userinfo.userid; }
发送聊天消息业务
先把消息写入到记录里,写入到数据库里。
(1)如果是单聊消息,targetid < GROUPID_BOUBDARY
如果接收方不在,那么先看看目标用户是否在线,如果目标用户不在线,那么就缓存这个消息
如果在线,那么就把目标用户的clientSession调出来,然后发送消息
(2)如果是群聊消息,就把群里的所有人调出来,然后看看目标是否在线,不在线就缓存消息,如果在线,就调出这个用户的clientSession,然后发送消息。
void ClientSession::OnChatResponse(int32_t targetid, const std::string& data, const std::shared_ptr<TcpConnection>& conn) { std::string outbuf; yt::BinaryWriteStream3 writeStream(&outbuf); writeStream.Write(msg_type_chat); writeStream.Write(m_seq); writeStream.Write(data.c_str(), data.length()); //消息发送者 writeStream.Write(m_userinfo.userid); //消息接受者 writeStream.Write(targetid); writeStream.Flush(); UserManager& userMgr = Singleton<UserManager>::Instance(); //写入消息记录 if (!userMgr.SaveChatMsgToDb(m_userinfo.userid, targetid, data)) { LOG_ERROR << "Write chat msg to db error, , senderid = " << m_userinfo.userid << ", targetid = " << targetid << ", chatmsg:" << data; } IMServer& imserver = Singleton<IMServer>::Instance(); MsgCacheManager& msgCacheMgr = Singleton<MsgCacheManager>::Instance(); //单聊消息 if (targetid < GROUPID_BOUBDARY) { //先看目标用户是否在线 std::shared_ptr<ClientSession> targetSession; imserver.GetSessionByUserId(targetSession, targetid); //目标用户不在线,缓存这个消息 if (!targetSession) { msgCacheMgr.AddChatMsgCache(targetid, outbuf); return; } targetSession->Send(outbuf); return; } //群聊消息 std::list<User> friends; userMgr.GetFriendInfoByUserId(targetid, friends); std::string strUserInfo; bool userOnline = false; for (const auto& iter : friends) { //先看目标用户是否在线 std::shared_ptr<ClientSession> targetSession; imserver.GetSessionByUserId(targetSession, iter.userid); //目标用户不在线,缓存这个消息 if (!targetSession) { msgCacheMgr.AddChatMsgCache(iter.userid, outbuf); continue; } targetSession->Send(outbuf); } }