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; //为了避免重复 };
用户管理器
用户管理器的成员
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; }
添加用户到数据库中
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; }