具体的流程如下介绍,后续需要着重研究数据库相关表的结构设计。
群组信令和协议设计
enum GroupCmdID {
CID_GROUP_NORMAL_LIST_REQUEST = 1025,
CID_GROUP_NORMAL_LIST_RESPONSE = 1026,
CID_GROUP_INFO_REQUEST = 1027,
CID_GROUP_INFO_RESPONSE = 1028,
// ...... 暂时省略无关信令
};
message IMNormalGroupListReq{
//cmd id: 0x0401
required uint32 user_id = 1;
optional bytes attach_data = 20;
}
message IMNormalGroupListRsp{
//cmd id: 0x0402
required uint32 user_id = 1;
repeated IM.BaseDefine.GroupVersionInfo group_version_list = 2;
optional bytes attach_data = 20;
}
message GroupVersionInfo{
required uint32 group_id = 1;
required uint32 version = 2; // 不同级别的群??
}
message IMGroupInfoListReq{
//cmd id: 0x0403
required uint32 user_id = 1; // 用户ID
repeated IM.BaseDefine.GroupVersionInfo group_version_list = 2; // 群ID列表
optional bytes attach_data = 20;
}
message IMGroupInfoListRsp{
//cmd id: 0x0404
required uint32 user_id = 1;
repeated IM.BaseDefine.GroupInfo group_info_list = 2;
optional bytes attach_data = 20;
}
message GroupInfo{
required uint32 group_id = 1;
required uint32 version = 2;
required string group_name = 3;
required string group_avatar = 4;
required uint32 group_creator_id = 5;
required GroupType group_type = 6;
required uint32 shield_status = 7; //1: shield 0: not shield
repeated uint32 group_member_list = 8;
}
请求用户群组ID
流程图
具体代码逻辑
db_proxy_server 收到 CID_GROUP_NORMAL_LIST_REQUEST后调用 DB_PROXY::getNormalGroupList 函数
主要就是读取用户ID所在群的ID列表
// group
m_handler_map.insert(make_pair(uint32_t(CID_GROUP_NORMAL_LIST_REQUEST), DB_PROXY::getNormalGroupList));
/**
* 获取正式群列表
*
* @param pPdu 收到的packet包指针
* @param conn_uuid 该包过来的socket 描述符
*/
void getNormalGroupList(CImPdu* pPdu, uint32_t conn_uuid)
{
IM::Group::IMNormalGroupListReq msg;
IM::Group::IMNormalGroupListRsp msgResp;
if(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()))
{
CImPdu* pPduRes = new CImPdu;
uint32_t nUserId = msg.user_id();
list<IM::BaseDefine::GroupVersionInfo> lsGroup;
// 关键函数
CGroupModel::getInstance()->getUserGroup(nUserId, lsGroup, IM::BaseDefine::GROUP_TYPE_NORMAL);
msgResp.set_user_id(nUserId);
for(auto it=lsGroup.begin(); it!=lsGroup.end(); ++it)
{
IM::BaseDefine::GroupVersionInfo* pGroupVersion = msgResp.add_group_version_list();
pGroupVersion->set_group_id(it->group_id());
pGroupVersion->set_version(it->version());
}
log("getNormalGroupList. userId=%u, count=%d", nUserId, msgResp.group_version_list_size());
msgResp.set_attach_data(msg.attach_data());
pPduRes->SetPBMsg(&msgResp);
pPduRes->SetSeqNum(pPdu->GetSeqNum());
pPduRes->SetServiceId(IM::BaseDefine::SID_GROUP);
pPduRes->SetCommandId(IM::BaseDefine::CID_GROUP_NORMAL_LIST_RESPONSE);
CProxyConn::AddResponsePdu(conn_uuid, pPduRes);
}
else
{
log("parse pb failed");
}
}
void CGroupModel::getUserGroup(uint32_t nUserId, list<IM::BaseDefine::GroupVersionInfo>& lsGroup, uint32_t nGroupType)
{
list<uint32_t> lsGroupId;
getUserGroupIds(nUserId, lsGroupId,0);
if(lsGroupId.size() != 0)
{
getGroupVersion(lsGroupId, lsGroup, nGroupType);
}
}
void CGroupModel::getUserGroupIds(uint32_t nUserId, list<uint32_t>& lsGroupId, uint32_t nLimited)
{
CDBManager* pDBManager = CDBManager::getInstance();
CDBConn* pDBConn = pDBManager->GetDBConn("teamtalk_slave");
if(pDBConn)
{
string strSql ;
if (nLimited != 0) {
strSql = "select groupId from IMGroupMember where userId=" + int2string(nUserId) + " and status = 0 order by updated desc, id desc limit " + int2string(nLimited);
}
else
{
strSql = "select groupId from IMGroupMember where userId=" + int2string(nUserId) + " and status = 0 order by updated desc, id desc";
}
CResultSet* pResultSet = pDBConn->ExecuteQuery(strSql.c_str());
if(pResultSet)
{
while(pResultSet->Next())
{
uint32_t nGroupId = pResultSet->GetInt("groupId");
lsGroupId.push_back(nGroupId);
}
delete pResultSet;
}
else
{
log("no result set for sql:%s", strSql.c_str());
}
pDBManager->RelDBConn(pDBConn);
}
else
{
log("no db connection for teamtalk_slave");
}
}
请求用户群组具体信息
流程图
具体代码逻辑
DB_PROXY::getGroupInfo函数主要做:
- 解析user_id,解析群ID列表
- 根据群ID 通过 redis 缓存查找读取群成员列表
- 根据群ID通过数据库查找IMGroup 表获取对应群的详细信息
- 组包群信息以及群成员列表
// group
m_handler_map.insert(make_pair(uint32_t(CID_GROUP_INFO_REQUEST), DB_PROXY::getGroupInfo));
/**
* 获取群信息
*
* @param pPdu 收到的packet包指针
* @param conn_uuid 该包过来的socket 描述符
*/
void getGroupInfo(CImPdu* pPdu, uint32_t conn_uuid)
{
IM::Group::IMGroupInfoListReq msg;
IM::Group::IMGroupInfoListRsp msgResp;
if(msg.ParseFromArray(pPdu->GetBodyData(), pPdu->GetBodyLength()))
{
CImPdu* pPduRes = new CImPdu;
uint32_t nUserId = msg.user_id();
uint32_t nGroupCnt = msg.group_version_list_size();
map<uint32_t, IM::BaseDefine::GroupVersionInfo> mapGroupId;
for(uint32_t i=0; i<nGroupCnt; ++i)
{
IM::BaseDefine::GroupVersionInfo groupInfo = msg.group_version_list(i);
// redis
if(CGroupModel::getInstance()->isValidateGroupId(groupInfo.group_id()))
{
mapGroupId[groupInfo.group_id()] = groupInfo;
}
}
list<IM::BaseDefine::GroupInfo> lsGroupInfo;
CGroupModel::getInstance()->getGroupInfo(mapGroupId, lsGroupInfo);
msgResp.set_user_id(nUserId);
for(auto it=lsGroupInfo.begin(); it!=lsGroupInfo.end(); ++it)
{
IM::BaseDefine::GroupInfo* pGroupInfo = msgResp.add_group_info_list();
pGroupInfo->set_group_id(it->group_id());
pGroupInfo->set_version(it->version());
pGroupInfo->set_group_name(it->group_name());
pGroupInfo->set_group_avatar(it->group_avatar());
pGroupInfo->set_group_creator_id(it->group_creator_id());
pGroupInfo->set_group_type(it->group_type());
pGroupInfo->set_shield_status(it->shield_status());
uint32_t nGroupMemberCnt = it->group_member_list_size();
for (uint32_t i=0; i<nGroupMemberCnt; ++i) {
uint32_t userId = it->group_member_list(i);
pGroupInfo->add_group_member_list(userId);
}
}
log("userId=%u, requestCount=%u", nUserId, nGroupCnt);
msgResp.set_attach_data(msg.attach_data());
pPduRes->SetPBMsg(&msgResp);
pPduRes->SetSeqNum(pPdu->GetSeqNum());
pPduRes->SetServiceId(IM::BaseDefine::SID_GROUP);
pPduRes->SetCommandId(IM::BaseDefine::CID_GROUP_INFO_RESPONSE);
CProxyConn::AddResponsePdu(conn_uuid, pPduRes);
}
else
{
log("parse pb failed");
}
}
// redis
bool CGroupModel::isValidateGroupId(uint32_t nGroupId)
{
bool bRet = false;
CacheManager* pCacheManager = CacheManager::getInstance();
CacheConn* pCacheConn = pCacheManager->GetCacheConn("group_member");
if(pCacheConn)
{
string strKey = "group_member_"+int2string(nGroupId);
bRet = pCacheConn->isExists(strKey);
pCacheManager->RelCacheConn(pCacheConn);
}
return bRet;
}
// mysql
void CGroupModel::getGroupInfo(map<uint32_t,IM::BaseDefine::GroupVersionInfo>& mapGroupId, list<IM::BaseDefine::GroupInfo>& lsGroupInfo)
{
if (!mapGroupId.empty())
{
CDBManager* pDBManager = CDBManager::getInstance();
CDBConn* pDBConn = pDBManager->GetDBConn("teamtalk_slave");
if (pDBConn)
{
string strClause;
bool bFirst = true;
for(auto it=mapGroupId.begin(); it!=mapGroupId.end(); ++it)
{
if(bFirst)
{
bFirst = false;
strClause = int2string(it->first);
}
else
{
strClause += ("," + int2string(it->first));
}
}
string strSql = "select * from IMGroup where id in (" + strClause + ") order by updated desc";
CResultSet* pResultSet = pDBConn->ExecuteQuery(strSql.c_str());
if(pResultSet)
{
while (pResultSet->Next()) {
uint32_t nGroupId = pResultSet->GetInt("id");
uint32_t nVersion = pResultSet->GetInt("version");
if(mapGroupId[nGroupId].version() < nVersion)
{
IM::BaseDefine::GroupInfo cGroupInfo;
cGroupInfo.set_group_id(nGroupId);
cGroupInfo.set_version(nVersion);
cGroupInfo.set_group_name(pResultSet->GetString("name"));
cGroupInfo.set_group_avatar(pResultSet->GetString("avatar"));
IM::BaseDefine::GroupType nGroupType = IM::BaseDefine::GroupType(pResultSet->GetInt("type"));
if(IM::BaseDefine::GroupType_IsValid(nGroupType))
{
cGroupInfo.set_group_type(nGroupType);
cGroupInfo.set_group_creator_id(pResultSet->GetInt("creator"));
lsGroupInfo.push_back(cGroupInfo);
}
else
{
log("invalid groupType. groupId=%u, groupType=%u", nGroupId, nGroupType);
}
}
}
delete pResultSet;
}
else
{
log("no result set for sql:%s", strSql.c_str());
}
pDBManager->RelDBConn(pDBConn);
if(!lsGroupInfo.empty())
{
fillGroupMember(lsGroupInfo);
}
}
else
{
log("no db connection for teamtalk_slave");
}
}
else
{
log("no ids in map");
}
}
最近联系会话信令和协议设计
enum BuddyListCmdID {
CID_BUDDY_LIST_RECENT_CONTACT_SESSION_REQUEST = 513,
CID_BUDDY_LIST_RECENT_CONTACT_SESSION_RESPONSE = 514,
// ...... 暂时省略无关信令
CID_BUDDY_LIST_USERS_STATUS_REQUEST = 522,
CID_BUDDY_LIST_USERS_STATUS_RESPONSE = 523,
// ...... 暂时省略无关信令
};