TeamTalk消息服务器(群组相关)

具体的流程如下介绍,后续需要着重研究数据库相关表的结构设计。

群组信令和协议设计

复制代码
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函数主要做:

  1. 解析user_id,解析群ID列表

  2. 根据群ID 通过 redis 缓存查找读取群成员列表

  3. 根据群ID通过数据库查找IMGroup 表获取对应群的详细信息

  4. 组包群信息以及群成员列表

    // 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, listIM::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,
  // ...... 暂时省略无关信令
};

获取最近联系会话

流程图

具体代码逻辑

相关推荐
极客悟道9 分钟前
巧解 Docker 镜像拉取难题:无需梯子和服务器,拉取数量无限制
后端·github
jyan_敬言14 分钟前
【C++】string类(二)相关接口介绍及其使用
android·开发语言·c++·青少年编程·visual studio
aiopencode28 分钟前
iOS 出海 App 安全加固指南:无源码环境下的 IPA 加固与防破解方法
后端
liangdabiao32 分钟前
AI一人公司?先搞定聚合支付!一天搞定全能的聚合支付系统
后端
liulilittle37 分钟前
SNIProxy 轻量级匿名CDN代理架构与实现
开发语言·网络·c++·网关·架构·cdn·通信
AillemaC38 分钟前
三分钟看懂回调函数
后端
yeyong39 分钟前
越学越糟心,今天遇到又一种新的服务控制方式 snap,用它来跑snmpd
后端
喷火龙8号42 分钟前
深入理解MSC架构:现代前后端分离项目的最佳实践
后端·架构
Java技术小馆1 小时前
GitDiagram如何让你的GitHub项目可视化
java·后端·面试
tan77º1 小时前
【Linux网络编程】Socket - UDP
linux·服务器·网络·c++·udp