diff --git a/CMakeLists.txt b/CMakeLists.txt index f04d568..87a126f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,17 @@ project(YourChat VERSION 0.1) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED True) -include_directories(${PROJECT_SOURCE_DIR}) - add_executable(yourchat main.cpp base.cpp config.cpp server.cpp chat_room.cpp tools.cpp chat_user.cpp database.cpp) +include_directories(${PROJECT_SOURCE_DIR}/src) + add_executable(yourchat + src/main.cpp + src/lib/base.cpp + src/core/config.cpp + src/core/server.cpp + src/core/chat_room.cpp + src/lib/tools.cpp + src/core/chat_user.cpp + src/lib/database.cpp + src/object/user.cpp + src/object/room.cpp + ) target_link_libraries(yourchat jsoncpp pthread pqxx) diff --git a/chat_user.cpp b/chat_user.cpp deleted file mode 100644 index db47420..0000000 --- a/chat_user.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// entfernt: #include "user.h" - -#include "chat_user.h" -#include -#include -#include -#include -#include -#include "chat_room.h" -#include -#include -#include -#include - -namespace Yc { -namespace Lib { - -ChatUser::ChatUser(std::shared_ptr parent, std::string name, std::string color, int socket) : - _parent(std::move(parent)), - _name(std::move(name)), - _color(std::move(color)), - _socket(socket), - _stop(false) { - _token = Yc::Lib::Tools::generateRandomString(32); - sendMsg(token, _token, "", ""); - thread = std::make_unique(&ChatUser::checkerTask, this); -} - - -ChatUser::~ChatUser() { - _parent->addMessage(ChatUser::system, std::string("leaved_chat"), std::string(_name), std::string(_color)); -} - -std::string ChatUser::name() const { - return _name; -} - -bool ChatUser::validateToken(std::string token) { - return (token == _token); -} - -bool ChatUser::isUser(std::shared_ptr toValidate) { - return (toValidate.get() == this); -} - -void ChatUser::sendMsg(MsgType type, const char *message, std::string userName, std::string color) { - sendMsg(type, std::string(message), userName, color); -} - -void ChatUser::sendMsg(MsgType type, std::string message , std::string userName, std::string color) { - Json::Value sendMessage; - sendMessage["type"] = type; - sendMessage["message"] = message; - sendMessage["userName"] = userName; - sendMessage["color"] = color; - send(sendMessage); -} - -void ChatUser::sendMsg(ChatUser::MsgType type, Json::Value message, std::string userName, std::string color) { - Json::Value sendMessage; - sendMessage["type"] = type; - sendMessage["message"] = message; - sendMessage["userName"] = userName; - sendMessage["color"] = color; - send(sendMessage); -} - -void ChatUser::checkerTask() { - while (!_stop) { - fd_set readSd; - FD_ZERO(&readSd); - FD_SET(_socket, &readSd); - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 500; - int selectResult = select(_socket + 1, &readSd, NULL, NULL, &tv); - if (selectResult == 1 && FD_ISSET(_socket, &readSd) == 1) { - _parent->removeUser(_token); - _stop = true; - delete this; - return; - } - std::string msg = readSocket(_socket); - if (msg == "") { - continue; - } - handleMessage(msg); - } -} - -void ChatUser::stop() { - _stop = true; -} - -std::string ChatUser::color() const { - return _color; -} - -void ChatUser::setParent(std::shared_ptr parent) { - _parent = std::move(parent); -} - -void ChatUser::send(std::string out) { - Base::send(_socket, out); -} - -void ChatUser::send(Json::Value out) { - Base::send(_socket, out); -} - -void ChatUser::handleMessage(std::string message) { - Json::Value jsonTree = getJsonTree(message); - if (jsonTree["token"].asString() != _token) { - return; - } - if (jsonTree["type"].asString() == "message") { - checkString(jsonTree["message"].asString()); - } else if (jsonTree["type"].asString() == "dice") { - doDice(); - } else if (jsonTree["type"].asString() == "scream") { - _parent->addMessage(ChatUser::scream, jsonTree["message"].asString(), std::string(_name), std::string(_color)); - } else if (jsonTree["type"].asString() == "do") { - _parent->addMessage(ChatUser::dosomething, jsonTree["message"].asString(), std::string(_name), std::string(_color)); - } else if (jsonTree["type"].asString() == "join") { - changeRoom(jsonTree["newroom"].asString(), jsonTree["password"].asString()); - } else if (jsonTree["type"].asString() == "userlist") { - sendUserList(); - } -} - -void ChatUser::checkString(std::string message) { - if (message.substr(0, 6) == "/join ") { - message = message.substr(6); - if (message.find(" ") == std::string::npos) { - changeRoom(message, ""); - } else { - std::string room = message.substr(0, message.find(" ")); - std::string password = message.substr(message.find(" ") + 1); - changeRoom(room, password); - } - } else if (message == "/dice") { - doDice(); - } else { - _parent->addMessage(ChatUser::message, std::string(message), std::string(_name), std::string(_color)); - } -} - -void ChatUser::sendUserList() { - Json::Value userList = _parent->userList(); - Json::Value msg = Json::objectValue; - msg["userlist"] = userList; - sendMsg(userListe, msg, "", ""); -} - -void ChatUser::doDice() { - switch (_parent->addDice(shared_from_this(), (rand() % 6) + 1)) { - case 1: - sendMsg(system, "dice_not_possible", "", ""); - break; - case 2: - sendMsg(system, "dice_allready_done", "", ""); - break; - default: - break; - } -} - -void ChatUser::changeRoom(std::string newRoom, std::string password) { - if (!_parent->userToNewRoom(shared_from_this(), newRoom, password)) { - sendMsg(ChatUser::system, "room_not_possible", "", ""); - } -} - -} // namespace Lib -} // namespace Yc diff --git a/chat_user.h b/chat_user.h deleted file mode 100644 index 34936e5..0000000 --- a/chat_user.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef YC_LIB_CHAT_USER_H -#define YC_LIB_CHAT_USER_H - -#include -#include -#include -#include -#include -#include "base.h" - -namespace Yc { -namespace Lib { - -class ChatRoom; - -class ChatUser: public Base, public std::enable_shared_from_this { -public: - enum MsgType { - error = -1, - token = 1, - userListe = 2, - roomList = 3, - message = 4, - system = 5, - scream = 6, - dosomething = 7, - dice = 8, - result = 9 - }; - - ChatUser(std::shared_ptr parent, std::string name, std::string color, int socket); - ~ChatUser(); - std::string name() const; - bool validateToken(std::string token); - bool isUser(std::shared_ptr toValidate); - void sendMsg(MsgType type, std::string message, std::string userName, std::string color); - void sendMsg(MsgType type, const char *message, std::string userName, std::string color); - void sendMsg(MsgType type, Json::Value message, std::string userName, std::string color); - void checkerTask(); - void stop(); - std::string color() const; - void setParent(std::shared_ptr parent); - -private: - std::shared_ptr _parent; - std::string _name; - std::string _color; - int _socket; - std::string _token; - bool _stop; - std::unique_ptr thread; - - void send(std::string out); - void send(Json::Value out); - void handleMessage(std::string message); - void doDice(); - void changeRoom(std::string newRoom, std::string password); - void checkString(std::string message); - void sendUserList(); -}; - -} // namespace Lib -} // namespace Yc - -#endif // YC_LIB_CHAT_USER_H diff --git a/db_example.cpp b/db_example.cpp deleted file mode 100644 index f1165d0..0000000 --- a/db_example.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include - -int main() { - try { - pqxx::connection c{"dbname=your_db user=your_user password=your_pass host=localhost"}; - pqxx::work txn{c}; - pqxx::result r = txn.exec("SELECT version();"); - for (auto row : r) { - std::cout << row[0].c_str() << std::endl; - } - } catch (const std::exception &e) { - std::cerr << "PostgreSQL error: " << e.what() << std::endl; - return 1; - } - return 0; -} diff --git a/src/chat_room.cpp b/src/chat_room.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/chat_room.h b/src/chat_room.h new file mode 100644 index 0000000..e69de29 diff --git a/src/chat_user.cpp b/src/chat_user.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/chat_user.h b/src/chat_user.h new file mode 100644 index 0000000..e69de29 diff --git a/chat_room.cpp b/src/core/chat_room.cpp similarity index 64% rename from chat_room.cpp rename to src/core/chat_room.cpp index 40f674c..a48b3f9 100755 --- a/chat_room.cpp +++ b/src/core/chat_room.cpp @@ -1,7 +1,7 @@ #include "chat_room.h" #include -#include +#include "server.h" #include #include #include @@ -9,18 +9,22 @@ #include #include -namespace Yc { - namespace Lib { +namespace Yc +{ + namespace Lib + { - ChatRoom::ChatRoom(std::shared_ptr parent, Json::Value roomParams) : - _parent(std::move(parent)), - _blocked(false), - _stop(false), - _roundRunning(false) { + ChatRoom::ChatRoom(std::shared_ptr parent, Json::Value roomParams) + : _room(roomParams), + _parent(std::move(parent)), + _blocked(false), + _stop(false), + _roundRunning(false) + { _name = roomParams["name"].asString(); _password = roomParams["password"].asString(); - std::vector allowedUsers; - for (auto &user: roomParams["allowed"]) { + for (auto &user : roomParams["allowed"]) + { _allowedUsers.push_back(user.asString()); } _type = (RoomType)roomParams["type"].asInt(); @@ -29,30 +33,38 @@ namespace Yc { thread = std::make_unique(&ChatRoom::run, this); } - ChatRoom::~ChatRoom() = default; + ChatRoom::~ChatRoom() = default; - void ChatRoom::run() { - while (!_stop) { - if (_msgQueue.size() > 0 && !_blocked) { + void ChatRoom::run() + { + while (!_stop) + { + if (_msgQueue.size() > 0 && !_blocked) + { _blocked = true; - while (_msgQueue.size() > 0) { + while (_msgQueue.size() > 0) + { Message message = _msgQueue.front(); - for (auto &user: _users) { + for (auto &user : _users) + { user->sendMsg(message.type, message.messageTr, message.userName, message.color); } _msgQueue.pop(); } _blocked = false; } - if ((_type & dice) == dice) { + 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)) { + 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(shared_from_this(), _userName, color, socket); @@ -63,8 +75,10 @@ namespace Yc { return true; } - bool ChatRoom::addUser(std::shared_ptr user, std::string password) { - if (password == _password) { + bool ChatRoom::addUser(std::shared_ptr user, std::string password) + { + if (password == _password) + { _users.push_back(user); user->setParent(shared_from_this()); _initRound(); @@ -73,19 +87,26 @@ namespace Yc { return false; } - bool ChatRoom::userNameExists(std::string userName) { - for (const auto &user: _users) { - if (user->name() == userName) { + 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) { + 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); @@ -94,10 +115,14 @@ namespace Yc { } } - void ChatRoom::removeUser(std::shared_ptr userToRemove, bool silent) { - for (auto it = _users.begin(); it != _users.end(); ++it) { - if (*it == userToRemove) { - if (!silent) { + void ChatRoom::removeUser(std::shared_ptr 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); @@ -106,15 +131,18 @@ namespace Yc { } } - void ChatRoom::setStop() { + void ChatRoom::setStop() + { _stop = true; } - void ChatRoom::addMessage(ChatUser::MsgType type, const char *messageText, std::string userName, std::string color) { + 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) { + void ChatRoom::addMessage(ChatUser::MsgType type, std::string messageText, std::string userName, std::string color) + { Message message; message.type = type; message.messageTr = messageText; @@ -123,33 +151,41 @@ namespace Yc { _msgQueue.push(message); } - void ChatRoom::addMessage(ChatUser::MsgType type, Json::Value messageText, std::string userName, std::string color) { + 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 user) { - while (_msgQueue.size() > 0) { + void ChatRoom::addUserWhenQueueEmpty(std::shared_ptr 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 user, std::string newRoom, std::string password) { + bool ChatRoom::userToNewRoom(std::shared_ptr user, std::string newRoom, std::string password) + { return _parent->changeRoom(user, newRoom, password); } - unsigned int ChatRoom::flags() { + unsigned int ChatRoom::flags() + { unsigned int value = (unsigned int)_type; - if (_password != "") { + if (_password != "") + { value += (unsigned int)ChatRoom::password; } return value; } - Json::Value ChatRoom::userList() { + Json::Value ChatRoom::userList() + { Json::Value users = Json::arrayValue; - for (auto &user: _users) { + for (auto &user : _users) + { Json::Value jsonUser = Json::objectValue; jsonUser["name"] = user->name(); users.append(jsonUser); @@ -157,24 +193,31 @@ namespace Yc { return users; } - ChatRoom::RoomType ChatRoom::type() { + ChatRoom::RoomType ChatRoom::type() + { return _type; } - bool ChatRoom::isType(ChatRoom::RoomType type) { + bool ChatRoom::isType(ChatRoom::RoomType type) + { return ((_type & type) == type); } - bool ChatRoom::canDice() { + bool ChatRoom::canDice() + { return (_roundRunning || (_type & rounds) == rounds) && (_type & dice) == dice; } - unsigned int ChatRoom::addDice(std::shared_ptr user, int diceValue) { - if (!canDice()) { + unsigned int ChatRoom::addDice(std::shared_ptr user, int diceValue) + { + if (!canDice()) + { return 1; } - for (auto &listUser: _diceValues) { - if (listUser.first == user) { + for (auto &listUser : _diceValues) + { + if (listUser.first == user) + { return 2; } } @@ -183,27 +226,36 @@ namespace Yc { return 0; } - bool ChatRoom::accessAllowed(std::string userName, std::string password) { + 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()) { + 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))) { + 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) { + } + else if (!_roundRunning && _lastRoundEnd <= time(NULL) - 15 && _users.size() >= 2) + { _roundStart = time(NULL); _roundRunning = true; _diceValues.clear(); @@ -212,19 +264,22 @@ namespace Yc { } } - void ChatRoom::_initRound() { - if (_users.size() == 2) { + 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, int>& val1, const std::pair, int>& val2) { - return (val1.second > val2.second); - }); + void ChatRoom::_showDiceRoundResults() + { + std::sort(_diceValues.begin(), _diceValues.end(), [=](const std::pair, int> &val1, const std::pair, int> &val2) + { return (val1.second > val2.second); }); Json::Value userList = Json::arrayValue; - for (auto &user: _diceValues) { + for (auto &user : _diceValues) + { Json::Value entry = Json::objectValue; entry["name"] = user.first->name(); entry["value"] = user.second; @@ -233,7 +288,8 @@ namespace Yc { addMessage(ChatUser::result, userList); } - std::string ChatRoom::name() { + std::string ChatRoom::name() + { return _name; } diff --git a/chat_room.h b/src/core/chat_room.h similarity index 86% rename from chat_room.h rename to src/core/chat_room.h index bd23742..c352717 100755 --- a/chat_room.h +++ b/src/core/chat_room.h @@ -2,7 +2,6 @@ #ifndef YC_LIB_CHAT_ROOM_H #define YC_LIB_CHAT_ROOM_H - #include #include #include @@ -11,18 +10,22 @@ #include #include -#include +#include "lib/base.h" #include "chat_user.h" +#include "object/room.h" -namespace Yc { - namespace Lib { +namespace Yc +{ + namespace Lib + { + class Server; - class Server; - - class ChatRoom: public Base, public std::enable_shared_from_this { + class ChatRoom : public Base, public std::enable_shared_from_this + { public: - enum RoomType { + enum RoomType + { none = 0, dice = 1, poker = 2, @@ -32,6 +35,7 @@ namespace Yc { ChatRoom(std::shared_ptr parent, Json::Value roomParams); ~ChatRoom(); + std::shared_ptr getServer() const { return _parent; } void run(); std::string name(); bool addUser(std::string userName, std::string color, std::string password, int socket); @@ -40,7 +44,7 @@ namespace Yc { void removeUser(std::string _token, bool silent = false); void removeUser(std::shared_ptr user, bool silent = false); void setStop(); - void addMessage(ChatUser::MsgType type, const char* messageText, std::string userName = "", std::string color = ""); + void addMessage(ChatUser::MsgType type, const char *messageText, std::string userName = "", std::string color = ""); void addMessage(ChatUser::MsgType type, std::string messageText, std::string userName = "", std::string color = ""); void addMessage(ChatUser::MsgType type, Json::Value messageText, std::string userName = "", std::string color = ""); RoomType type(); @@ -53,8 +57,10 @@ namespace Yc { bool userToNewRoom(std::shared_ptr user, std::string newRoom, std::string password); unsigned int flags(); Json::Value userList(); + private: - struct Message { + struct Message + { ChatUser::MsgType type; std::string messageTr; std::string userName; @@ -76,6 +82,7 @@ namespace Yc { time_t _lastRoundEnd; int _roundLength; std::vector, int>> _diceValues; + Yc::Object::Room _room; void _handleDice(); void _startDiceRound(); void _endDiceRound(); diff --git a/src/core/chat_user.cpp b/src/core/chat_user.cpp new file mode 100644 index 0000000..fe9031d --- /dev/null +++ b/src/core/chat_user.cpp @@ -0,0 +1,275 @@ +// entfernt: #include "user.h" + +#include "chat_user.h" +#include "server.h" +#include "lib/tools.h" +#include +#include +#include +#include +#include "chat_room.h" +#include +#include +#include +#include + +namespace Yc +{ + namespace Lib + { + + ChatUser::ChatUser(std::shared_ptr parent, std::string name, std::string color, int socket) + : _parent(std::move(parent)), + _name(name), + _color(color), + _socket(socket), + _stop(false) + { + // Hole DB-Connection + auto server = _parent->getServer(); + auto db = server->_database; + // Suche Community-User + std::string query = "SELECT * FROM community.\"user\" WHERE username = '" + name + "' LIMIT 1;"; + auto result = db->exec(query); + Json::Value userJson; + if (result.empty()) { + // Kein Community-User, lege Dummy an + userJson["display_name"] = name; + userJson["color"] = "#000000"; + } else { + const auto& row = result[0]; + int falukant_user_id = row["id"].as(); + // Suche Chat-User + std::string chatUserQuery = "SELECT * FROM chat.\"user\" WHERE falukant_user_id = " + std::to_string(falukant_user_id) + " LIMIT 1;"; + auto chatUserResult = db->exec(chatUserQuery); + if (chatUserResult.empty()) { + // Chat-User anlegen + std::string insert = "INSERT INTO chat.\"user\" (falukant_user_id, display_name, color, show_gender, show_age, created_at, updated_at) VALUES (" + + std::to_string(falukant_user_id) + ", '" + name + "', '#000000', true, true, NOW(), NOW()) RETURNING *;"; + auto newUser = db->exec(insert); + if (!newUser.empty()) { + const auto& u = newUser[0]; + userJson["id"] = u["id"].as(); + userJson["falukant_user_id"] = u["falukant_user_id"].as(); + userJson["display_name"] = u["display_name"].c_str(); + userJson["color"] = u["color"].c_str(); + userJson["show_gender"] = u["show_gender"].as(); + userJson["show_age"] = u["show_age"].as(); + userJson["created_at"] = u["created_at"].c_str(); + userJson["updated_at"] = u["updated_at"].c_str(); + } + } else { + const auto& u = chatUserResult[0]; + userJson["id"] = u["id"].as(); + userJson["falukant_user_id"] = u["falukant_user_id"].as(); + userJson["display_name"] = u["display_name"].c_str(); + userJson["color"] = u["color"].c_str(); + userJson["show_gender"] = u["show_gender"].as(); + userJson["show_age"] = u["show_age"].as(); + userJson["created_at"] = u["created_at"].c_str(); + userJson["updated_at"] = u["updated_at"].c_str(); + } + // Rechte laden + std::string rightsQuery = "SELECT r.tr FROM chat.user_rights ur JOIN chat.rights r ON ur.chat_right_id = r.id WHERE ur.chat_user_id = " + std::to_string(userJson["id"].asInt()) + ";"; + auto rightsResult = db->exec(rightsQuery); + Json::Value rights(Json::arrayValue); + for (const auto& r : rightsResult) { + rights.append(r["tr"].c_str()); + } + userJson["rights"] = rights; + } + _user = Yc::Object::User(userJson); + _token = Yc::Lib::Tools::generateRandomString(32); + sendMsg(token, _token, "", ""); + thread = std::make_unique(&ChatUser::checkerTask, this); + } + + ChatUser::~ChatUser() + { + _parent->addMessage(ChatUser::system, std::string("leaved_chat"), std::string(_name), std::string(_color)); + } + + std::string ChatUser::name() const + { + return _name; + } + + bool ChatUser::validateToken(std::string token) + { + return (token == _token); + } + + bool ChatUser::isUser(std::shared_ptr toValidate) + { + return (toValidate.get() == this); + } + + void ChatUser::sendMsg(MsgType type, const char *message, std::string userName, std::string color) + { + sendMsg(type, std::string(message), userName, color); + } + + void ChatUser::sendMsg(MsgType type, std::string message, std::string userName, std::string color) + { + Json::Value sendMessage; + sendMessage["type"] = type; + sendMessage["message"] = message; + sendMessage["userName"] = userName; + sendMessage["color"] = color; + send(sendMessage); + } + + void ChatUser::sendMsg(MsgType type, Json::Value message, std::string userName, std::string color) + { + Json::Value sendMessage; + sendMessage["type"] = type; + sendMessage["message"] = message; + sendMessage["userName"] = userName; + sendMessage["color"] = color; + send(sendMessage); + } + + void ChatUser::checkerTask() + { + while (!_stop) + { + fd_set readSd; + FD_ZERO(&readSd); + FD_SET(_socket, &readSd); + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500; + int selectResult = select(_socket + 1, &readSd, NULL, NULL, &tv); + if (selectResult == 1 && FD_ISSET(_socket, &readSd) == 1) + { + _parent->removeUser(_token); + _stop = true; + delete this; + return; + } + std::string msg = readSocket(_socket); + if (msg == "") + { + continue; + } + handleMessage(msg); + } + } + + void ChatUser::stop() + { + _stop = true; + } + + std::string ChatUser::color() const + { + return _color; + } + + void ChatUser::setParent(std::shared_ptr parent) + { + _parent = std::move(parent); + } + + void ChatUser::send(std::string out) + { + Base::send(_socket, out); + } + + void ChatUser::send(Json::Value out) + { + Base::send(_socket, out); + } + + void ChatUser::handleMessage(std::string message) + { + Json::Value jsonTree = getJsonTree(message); + if (jsonTree["token"].asString() != _token) + { + return; + } + if (jsonTree["type"].asString() == "message") + { + checkString(jsonTree["message"].asString()); + } + else if (jsonTree["type"].asString() == "dice") + { + doDice(); + } + else if (jsonTree["type"].asString() == "scream") + { + _parent->addMessage(ChatUser::scream, jsonTree["message"].asString(), std::string(_name), std::string(_color)); + } + else if (jsonTree["type"].asString() == "do") + { + _parent->addMessage(ChatUser::dosomething, jsonTree["message"].asString(), std::string(_name), std::string(_color)); + } + else if (jsonTree["type"].asString() == "join") + { + changeRoom(jsonTree["newroom"].asString(), jsonTree["password"].asString()); + } + else if (jsonTree["type"].asString() == "userlist") + { + sendUserList(); + } + } + + void ChatUser::checkString(std::string message) + { + if (message.substr(0, 6) == "/join ") + { + message = message.substr(6); + if (message.find(" ") == std::string::npos) + { + changeRoom(message, ""); + } + else + { + std::string room = message.substr(0, message.find(" ")); + std::string password = message.substr(message.find(" ") + 1); + changeRoom(room, password); + } + } + else if (message == "/dice") + { + doDice(); + } + else + { + _parent->addMessage(ChatUser::message, std::string(message), std::string(_name), std::string(_color)); + } + } + + void ChatUser::sendUserList() + { + Json::Value userList = _parent->userList(); + Json::Value msg = Json::objectValue; + msg["userlist"] = userList; + sendMsg(userListe, msg, "", ""); + } + + void ChatUser::doDice() + { + switch (_parent->addDice(shared_from_this(), (rand() % 6) + 1)) + { + case 1: + sendMsg(system, "dice_not_possible", "", ""); + break; + case 2: + sendMsg(system, "dice_allready_done", "", ""); + break; + default: + break; + } + } + + void ChatUser::changeRoom(std::string newRoom, std::string password) + { + if (!_parent->userToNewRoom(shared_from_this(), newRoom, password)) + { + sendMsg(ChatUser::system, "room_not_possible", "", ""); + } + } + + } // namespace Lib +} // namespace Yc diff --git a/src/core/chat_user.h b/src/core/chat_user.h new file mode 100644 index 0000000..fe25539 --- /dev/null +++ b/src/core/chat_user.h @@ -0,0 +1,71 @@ +#ifndef YC_LIB_CHAT_USER_H +#define YC_LIB_CHAT_USER_H + +#include +#include +#include +#include +#include +#include "lib/base.h" +#include "object/user.h" + +namespace Yc +{ + namespace Lib + { + + class ChatRoom; + + class ChatUser : public Base, public std::enable_shared_from_this + { + public: + enum MsgType + { + error = -1, + token = 1, + userListe = 2, + roomList = 3, + message = 4, + system = 5, + scream = 6, + dosomething = 7, + dice = 8, + result = 9 + }; + + ChatUser(std::shared_ptr parent, std::string name, std::string color, int socket); + ~ChatUser(); + std::string name() const; + bool validateToken(std::string token); + bool isUser(std::shared_ptr toValidate); + void sendMsg(MsgType type, std::string message, std::string userName, std::string color); + void sendMsg(MsgType type, const char *message, std::string userName, std::string color); + void sendMsg(MsgType type, Json::Value message, std::string userName, std::string color); + void checkerTask(); + void stop(); + std::string color() const; + void setParent(std::shared_ptr parent); + + private: + std::shared_ptr _parent; + Yc::Object::User _user; + std::string _name; + std::string _color; + int _socket; + std::string _token; + bool _stop; + std::unique_ptr thread; + + void send(std::string out); + void send(Json::Value out); + void handleMessage(std::string message); + void doDice(); + void changeRoom(std::string newRoom, std::string password); + void checkString(std::string message); + void sendUserList(); + }; + + } // namespace Lib +} // namespace Yc + +#endif // YC_LIB_CHAT_USER_H diff --git a/config.cpp b/src/core/config.cpp similarity index 100% rename from config.cpp rename to src/core/config.cpp diff --git a/config.h b/src/core/config.h similarity index 100% rename from config.h rename to src/core/config.h diff --git a/server.cpp b/src/core/server.cpp similarity index 79% rename from server.cpp rename to src/core/server.cpp index 7d44d8d..2bb7166 100755 --- a/server.cpp +++ b/src/core/server.cpp @@ -32,7 +32,6 @@ namespace Yc { std::cout << "bind not possible" << std::endl; exit(-1); } - // createRooms wird jetzt außerhalb des Konstruktors aufgerufen } void Server::run() { @@ -114,8 +113,30 @@ namespace Yc { } void Server::createRooms(Json::Value roomList) { + // Ignoriere roomList, lade stattdessen aus der Datenbank auto self = shared_from_this(); - for (auto &room: roomList) { + std::string query = R"( + SELECT r.id, r.title, r.password_hash, r.room_type_id, r.is_public, r.owner_id, r.min_age, r.max_age, r.created_at, r.updated_at, rt.tr as room_type + FROM chat.room r + LEFT JOIN chat.room_type rt ON r.room_type_id = rt.id + )"; + auto result = _database->exec(query); + for (const auto& row : result) { + Json::Value room; + room["id"] = row["id"].as(); + room["name"] = row["title"].c_str(); + room["password"] = row["password_hash"].is_null() ? "" : row["password_hash"].c_str(); + room["type"] = row["room_type_id"].is_null() ? 0 : row["room_type_id"].as(); + room["is_public"] = row["is_public"].as(); + room["owner_id"] = row["owner_id"].is_null() ? 0 : row["owner_id"].as(); + room["min_age"] = row["min_age"].is_null() ? 0 : row["min_age"].as(); + room["max_age"] = row["max_age"].is_null() ? 0 : row["max_age"].as(); + room["created_at"] = row["created_at"].c_str(); + room["updated_at"] = row["updated_at"].c_str(); + room["room_type"] = row["room_type"].is_null() ? "" : row["room_type"].c_str(); + // Platzhalter für Felder, die im Konstruktor benötigt werden + room["allowed"] = Json::arrayValue; // ggf. später befüllen + room["roundlength"] = 60; // Default-Wert auto newRoom = std::make_shared(self, room); _rooms.push_back(newRoom); } diff --git a/server.h b/src/core/server.h similarity index 96% rename from server.h rename to src/core/server.h index 72602ee..81be4fe 100755 --- a/server.h +++ b/src/core/server.h @@ -2,10 +2,10 @@ #define YP_LIB_SERVER_H #include "config.h" -#include "database.h" +#include "lib/database.h" #include #include "chat_room.h" -#include "base.h" +#include "lib/base.h" #include namespace Yc { diff --git a/base.cpp b/src/lib/base.cpp similarity index 100% rename from base.cpp rename to src/lib/base.cpp diff --git a/base.h b/src/lib/base.h similarity index 100% rename from base.h rename to src/lib/base.h diff --git a/database.cpp b/src/lib/database.cpp similarity index 100% rename from database.cpp rename to src/lib/database.cpp diff --git a/database.h b/src/lib/database.h similarity index 93% rename from database.h rename to src/lib/database.h index 9a2a5cf..949413e 100644 --- a/database.h +++ b/src/lib/database.h @@ -3,7 +3,7 @@ #include #include -#include "config.h" +#include "../core/config.h" namespace Yc { namespace Lib { diff --git a/tools.cpp b/src/lib/tools.cpp similarity index 100% rename from tools.cpp rename to src/lib/tools.cpp diff --git a/tools.h b/src/lib/tools.h similarity index 100% rename from tools.h rename to src/lib/tools.h diff --git a/main.cpp b/src/main.cpp similarity index 80% rename from main.cpp rename to src/main.cpp index 2275449..ad33cb3 100755 --- a/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ -#include "config.h" -#include "server.h" -#include "database.h" +#include "core/config.h" +#include "core/server.h" +#include "lib/database.h" // main function int main(int, char **) { diff --git a/src/object/room.cpp b/src/object/room.cpp new file mode 100644 index 0000000..16bc2aa --- /dev/null +++ b/src/object/room.cpp @@ -0,0 +1,42 @@ +#include "room.h" + +namespace Yc +{ + namespace Object + { + + Room::Room(const Json::Value &roomJson) + { + _id = roomJson.isMember("id") && !roomJson["id"].isNull() ? roomJson["id"].asInt() : 0; + _title = roomJson.isMember("name") && !roomJson["name"].isNull() ? roomJson["name"].asString() : ""; + _owner_id = roomJson.isMember("owner_id") && !roomJson["owner_id"].isNull() ? roomJson["owner_id"].asInt() : 0; + _is_public = roomJson.isMember("is_public") && !roomJson["is_public"].isNull() ? roomJson["is_public"].asBool() : true; + _gender_restriction_id = roomJson.isMember("gender_restriction_id") && !roomJson["gender_restriction_id"].isNull() ? roomJson["gender_restriction_id"].asInt() : 0; + _min_age = roomJson.isMember("min_age") && !roomJson["min_age"].isNull() ? roomJson["min_age"].asInt() : 0; + _max_age = roomJson.isMember("max_age") && !roomJson["max_age"].isNull() ? roomJson["max_age"].asInt() : 0; + _password_hash = roomJson.isMember("password") && !roomJson["password"].isNull() ? roomJson["password"].asString() : ""; + _friends_of_owner_only = roomJson.isMember("friends_of_owner_only") && !roomJson["friends_of_owner_only"].isNull() ? roomJson["friends_of_owner_only"].asBool() : false; + _required_user_right_id = roomJson.isMember("required_user_right_id") && !roomJson["required_user_right_id"].isNull() ? roomJson["required_user_right_id"].asInt() : 0; + _created_at = roomJson.isMember("created_at") && !roomJson["created_at"].isNull() ? roomJson["created_at"].asString() : ""; + _updated_at = roomJson.isMember("updated_at") && !roomJson["updated_at"].isNull() ? roomJson["updated_at"].asString() : ""; + _room_type_id = roomJson.isMember("type") && !roomJson["type"].isNull() ? roomJson["type"].asInt() : 0; + _room_type_tr = roomJson.isMember("room_type") && !roomJson["room_type"].isNull() ? roomJson["room_type"].asString() : ""; + } + + int Room::id() const { return _id; } + const std::string &Room::title() const { return _title; } + int Room::owner_id() const { return _owner_id; } + bool Room::is_public() const { return _is_public; } + int Room::gender_restriction_id() const { return _gender_restriction_id; } + int Room::min_age() const { return _min_age; } + int Room::max_age() const { return _max_age; } + const std::string &Room::password_hash() const { return _password_hash; } + bool Room::friends_of_owner_only() const { return _friends_of_owner_only; } + int Room::required_user_right_id() const { return _required_user_right_id; } + const std::string &Room::created_at() const { return _created_at; } + const std::string &Room::updated_at() const { return _updated_at; } + int Room::room_type_id() const { return _room_type_id; } + const std::string &Room::room_type_tr() const { return _room_type_tr; } + + } // namespace Object +} // namespace Yc diff --git a/src/object/room.h b/src/object/room.h new file mode 100644 index 0000000..e721e98 --- /dev/null +++ b/src/object/room.h @@ -0,0 +1,48 @@ +#pragma once +#include +#include + +namespace Yc +{ + namespace Object + { + + class Room + { + public: + Room(const Json::Value &roomJson); + + int id() const; + const std::string &title() const; + int owner_id() const; + bool is_public() const; + int gender_restriction_id() const; + int min_age() const; + int max_age() const; + const std::string &password_hash() const; + bool friends_of_owner_only() const; + int required_user_right_id() const; + const std::string &created_at() const; + const std::string &updated_at() const; + int room_type_id() const; + const std::string &room_type_tr() const; + + private: + int _id = 0; + std::string _title; + int _owner_id = 0; + bool _is_public = true; + int _gender_restriction_id = 0; + int _min_age = 0; + int _max_age = 0; + std::string _password_hash; + bool _friends_of_owner_only = false; + int _required_user_right_id = 0; + std::string _created_at; + std::string _updated_at; + int _room_type_id = 0; + std::string _room_type_tr; + }; + + } // namespace Object +} // namespace Yc diff --git a/src/object/user.cpp b/src/object/user.cpp new file mode 100644 index 0000000..f1d2e0a --- /dev/null +++ b/src/object/user.cpp @@ -0,0 +1,37 @@ +#include "user.h" + +namespace Yc +{ + namespace Object + { + + User::User() = default; + + User::User(const Json::Value& userJson) { + _id = userJson.isMember("id") && !userJson["id"].isNull() ? userJson["id"].asInt() : 0; + _falukant_user_id = userJson.isMember("falukant_user_id") && !userJson["falukant_user_id"].isNull() ? userJson["falukant_user_id"].asInt() : 0; + _display_name = userJson.isMember("display_name") && !userJson["display_name"].isNull() ? userJson["display_name"].asString() : ""; + _color = userJson.isMember("color") && !userJson["color"].isNull() ? userJson["color"].asString() : "#000000"; + _show_gender = userJson.isMember("show_gender") && !userJson["show_gender"].isNull() ? userJson["show_gender"].asBool() : true; + _show_age = userJson.isMember("show_age") && !userJson["show_age"].isNull() ? userJson["show_age"].asBool() : true; + _created_at = userJson.isMember("created_at") && !userJson["created_at"].isNull() ? userJson["created_at"].asString() : ""; + _updated_at = userJson.isMember("updated_at") && !userJson["updated_at"].isNull() ? userJson["updated_at"].asString() : ""; + if (userJson.isMember("rights") && userJson["rights"].isArray()) { + for (const auto& r : userJson["rights"]) { + _rights.push_back(r.asString()); + } + } + } + + int User::id() const { return _id; } + int User::falukant_user_id() const { return _falukant_user_id; } + const std::string& User::display_name() const { return _display_name; } + const std::string& User::color() const { return _color; } + bool User::show_gender() const { return _show_gender; } + bool User::show_age() const { return _show_age; } + const std::string& User::created_at() const { return _created_at; } + const std::string& User::updated_at() const { return _updated_at; } + const std::vector& User::rights() const { return _rights; } + + } // namespace Object +} // namespace Yc diff --git a/src/object/user.h b/src/object/user.h new file mode 100644 index 0000000..06cb972 --- /dev/null +++ b/src/object/user.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include + +namespace Yc +{ + namespace Object + { + + class User { + public: + User(); + User(const Json::Value& userJson); + + int id() const; + int falukant_user_id() const; + const std::string& display_name() const; + const std::string& color() const; + bool show_gender() const; + bool show_age() const; + const std::string& created_at() const; + const std::string& updated_at() const; + const std::vector& rights() const; + + private: + int _id = 0; + int _falukant_user_id = 0; + std::string _display_name; + std::string _color = "#000000"; + bool _show_gender = true; + bool _show_age = true; + std::string _created_at; + std::string _updated_at; + std::vector _rights; + }; + + } // namespace Object +} // namespace Yc diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..e69de29