Refactor chat system: Introduce ChatRoom and ChatUser classes
- Created ChatRoom class to manage chat room functionalities, including user management, message handling, and game mechanics. - Developed ChatUser class to represent individual users, handling user-specific actions and interactions within chat rooms. - Implemented a Config class for loading configuration settings from a JSON file. - Established a Server class to manage connections, handle requests, and facilitate communication between users and chat rooms. - Introduced a Database class for database interactions, utilizing PostgreSQL for user and room data management. - Added utility functions in the Base class for JSON handling and socket communication. - Created Object classes for Room and User to encapsulate their properties and behaviors. - Updated main function to initialize server and load chat rooms from configuration.
This commit is contained in:
297
src/core/chat_room.cpp
Executable file
297
src/core/chat_room.cpp
Executable file
@@ -0,0 +1,297 @@
|
||||
#include "chat_room.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "server.h"
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <thread>
|
||||
|
||||
namespace Yc
|
||||
{
|
||||
namespace Lib
|
||||
{
|
||||
|
||||
ChatRoom::ChatRoom(std::shared_ptr<Server> parent, Json::Value roomParams)
|
||||
: _room(roomParams),
|
||||
_parent(std::move(parent)),
|
||||
_blocked(false),
|
||||
_stop(false),
|
||||
_roundRunning(false)
|
||||
{
|
||||
_name = roomParams["name"].asString();
|
||||
_password = roomParams["password"].asString();
|
||||
for (auto &user : roomParams["allowed"])
|
||||
{
|
||||
_allowedUsers.push_back(user.asString());
|
||||
}
|
||||
_type = (RoomType)roomParams["type"].asInt();
|
||||
_roundLength = roomParams["roundlength"].asInt();
|
||||
_lastRoundEnd = std::time(NULL);
|
||||
thread = std::make_unique<std::thread>(&ChatRoom::run, this);
|
||||
}
|
||||
|
||||
ChatRoom::~ChatRoom() = default;
|
||||
|
||||
void ChatRoom::run()
|
||||
{
|
||||
while (!_stop)
|
||||
{
|
||||
if (_msgQueue.size() > 0 && !_blocked)
|
||||
{
|
||||
_blocked = true;
|
||||
while (_msgQueue.size() > 0)
|
||||
{
|
||||
Message message = _msgQueue.front();
|
||||
for (auto &user : _users)
|
||||
{
|
||||
user->sendMsg(message.type, message.messageTr, message.userName, message.color);
|
||||
}
|
||||
_msgQueue.pop();
|
||||
}
|
||||
_blocked = false;
|
||||
}
|
||||
if ((_type & dice) == dice)
|
||||
{
|
||||
_handleDice();
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatRoom::addUser(std::string _userName, std::string color, std::string _password, int socket)
|
||||
{
|
||||
if (_password != "" && _password == _password && std::find(std::begin(_allowedUsers), std::end(_allowedUsers), _userName) == std::end(_allowedUsers))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto newUser = std::make_shared<ChatUser>(shared_from_this(), _userName, color, socket);
|
||||
_users.push_back(newUser);
|
||||
newUser->sendMsg(ChatUser::roomList, _parent->jsonRoomList(), "", "");
|
||||
addMessage(ChatUser::system, "room_entered", newUser->name(), newUser->color());
|
||||
_initRound();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatRoom::addUser(std::shared_ptr<ChatUser> user, std::string password)
|
||||
{
|
||||
if (password == _password)
|
||||
{
|
||||
_users.push_back(user);
|
||||
user->setParent(shared_from_this());
|
||||
_initRound();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatRoom::userNameExists(std::string userName)
|
||||
{
|
||||
for (const auto &user : _users)
|
||||
{
|
||||
if (user->name() == userName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatRoom::removeUser(std::string _token, bool silent)
|
||||
{
|
||||
for (auto it = _users.begin(); it != _users.end(); ++it)
|
||||
{
|
||||
if ((*it)->validateToken(_token))
|
||||
{
|
||||
if (!silent)
|
||||
{
|
||||
addMessage(ChatUser::system, (*it)->name(), (*it)->color());
|
||||
}
|
||||
_users.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::removeUser(std::shared_ptr<ChatUser> userToRemove, bool silent)
|
||||
{
|
||||
for (auto it = _users.begin(); it != _users.end(); ++it)
|
||||
{
|
||||
if (*it == userToRemove)
|
||||
{
|
||||
if (!silent)
|
||||
{
|
||||
addMessage(ChatUser::system, (*it)->name(), (*it)->color());
|
||||
}
|
||||
_users.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::setStop()
|
||||
{
|
||||
_stop = true;
|
||||
}
|
||||
|
||||
void ChatRoom::addMessage(ChatUser::MsgType type, const char *messageText, std::string userName, std::string color)
|
||||
{
|
||||
addMessage(type, (std::string)messageText, userName, color);
|
||||
}
|
||||
|
||||
void ChatRoom::addMessage(ChatUser::MsgType type, std::string messageText, std::string userName, std::string color)
|
||||
{
|
||||
Message message;
|
||||
message.type = type;
|
||||
message.messageTr = messageText;
|
||||
message.userName = userName;
|
||||
message.color = color;
|
||||
_msgQueue.push(message);
|
||||
}
|
||||
|
||||
void ChatRoom::addMessage(ChatUser::MsgType type, Json::Value messageText, std::string userName, std::string color)
|
||||
{
|
||||
addMessage(type, getJsonString(messageText), userName, color);
|
||||
}
|
||||
|
||||
void ChatRoom::addUserWhenQueueEmpty(std::shared_ptr<ChatUser> user)
|
||||
{
|
||||
while (_msgQueue.size() > 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
_users.push_back(user);
|
||||
user->setParent(shared_from_this());
|
||||
}
|
||||
|
||||
bool ChatRoom::userToNewRoom(std::shared_ptr<ChatUser> user, std::string newRoom, std::string password)
|
||||
{
|
||||
return _parent->changeRoom(user, newRoom, password);
|
||||
}
|
||||
|
||||
unsigned int ChatRoom::flags()
|
||||
{
|
||||
unsigned int value = (unsigned int)_type;
|
||||
if (_password != "")
|
||||
{
|
||||
value += (unsigned int)ChatRoom::password;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Json::Value ChatRoom::userList()
|
||||
{
|
||||
Json::Value users = Json::arrayValue;
|
||||
for (auto &user : _users)
|
||||
{
|
||||
Json::Value jsonUser = Json::objectValue;
|
||||
jsonUser["name"] = user->name();
|
||||
users.append(jsonUser);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
ChatRoom::RoomType ChatRoom::type()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
bool ChatRoom::isType(ChatRoom::RoomType type)
|
||||
{
|
||||
return ((_type & type) == type);
|
||||
}
|
||||
|
||||
bool ChatRoom::canDice()
|
||||
{
|
||||
return (_roundRunning || (_type & rounds) == rounds) && (_type & dice) == dice;
|
||||
}
|
||||
|
||||
unsigned int ChatRoom::addDice(std::shared_ptr<ChatUser> user, int diceValue)
|
||||
{
|
||||
if (!canDice())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
for (auto &listUser : _diceValues)
|
||||
{
|
||||
if (listUser.first == user)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
_diceValues.push_back(std::make_pair(user, diceValue));
|
||||
addMessage(ChatUser::dice, std::to_string(diceValue), user->name(), user->color());
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ChatRoom::accessAllowed(std::string userName, std::string password)
|
||||
{
|
||||
return (_allowedUsers.size() == 0 || _password == "" || _password == password || std::find(_allowedUsers.begin(), _allowedUsers.end(), userName) != _allowedUsers.end());
|
||||
}
|
||||
|
||||
bool ChatRoom::userIsInRoom(std::string userName)
|
||||
{
|
||||
for (auto &user : _users)
|
||||
{
|
||||
if (userName == user->name())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatRoom::_handleDice()
|
||||
{
|
||||
if (((_type & rounds) == rounds))
|
||||
{
|
||||
if (_roundRunning && (_users.size() < 2 || _roundStart + _roundLength >= time(NULL)))
|
||||
{
|
||||
_lastRoundEnd = time(NULL);
|
||||
_roundRunning = false;
|
||||
addMessage(ChatUser::system, "round_ends");
|
||||
_showDiceRoundResults();
|
||||
}
|
||||
else if (!_roundRunning && _lastRoundEnd <= time(NULL) - 15 && _users.size() >= 2)
|
||||
{
|
||||
_roundStart = time(NULL);
|
||||
_roundRunning = true;
|
||||
_diceValues.clear();
|
||||
addMessage(ChatUser::system, "next_round_starts_now");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::_initRound()
|
||||
{
|
||||
if (_users.size() == 2)
|
||||
{
|
||||
_lastRoundEnd = time(NULL);
|
||||
addMessage(ChatUser::system, "next_round_starts_soon");
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoom::_showDiceRoundResults()
|
||||
{
|
||||
std::sort(_diceValues.begin(), _diceValues.end(), [=](const std::pair<std::shared_ptr<ChatUser>, int> &val1, const std::pair<std::shared_ptr<ChatUser>, int> &val2)
|
||||
{ return (val1.second > val2.second); });
|
||||
Json::Value userList = Json::arrayValue;
|
||||
for (auto &user : _diceValues)
|
||||
{
|
||||
Json::Value entry = Json::objectValue;
|
||||
entry["name"] = user.first->name();
|
||||
entry["value"] = user.second;
|
||||
userList.append(entry);
|
||||
}
|
||||
addMessage(ChatUser::result, userList);
|
||||
}
|
||||
|
||||
std::string ChatRoom::name()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
} // namespace Lib
|
||||
} // namespace Yc
|
||||
Reference in New Issue
Block a user