聊天服务器——Usermanager2

UserManager

用户管理器就是把所有的用户都加载起来,存放着所有的用户,方便后续的查找等操作

首先userid有一个边界,GROUPID_BOUBDARY。

当小于这个边界时,userid就代表着是用户的id。当大于这个边界时,userid就代表着是群id。

User

User的定义,定义了用户的id,名字,密码,昵称,头像等等等,注意还有一个好友列表set

//用户或者群
struct User
{
    int32_t        userid;      //0x0FFFFFFF以上是群号,以下是普通用户
    string         username;    //群账户的username也是群号userid的字符串形式
    string         password;
    string         nickname;    //群账号为群名称
    int32_t        facetype;
    string         customface;
    string         customfacefmt;//自定义头像格式
    int32_t        gender;
    int32_t        birthday;
    string         signature;
    string         address;
    string         phonenumber;
    string         mail;
    int32_t        ownerid;        //对于群账号,为群主userid
    set<int32_t>   friends;        //为了避免重复
};

启动数据库

 std::unique_ptr<CDatabaseMysql> pConn;
 pConn.reset(new CDatabaseMysql());
 if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
 {
     LOG_FATAL << "UserManager::SaveChatMsgToDb failed, please check params";
     return false;
 }

用户管理器

用户管理器的成员

    int                 m_baseUserId{ 0 };        //m_baseUserId, 取数据库里面userid最大值,新增用户在这个基础上递增
    int                 m_baseGroupId{0x0FFFFFFF}; //群的id起点
    list<User>          m_allCachedUsers;          //所有用户的list
    mutex               m_mutex;
​
    string              m_strDbServer;
    string              m_strDbUserName;
    string              m_strDbPassword;
    string              m_strDbName;

用户管理器的初始化,就是把用户信息从数据库里加载出来,加载到m_allCachedUsers,

再从数据库里把关系全部加载出来。

bool UserManager::Init(const char* dbServer, const char* dbUserName, const char* dbPassword, const char* dbName)
{
    m_strDbServer = dbServer;
    m_strDbUserName = dbUserName;
    m_strDbPassword = dbPassword;
    m_strDbName = dbName;
​
    if (!LoadUsersFromDb())
        return false;
​
    for (auto& iter : m_allCachedUsers)
    {
        if (!LoadRelationhipFromDb(iter.userid, iter.friends))
        {
            LOG_WARN << "Load relationship from db error, userid=" << iter.userid;
        }
    }
​
    return true;
}

从t_user数据库中加载用户信息,加载所有的用户,然后一条一条的放入到m_allCachedUsers

bool UserManager::LoadUsersFromDb()
{  
    std::unique_ptr<CDatabaseMysql> pConn;
    pConn.reset(new CDatabaseMysql());
    if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
    {
        LOG_FATAL << "UserManager::LoadUsersFromDb failed, please check params";
        return false;
    }
​
    //TODO: 到底是空数据集还是出错,需要修改下返回类型
    QueryResult* pResult = pConn->Query("SELECT f_user_id, f_username, f_nickname, f_password,  f_facetype, f_customface, f_gender, f_birthday, f_signature, f_address, f_phonenumber, f_mail FROM t_user ORDER BY  f_user_id DESC");
    if (NULL == pResult)
    {
        LOG_INFO << "UserManager::_Query error, dbname=" << m_strDbName;
        return false;
    }
 
    while (true)
    {
        Field* pRow = pResult->Fetch();
        if (pRow == NULL)
            break;
        
        User u;
        u.userid = pRow[0].GetInt32();
        u.username = pRow[1].GetString();
        u.nickname = pRow[2].GetString();
        u.password = pRow[3].GetString();
        u.facetype = pRow[4].GetInt32();
        u.customface = pRow[5].GetString();
        u.gender = pRow[6].GetInt32();
        u.birthday = pRow[7].GetInt32();
        u.signature = pRow[8].GetString();
        u.address = pRow[9].GetString();
        u.phonenumber = pRow[10].GetString();
        u.mail = pRow[11].GetString();
        m_allCachedUsers.push_back(u);
​
        LOG_INFO << "userid: " << u.userid << ", username: " << u.username << ", password: " << u.password << ", nickname: " << u.nickname << ", signature: " << u.signature;
        
        //计算当前最大userid
        if (u.userid < GROUPID_BOUBDARY && u.userid > m_baseUserId)
            m_baseUserId = u.userid;
​
        //计算当前最大群组id
        if (u.userid > GROUPID_BOUBDARY && u.userid > m_baseGroupId)
            m_baseGroupId = u.userid;
​
        if (!pResult->NextRow())
        {
            break;
        }
    }
​
    LOG_INFO << "current base userid: " << m_baseUserId << ", current base group id: " << m_baseGroupId;
​
    pResult->EndQuery();
​
    return true;
}

从t_user_relationship数据库中找userid的好友关系

bool UserManager::LoadRelationhipFromDb(int32_t userid, std::set<int32_t>& r)
{
    std::unique_ptr<CDatabaseMysql> pConn;
    pConn.reset(new CDatabaseMysql());
    if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
    {
        LOG_FATAL << "UserManager::LoadRelationhipFromDb failed, please check params";
        return false;
    }
​
    char sql[256] = { 0 };
    snprintf(sql, 256, "SELECT f_user_id1, f_user_id2 FROM t_user_relationship WHERE f_user_id1 = %d OR f_user_id2 = %d ", userid, userid);
    QueryResult* pResult = pConn->Query(sql);
    if (NULL == pResult)
    {
        LOG_INFO << "UserManager::Query error, db=" << m_strDbName;
        return false;
    }
​
    while (true)
    {
        Field* pRow = pResult->Fetch();
        if (pRow == NULL)
            break;
​
        int friendid1 = pRow[0].GetInt32();
        int friendid2 = pRow[1].GetInt32();
        if (friendid1 == userid)
        {
            r.insert(friendid2);
            LOG_INFO << "userid=" << userid << ", friendid=" << friendid2;
        }
        else
        {
            r.insert(friendid1);
            LOG_INFO << "userid=" << userid << ", friendid=" << friendid1;
        }
​
        
        if (!pResult->NextRow())
        {
            break;
        }
    }
​
    pResult->EndQuery();
    
    return true;
}

添加用户到数据库中。先把用户添加到数据库里,再把用户添加到m_allCachedUsers

bool UserManager::AddUser(User& u)
{
    std::unique_ptr<CDatabaseMysql> pConn;
    pConn.reset(new CDatabaseMysql());
    if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
    {
        LOG_FATAL << "UserManager::AddUser failed, please check params";
        return false;
    }
​
    ++ m_baseUserId;
    char sql[256] = { 0 };
    snprintf(sql, 256, "INSERT INTO t_user(f_user_id, f_username, f_nickname, f_password, f_register_time) VALUES(%d, '%s', '%s', '%s', NOW())", m_baseUserId, u.username.c_str(), u.nickname.c_str(), u.password.c_str());
    if (!pConn->Execute(sql))
    {
        LOG_WARN << "insert user error, sql=" << sql;
        return false;
    }
    //设置一些字段的默认值
    u.userid = m_baseUserId;
    u.facetype = 0;
    u.birthday = 19900101;
    u.gender = 0;
    u.ownerid = 0;
​
    {
        std::lock_guard<std::mutex> guard(m_mutex);
        m_allCachedUsers.push_back(u);
    }
​
    return true;
}

创建两个用户的好友关系,先把两个用户的关系放入到表t_user_relationship。然后再给两个用户之间互相添加好友,AddFriendToUser。

bool UserManager::MakeFriendRelationship(int32_t smallUserid, int32_t greaterUserid)
{
    if (smallUserid >= greaterUserid)
        return false;
​
    std::unique_ptr<CDatabaseMysql> pConn;
    pConn.reset(new CDatabaseMysql());
    if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
    {
        LOG_FATAL << "UserManager::LoadUsersFromDb failed, please check params";
        return false;
    }
​
    char sql[256] = { 0 };
    snprintf(sql, 256, "INSERT INTO t_user_relationship(f_user_id1, f_user_id2) VALUES(%d, %d)", smallUserid, greaterUserid);
    if (!pConn->Execute(sql))
    {
        LOG_WARN << "make relationship error, sql=" << sql << ", smallUserid = " << smallUserid << ", greaterUserid = " << greaterUserid;;
        return false;
    }
    
    if (!AddFriendToUser(smallUserid, greaterUserid))
    {
        LOG_WARN << "make relationship error, smallUserid=" << smallUserid << ", greaterUserid=" << greaterUserid;
        return false;
    }
​
    return true;
}

添加好友就是在user的好友list里添加对方的userid。

bool UserManager::AddFriendToUser(int32_t userid, int32_t friendid)
{
    bool bFound1 = false;
    bool bFound2 = false;
    std::lock_guard<std::mutex> guard(m_mutex);
    for (auto& iter : m_allCachedUsers)
    {
        if (iter.userid == userid)
        {
            iter.friends.insert(friendid);
            bFound1 = true;
        }
​
        if (iter.userid == friendid)
        {
            iter.friends.insert(userid);
            bFound2 = true;
        }
​
        if (bFound1 && bFound2)
            return true;
    }
​
    return false;
}

删除好友,就是把两个好友之间的好友列表互相剔除。在 m_allCachedUsers里找到userid和friendid,然后在userid的好友列表剔除friendid,friendid的好友列表剔除userid。

bool UserManager::DeleteFriendToUser(int32_t userid, int32_t friendid)
{
    bool bFound1 = false;
    bool bFound2 = false;
    std::lock_guard<std::mutex> guard(m_mutex);
    for (auto& iter : m_allCachedUsers)
    {
        if (iter.userid == userid)
        {
            iter.friends.erase(friendid);
            bFound1 = true;
        }
​
        if (iter.userid == friendid)
        {
            iter.friends.erase(userid);
            bFound2 = true;
        }
​
        if (bFound1 && bFound2)
            return true;
    }
​
    return false;
}

更新用户信息,先去数据库里把用户信息更新一下,然后再去m_allCachedUsers根据userid找到对应的用户,然后把用户信息更新一下。

bool UserManager::UpdateUserInfo(int32_t userid, const User& newuserinfo)
{
    std::unique_ptr<CDatabaseMysql> pConn;
    pConn.reset(new CDatabaseMysql());
    if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
    {
        LOG_ERROR << "UserManager::Initialize db failed, please check params";
        return false;
    }
​
    std::ostringstream osSql;
    osSql << "UPDATE t_user SET f_nickname='"        
          << newuserinfo.nickname << "', f_facetype=" 
          << newuserinfo.facetype << ", f_customface='" 
          << newuserinfo.customface << "', f_gender=" 
          << newuserinfo.gender << ", f_birthday=" 
          << newuserinfo.birthday << ", f_signature='" 
          << newuserinfo.signature << "', f_address='" 
          << newuserinfo.address << "', f_phonenumber='" 
          << newuserinfo.phonenumber << "', f_mail='" 
          << newuserinfo.mail << "' WHERE f_user_id=" 
          << userid;
    if (!pConn->Execute(osSql.str().c_str()))
    {
        LOG_ERROR << "UpdateUserInfo error, sql=" << osSql.str();
        return false;
    }
​
    LOG_INFO << "update userinfo successfully, userid: " << userid << ", sql: " << osSql.str();
​
    std::lock_guard<std::mutex> guard(m_mutex);
    for (auto& iter : m_allCachedUsers)
    {
        if (iter.userid == userid)
        {
            iter.nickname = newuserinfo.nickname;
            iter.facetype = newuserinfo.facetype;
            iter.customface = newuserinfo.customface;
            iter.gender = newuserinfo.gender;
            iter.birthday = newuserinfo.birthday;
            iter.signature = newuserinfo.signature;
            iter.address = newuserinfo.address;
            iter.phonenumber = newuserinfo.phonenumber;
            iter.mail = newuserinfo.mail;
            return true;
        }
    }
​
    LOG_ERROR << "update userinfo to db successfully, find exsit user in memory error, m_allCachedUsers.size(): " << m_allCachedUsers.size() << ", userid: " << userid << ", sql : " << osSql.str();
​
    return false;
}

更改密码。先是去数据库里改密码,然后再去m_allCachedUsers里改密码。

bool UserManager::ModifyUserPassword(int32_t userid, const std::string& newpassword)
{
    std::unique_ptr<CDatabaseMysql> pConn;
    pConn.reset(new CDatabaseMysql());
    if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
    {
        LOG_ERROR << "UserManager::Initialize db failed, please check params";
        return false;
    }
​
    std::ostringstream osSql;
    osSql << "UPDATE t_user SET f_password='"
        << newpassword << "' WHERE f_user_id="
        << userid;
    if (!pConn->Execute(osSql.str().c_str()))
    {
        LOG_ERROR << "UpdateUserInfo error, sql=" << osSql.str();
        return false;
    }
​
    LOG_INFO << "update user password successfully, userid: " << userid << ", sql : " << osSql.str();
​
    std::lock_guard<std::mutex> guard(m_mutex);
    for (auto& iter : m_allCachedUsers)
    {
        if (iter.userid == userid)
        {
            iter.password = newpassword;         
            return true;
        }
    }
​
    LOG_ERROR << "update user password to db successfully, find exsit user in memory error, m_allCachedUsers.size(): " << m_allCachedUsers.size() << ", userid: " << userid << ", sql : " << osSql.str();
​
    return false;
}

添加群,就是把groupid当成userid,然后群当成用户user,插入到t_user。

bool UserManager::AddGroup(const char* groupname, int32_t ownerid, int32_t& groupid)
{
    std::unique_ptr<CDatabaseMysql> pConn;
    pConn.reset(new CDatabaseMysql());
    if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
    {
        LOG_FATAL << "UserManager::AddUser failed, please check params";
        return false;
    }
​
    ++m_baseGroupId;
    char sql[256] = { 0 };
    snprintf(sql, 256, "INSERT INTO t_user(f_user_id, f_username, f_nickname, f_password, f_owner_id, f_register_time) VALUES(%d, '%d', '%s', '', %d,  NOW())", m_baseGroupId, m_baseGroupId, groupname, ownerid);
    if (!pConn->Execute(sql))
    {
        LOG_WARN << "insert group error, sql=" << sql;
        return false;
    }
    
    groupid = m_baseGroupId;
​
    User u;
    u.userid = groupid;
    char szUserName[12] = { 0 };
    snprintf(szUserName, 12, "%d", groupid);
    u.username = szUserName;
    u.nickname = groupname;
    u.ownerid = ownerid;
    {
        std::lock_guard<std::mutex> guard(m_mutex);
        m_allCachedUsers.push_back(u);
    }
​
    return true;
}

插入聊天信息到数据库中

数据库里有一个表t_chatmsg,插入的信息有发送者id和接收者id,聊天信息string。

bool UserManager::SaveChatMsgToDb(int32_t senderid, int32_t targetid, const std::string& chatmsg)
{
    std::unique_ptr<CDatabaseMysql> pConn;
    pConn.reset(new CDatabaseMysql());
    if (!pConn->Initialize(m_strDbServer, m_strDbUserName, m_strDbPassword, m_strDbName))
    {
        LOG_FATAL << "UserManager::SaveChatMsgToDb failed, please check params";
        return false;
    }
​
    ostringstream sql;
    sql << "INSERT INTO t_chatmsg(f_senderid, f_targetid, f_msgcontent) VALUES(" << senderid << ", " << targetid << ", '" << chatmsg << "')";
    if (!pConn->Execute(sql.str().c_str()))
    {
        LOG_WARN << "UserManager::SaveChatMsgToDb, sql=" << sql.str() << ", senderid = " << senderid << ", targetid = " << targetid << ", chatmsg:" << chatmsg;
        return false;
    }
​
    return true;
}
  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值