diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..515c81b --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/g++", + "cStandard": "c11", + "cppStandard": "c++23", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c7887e5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,78 @@ +{ + "files.associations": { + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "format": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "queue": "cpp", + "ranges": "cpp", + "semaphore": "cpp", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "stdfloat": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "text_encoding": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "variant": "cpp" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b55313..8908fd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,5 +5,6 @@ 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 room.cpp tools.cpp user.cpp) -target_link_libraries(yourchat jsoncpp pthread) + add_executable(yourchat main.cpp base.cpp config.cpp server.cpp room.cpp tools.cpp chat_user.cpp database.cpp) + # Removed chatroom.cpp, chatuser.cpp, chatroom.h, chatuser.h from the build + target_link_libraries(yourchat jsoncpp pthread pqxx) diff --git a/chat_user.cpp b/chat_user.cpp new file mode 100644 index 0000000..c1a13bd --- /dev/null +++ b/chat_user.cpp @@ -0,0 +1,175 @@ +// entfernt: #include "user.h" + +#include "chat_user.h" +#include +#include +#include +#include +#include +#include "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 new file mode 100644 index 0000000..d937da6 --- /dev/null +++ b/chat_user.h @@ -0,0 +1,68 @@ +#ifndef YC_LIB_CHAT_USER_H +#define YC_LIB_CHAT_USER_H + + +#include +#include +#include +#include +#include + + +#include "base.h" +// Forward declaration to break cyclic dependency +namespace Yc { namespace Lib { class Room; } } + +namespace Yc { +namespace Lib { + +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/database.cpp b/database.cpp new file mode 100644 index 0000000..ac5a52d --- /dev/null +++ b/database.cpp @@ -0,0 +1,42 @@ +#include "database.h" +#include +#include + +namespace Yc { +namespace Lib { + +Database::Database(std::shared_ptr config) +{ + // Hole Verbindungsdaten aus der Config + std::string dbname = config->value("database", "database").asString(); + std::string user = config->value("database", "user").asString(); + std::string password = config->value("database", "password").asString(); + std::string host = config->value("database", "host").asString(); + + std::string conninfo = + "dbname=" + dbname + + " user=" + user + + " password=" + password + + " host=" + host; + + try { + _connection = std::make_unique(conninfo); + if (!_connection->is_open()) { + throw std::runtime_error("Failed to open database connection"); + } + } catch (const std::exception& e) { + throw std::runtime_error(std::string("Database connection error: ") + e.what()); + } +} + +// Beispielmethode für eine Abfrage +pqxx::result Database::exec(const std::string& query) +{ + pqxx::work txn(*_connection); + pqxx::result r = txn.exec(query); + txn.commit(); + return r; +} + +} // namespace Lib +} // namespace Yc diff --git a/database.h b/database.h new file mode 100644 index 0000000..9a2a5cf --- /dev/null +++ b/database.h @@ -0,0 +1,23 @@ +#ifndef YC_LIB_DATABASE_H +#define YC_LIB_DATABASE_H + +#include +#include +#include "config.h" + +namespace Yc { +namespace Lib { + +class Database { +public: + Database(std::shared_ptr config); + ~Database() = default; + pqxx::result exec(const std::string& query); +private: + std::unique_ptr _connection; +}; + +} // namespace Lib +} // namespace Yc + +#endif // YC_LIB_DATABASE_H diff --git a/db_example.cpp b/db_example.cpp new file mode 100644 index 0000000..f1165d0 --- /dev/null +++ b/db_example.cpp @@ -0,0 +1,17 @@ +#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/main.cpp b/main.cpp index 9aa4382..2275449 100755 --- a/main.cpp +++ b/main.cpp @@ -1,10 +1,13 @@ + #include "config.h" #include "server.h" +#include "database.h" // main function int main(int, char **) { auto config = std::make_shared(); - auto server = std::make_shared(config); + auto database = std::make_shared(config); + auto server = std::make_shared(config, database); server->createRooms(config->group("rooms")); server->run(); return 0; diff --git a/room.cpp b/room.cpp index 8d64b39..677a24c 100755 --- a/room.cpp +++ b/room.cpp @@ -55,15 +55,15 @@ namespace Yc { 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); + auto newUser = std::make_shared(shared_from_this(), _userName, color, socket); _users.push_back(newUser); - newUser->sendMsg(User::roomList, _parent->jsonRoomList(), "", ""); - addMessage(User::system, "room_entered", newUser->name(), newUser->color()); + newUser->sendMsg(ChatUser::roomList, _parent->jsonRoomList(), "", ""); + addMessage(ChatUser::system, "room_entered", newUser->name(), newUser->color()); _initRound(); return true; } - bool Room::addUser(std::shared_ptr user, std::string password) { + bool Room::addUser(std::shared_ptr user, std::string password) { if (password == _password) { _users.push_back(user); user->setParent(shared_from_this()); @@ -86,7 +86,7 @@ namespace Yc { for (auto it = _users.begin(); it != _users.end(); ++it) { if ((*it)->validateToken(_token)) { if (!silent) { - addMessage(User::system, "room_exit", (*it)->name(), (*it)->color()); + addMessage(ChatUser::system, (*it)->name(), (*it)->color()); } _users.erase(it); break; @@ -94,11 +94,11 @@ namespace Yc { } } - void Room::removeUser(std::shared_ptr userToRemove, bool silent) { + void Room::removeUser(std::shared_ptr userToRemove, bool silent) { for (auto it = _users.begin(); it != _users.end(); ++it) { if (*it == userToRemove) { if (!silent) { - addMessage(User::system, "room_exit", (*it)->name(), (*it)->color()); + addMessage(ChatUser::system, (*it)->name(), (*it)->color()); } _users.erase(it); break; @@ -110,11 +110,11 @@ namespace Yc { _stop = true; } - void Room::addMessage(User::MsgType type, const char *messageText, std::string userName, std::string color) { + void Room::addMessage(ChatUser::MsgType type, const char *messageText, std::string userName, std::string color) { addMessage(type, (std::string)messageText, userName, color); } - void Room::addMessage(User::MsgType type, std::string messageText, std::string userName, std::string color) { + void Room::addMessage(ChatUser::MsgType type, std::string messageText, std::string userName, std::string color) { Message message; message.type = type; message.messageTr = messageText; @@ -123,11 +123,11 @@ namespace Yc { _msgQueue.push(message); } - void Room::addMessage(User::MsgType type, Json::Value messageText, std::string userName, std::string color) { + void Room::addMessage(ChatUser::MsgType type, Json::Value messageText, std::string userName, std::string color) { addMessage(type, getJsonString(messageText), userName, color); } - void Room::addUserWhenQueueEmpty(std::shared_ptr user) { + void Room::addUserWhenQueueEmpty(std::shared_ptr user) { while (_msgQueue.size() > 0) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } @@ -135,7 +135,7 @@ namespace Yc { user->setParent(shared_from_this()); } - bool Room::userToNewRoom(std::shared_ptr user, std::string newRoom, std::string password) { + bool Room::userToNewRoom(std::shared_ptr user, std::string newRoom, std::string password) { return _parent->changeRoom(user, newRoom, password); } @@ -169,7 +169,7 @@ namespace Yc { return (_roundRunning || (_type & rounds) == rounds) && (_type & dice) == dice; } - unsigned int Room::addDice(std::shared_ptr user, int diceValue) { + unsigned int Room::addDice(std::shared_ptr user, int diceValue) { if (!canDice()) { return 1; } @@ -179,7 +179,7 @@ namespace Yc { } } _diceValues.push_back(std::make_pair(user, diceValue)); - addMessage(User::dice, std::to_string(diceValue), user->name(), user->color()); + addMessage(ChatUser::dice, std::to_string(diceValue), user->name(), user->color()); return 0; } @@ -201,13 +201,13 @@ namespace Yc { if (_roundRunning && (_users.size() < 2 || _roundStart + _roundLength >= time(NULL))) { _lastRoundEnd = time(NULL); _roundRunning = false; - addMessage(User::system, "round_ends"); + addMessage(ChatUser::system, "round_ends"); _showDiceRoundResults(); } else if (!_roundRunning && _lastRoundEnd <= time(NULL) - 15 && _users.size() >= 2) { _roundStart = time(NULL); _roundRunning = true; _diceValues.clear(); - addMessage(User::system, "next_round_starts_now"); + addMessage(ChatUser::system, "next_round_starts_now"); } } } @@ -215,12 +215,12 @@ namespace Yc { void Room::_initRound() { if (_users.size() == 2) { _lastRoundEnd = time(NULL); - addMessage(User::system, "next_round_starts_soon"); + addMessage(ChatUser::system, "next_round_starts_soon"); } } void Room::_showDiceRoundResults() { - std::sort(_diceValues.begin(), _diceValues.end(), [=](const std::pair, int>& val1, const std::pair, int>& val2) { + 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; @@ -230,7 +230,7 @@ namespace Yc { entry["value"] = user.second; userList.append(entry); } - addMessage(User::result, userList); + addMessage(ChatUser::result, userList); } std::string Room::name() { diff --git a/room.h b/room.h index 29944f0..4d4670b 100755 --- a/room.h +++ b/room.h @@ -1,20 +1,23 @@ #ifndef YC_LIB_ROOM_H #define YC_LIB_ROOM_H + #include #include -#include #include #include #include #include #include + #include +#include "chat_user.h" namespace Yc { namespace Lib { - class Server; + + class Server; class Room: public Base, public std::enable_shared_from_this { public: @@ -31,27 +34,27 @@ namespace Yc { void run(); std::string name(); bool addUser(std::string userName, std::string color, std::string password, int socket); - bool addUser(std::shared_ptr user, std::string password); + bool addUser(std::shared_ptr user, std::string password); bool userNameExists(std::string userName); void removeUser(std::string _token, bool silent = false); - void removeUser(std::shared_ptr user, bool silent = false); + void removeUser(std::shared_ptr user, bool silent = false); void setStop(); - void addMessage(User::MsgType type, const char* messageText, std::string userName = "", std::string color = ""); - void addMessage(User::MsgType type, std::string messageText, std::string userName = "", std::string color = ""); - void addMessage(User::MsgType type, Json::Value 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(); bool isType(RoomType type); bool canDice(); - unsigned int addDice(std::shared_ptr user, int diceValue); + unsigned int addDice(std::shared_ptr user, int diceValue); bool accessAllowed(std::string userName, std::string password); bool userIsInRoom(std::string userName); - void addUserWhenQueueEmpty(std::shared_ptr user); - bool userToNewRoom(std::shared_ptr user, std::string newRoom, std::string password); + void addUserWhenQueueEmpty(std::shared_ptr user); + bool userToNewRoom(std::shared_ptr user, std::string newRoom, std::string password); unsigned int flags(); Json::Value userList(); private: struct Message { - User::MsgType type; + ChatUser::MsgType type; std::string messageTr; std::string userName; std::string color; @@ -62,7 +65,7 @@ namespace Yc { std::string _password; std::vector _allowedUsers; RoomType _type; - std::vector> _users; + std::vector> _users; bool _blocked; bool _stop; std::queue _msgQueue; @@ -71,7 +74,7 @@ namespace Yc { time_t _roundStart; time_t _lastRoundEnd; int _roundLength; - std::vector, int>> _diceValues; + std::vector, int>> _diceValues; void _handleDice(); void _startDiceRound(); void _endDiceRound(); diff --git a/server.cpp b/server.cpp index 512210f..d40ad9f 100755 --- a/server.cpp +++ b/server.cpp @@ -15,8 +15,9 @@ namespace Yc { namespace Lib { - Server::Server(std::shared_ptr config) : + Server::Server(std::shared_ptr config, std::shared_ptr database) : _config(std::move(config)), + _database(std::move(database)), _stop(false) { struct sockaddr_in serverAddr; int opt = true; @@ -82,7 +83,7 @@ namespace Yc { return false; } - bool Server::changeRoom(std::shared_ptr user, std::string newRoom, std::string password) { + bool Server::changeRoom(std::shared_ptr user, std::string newRoom, std::string password) { if (!roomAllowed(newRoom, user->name(), password)) { return false; } @@ -96,16 +97,16 @@ namespace Yc { msg["tr"] = "room_change_to"; msg["to"] = newRoom; userMsg["from"] = room->name(); - room->addMessage(User::system, msg, user->name(), user->color()); + room->addMessage(ChatUser::system, msg, user->name(), user->color()); } } - user->sendMsg(User::system, userMsg, "", ""); + user->sendMsg(ChatUser::system, userMsg, "", ""); for (auto &room: _rooms) { if (room->name() == newRoom) { Json::Value msg = Json::objectValue; msg["tr"] = "room_change_to"; msg["from"] = userMsg["from"]; - room->addMessage(User::system, msg, user->name(), user->color()); + room->addMessage(ChatUser::system, msg, user->name(), user->color()); room->addUserWhenQueueEmpty(user); } } @@ -155,7 +156,7 @@ namespace Yc { void Server::initUser(int userSocket, Json::Value data) { if (userExists(data["name"].asString())) { Json::Value errorJson; - errorJson["type"] = User::error; + errorJson["type"] = ChatUser::error; errorJson["message"] = "loggedin"; send(userSocket, errorJson); close(userSocket); diff --git a/server.h b/server.h index 34b5d50..6ba33a8 100755 --- a/server.h +++ b/server.h @@ -2,6 +2,7 @@ #define YP_LIB_SERVER_H #include "config.h" +#include "database.h" #include #include "room.h" #include "base.h" @@ -13,15 +14,15 @@ namespace Yc { class Server: public Base, public std::enable_shared_from_this { public: - Server(std::shared_ptr config); + Server(std::shared_ptr config, std::shared_ptr database); void run(); std::vector roomList(); Json::Value jsonRoomList(); bool roomAllowed(std::string roomName, std::string userName, std::string password); - bool changeRoom(std::shared_ptr user, std::string newRoom, std::string password); - public: + bool changeRoom(std::shared_ptr user, std::string newRoom, std::string password); int _socket; std::shared_ptr _config; + std::shared_ptr _database; bool _stop; std::vector> _rooms; void createRooms(Json::Value roomList); diff --git a/user.cpp b/user.cpp index 2b675f9..bc01822 100755 --- a/user.cpp +++ b/user.cpp @@ -170,3 +170,175 @@ namespace Yc { } } // namespace Lib } // namespace Yc +#include "user.h" + +#include +#include +#include +#include +#include +#include "room.h" +#include +#include +#include +#include + +namespace Yc { + namespace Lib { + + User::User(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(&User::checkerTask, this); + } + + User::~User() { + _parent->addMessage(User::system, std::string("leaved_chat"), _name, _color); + } + + std::string User::name() const { + return _name; + } + + bool User::validateToken(std::string token) { + return (token == _token); + } + + bool User::isUser(std::shared_ptr toValidate) { + return (toValidate.get() == this); + } + + void User::sendMsg(MsgType type, const char *message, std::string userName, std::string color) { + sendMsg(type, std::string(message), userName, color); + } + + void User::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 User::sendMsg(User::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 User::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 User::stop() { + _stop = true; + } + + std::string User::color() const { + return _color; + } + + void User::setParent(std::shared_ptr parent) { + _parent = std::move(parent); + } + + void User::send(std::string out) { + Base::send(_socket, out); + } + + void User::send(Json::Value out) { + Base::send(_socket, out); + } + + void User::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(User::scream, jsonTree["message"].asString(), _name, _color); + } else if (jsonTree["type"].asString() == "do") { + _parent->addMessage(User::dosomething, jsonTree["message"].asString(), _name, _color); + } else if (jsonTree["type"].asString() == "join") { + changeRoom(jsonTree["newroom"].asString(), jsonTree["password"].asString()); + } else if (jsonTree["type"].asString() == "userlist") { + sendUserList(); + } + } + + void User::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(User::message, message, _name, _color); + } + } + + void User::sendUserList() { + Json::Value userList = _parent->userList(); + Json::Value msg = Json::objectValue; + msg["userlist"] = userList; + sendMsg(userListe, msg, "", ""); + } + + void User::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 User::changeRoom(std::string newRoom, std::string password) { + if (!_parent->userToNewRoom(shared_from_this(), newRoom, password)) { + sendMsg(User::system, "room_not_possible", "", ""); + } + } + } // namespace Lib +} // namespace Yc