From 97456d99e72e15fc9dee1f64ce41aeb6350f8630 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 5 Sep 2025 14:37:28 +0200 Subject: [PATCH] =?UTF-8?q?F=C3=BCge=20Unterst=C3=BCtzung=20f=C3=BCr=20Tok?= =?UTF-8?q?en=20in=20der=20Benutzeranmeldung=20im=20ChatRoom=20hinzu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implementiere eine neue Methode `addUser`, die einen Token als Parameter akzeptiert, um die Benutzeranmeldung über WebSockets zu verbessern. - Aktualisiere den Konstruktor von `ChatUser`, um den Token zu verarbeiten und sicherzustellen, dass Benutzer korrekt initialisiert werden. - Ergänze Debug-Ausgaben, um den Ablauf beim Hinzufügen von Benutzern und beim Senden von Nachrichten zu protokollieren, um die Nachverfolgbarkeit zu erhöhen. --- src/core/chat_room.cpp | 68 ++++++++++++++++++++++++++++++++ src/core/chat_room.h | 1 + src/core/chat_user.cpp | 86 +++++++++++++++++++++++++++++++++++++++-- src/core/chat_user.h | 1 + src/core/ssl_server.cpp | 5 ++- 5 files changed, 156 insertions(+), 5 deletions(-) diff --git a/src/core/chat_room.cpp b/src/core/chat_room.cpp index a4489c3..b5c2e61 100755 --- a/src/core/chat_room.cpp +++ b/src/core/chat_room.cpp @@ -243,6 +243,74 @@ namespace Yc return true; } + bool ChatRoom::addUser(std::string _userName, std::string color, std::string _password, void* wsi, std::string token) + { + if (_password != "" && _password == _password && std::find(std::begin(_allowedUsers), std::end(_allowedUsers), _userName) == std::end(_allowedUsers)) + { + return false; + } + std::shared_ptr newUser; + if (_database) { + // Verwende den neuen WebSocket-Konstruktor mit Token + newUser = std::make_shared(shared_from_this(), _userName, color, wsi, _database, token); + } else { + // Fallback: WebSocket ohne Datenbank nicht unterstützt + return false; + } + _users.push_back(newUser); + + // Sende zuerst alle wichtigen Nachrichten, bevor der checkerTask Thread startet + #ifdef YC_DEBUG + std::cout << "[Debug] addUser(WebSocket with token): Starting message sequence for user: " << newUser->name() << std::endl; + #endif + + if (_parent) { + Json::Value roomList = _parent->jsonRoomList(); + #ifdef YC_DEBUG + std::cout << "[Debug] addUser(WebSocket with token): Sending roomList to user: " << newUser->name() << std::endl; + #endif + newUser->sendMsg(ChatUser::roomList, roomList, "", ""); + } + + // Kurze Pause, damit der WebSocket-Handshake vollständig abgeschlossen ist + #ifdef YC_DEBUG + std::cout << "[Debug] addUser(WebSocket with token): Waiting 100ms for WebSocket handshake..." << std::endl; + #endif + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Sende aktuelle Userliste an den neuen User + Json::Value currentUserList = userList(); + #ifdef YC_DEBUG + std::cout << "[Debug] addUser(WebSocket with token): Sending userListe to user: " << newUser->name() << std::endl; + #endif + newUser->sendMsg(ChatUser::userListe, currentUserList, "", ""); + + // Sende aktualisierte Userliste an alle anderen User im Raum + for (auto &existingUser : _users) { + if (existingUser != newUser) { + #ifdef YC_DEBUG + std::cout << "[Debug] addUser(WebSocket with token): Sending userListe to existing user: " << existingUser->name() << std::endl; + #endif + existingUser->sendMsg(ChatUser::userListe, currentUserList, "", ""); + } + } + + // Broadcast an andere Nutzer: Benutzer X hat den Chat betreten (mit Farbinfo) + #ifdef YC_DEBUG + std::cout << "[Debug] addUser(WebSocket with token): Sending 'user_entered_chat' message for user: " << newUser->name() << std::endl; + #endif + addMessage(ChatUser::system, "user_entered_chat", newUser->name(), newUser->color()); + + // Starte den checkerTask Thread erst nach dem Senden aller wichtigen Nachrichten + #ifdef YC_DEBUG + std::cout << "[Debug] addUser(WebSocket with token): Starting checkerTask thread for user: " << newUser->name() << std::endl; + #endif + newUser->start(); + + _initRound(); + return true; + } + bool ChatRoom::addUser(std::shared_ptr user, std::string password) { if (password == _password) diff --git a/src/core/chat_room.h b/src/core/chat_room.h index c392323..4a30ae4 100755 --- a/src/core/chat_room.h +++ b/src/core/chat_room.h @@ -43,6 +43,7 @@ namespace Yc std::string name(); bool addUser(std::string userName, std::string color, std::string password, int socket); bool addUser(std::string userName, std::string color, std::string password, void* wsi); + bool addUser(std::string userName, std::string color, std::string password, void* wsi, std::string token); bool addUser(std::shared_ptr user, std::string password); bool userNameExists(std::string userName); void removeUser(std::string _token, bool silent = false); diff --git a/src/core/chat_user.cpp b/src/core/chat_user.cpp index 86978f1..5b2da4f 100644 --- a/src/core/chat_user.cpp +++ b/src/core/chat_user.cpp @@ -42,7 +42,7 @@ namespace Yc // Fallback für SSL-Server ohne Parent _user = Yc::Object::User(Json::Value()); _token = Yc::Lib::Tools::generateRandomString(32); - sendMsg(token, _token, _name, _color); + sendMsg(ChatUser::token, _token, _name, _color); return; } auto server = _parent->getServer(); @@ -50,7 +50,7 @@ namespace Yc // Fallback wenn Server nicht verfügbar _user = Yc::Object::User(Json::Value()); _token = Yc::Lib::Tools::generateRandomString(32); - sendMsg(token, _token, _name, _color); + sendMsg(ChatUser::token, _token, _name, _color); return; } auto db = server->_database; @@ -131,7 +131,7 @@ namespace Yc // Fallback wenn keine Datenbank verfügbar _user = Yc::Object::User(Json::Value()); _token = Yc::Lib::Tools::generateRandomString(32); - sendMsg(token, _token, _name, _color); + sendMsg(ChatUser::token, _token, _name, _color); return; } auto db = database; @@ -279,6 +279,86 @@ namespace Yc // Thread-Start erfolgt jetzt explizit per start(), nicht im Konstruktor } + ChatUser::ChatUser(std::shared_ptr parent, std::string name, std::string color, void* wsi, std::shared_ptr database, std::string token) + : _parent(std::move(parent)), + _name(name), + _color(color), + _socket(-1), + _wsi(wsi), + _token(token), + _stop(false) + { + #ifdef YC_DEBUG + std::cout << "[Debug] ChatUser constructor with token: name=" << _name << ", token=" << _token << std::endl; + #endif + // Verwende die direkt übergebene Datenbank + if (!database) { + // Fallback wenn keine Datenbank verfügbar + _user = Yc::Object::User(Json::Value()); + sendMsg(ChatUser::token, _token, _name, _color); + return; + } + auto db = 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); + // Prefer DB color if available + if (_user.id() != 0 && !_user.color().empty()) { + _color = _user.color(); + } + // Beim Initial-Token direkt Name und aktuelle Farbe mitsenden, damit der Client "ich" korrekt färben kann + sendMsg(ChatUser::token, _token, _name, _color); + // Thread-Start erfolgt jetzt explizit per start(), nicht im Konstruktor + } + ChatUser::~ChatUser() { // Hinweis: Thread wird nicht im Destruktor gejoint, um Deadlocks zu vermeiden! diff --git a/src/core/chat_user.h b/src/core/chat_user.h index a0d6eee..2a733ff 100644 --- a/src/core/chat_user.h +++ b/src/core/chat_user.h @@ -37,6 +37,7 @@ namespace Yc ChatUser(std::shared_ptr parent, std::string name, std::string color, int socket); ChatUser(std::shared_ptr parent, std::string name, std::string color, int socket, std::shared_ptr database); ChatUser(std::shared_ptr parent, std::string name, std::string color, void* wsi, std::shared_ptr database); + ChatUser(std::shared_ptr parent, std::string name, std::string color, void* wsi, std::shared_ptr database, std::string token); ~ChatUser(); std::string name() const; std::string getToken() const; diff --git a/src/core/ssl_server.cpp b/src/core/ssl_server.cpp index 4288345..392c084 100644 --- a/src/core/ssl_server.cpp +++ b/src/core/ssl_server.cpp @@ -1,6 +1,7 @@ #include "ssl_server.h" #include "config.h" #include "lib/database.h" +#include "lib/tools.h" #include "chat_room.h" #include "chat_user.h" #include "lib/base.h" @@ -265,7 +266,7 @@ void SSLServer::handleWebSocketMessage(struct lws *wsi, const std::string& messa // Generate token if not provided if (token.empty()) { - token = Base::generateToken(); + token = Yc::Lib::Tools::generateRandomString(32); } // Store user data in connections map instead @@ -300,7 +301,7 @@ void SSLServer::handleWebSocketMessage(struct lws *wsi, const std::string& messa std::cout << "[Debug] Attempting to add user '" << name << "' to room '" << room << "' with WebSocket wsi pointer" << std::endl; #endif - if (roomObj->addUser(name, color, password, wsi)) { + if (roomObj->addUser(name, color, password, wsi, token)) { std::cout << "[YourChat] Successfully added user '" << name << "' to room '" << room << "'" << std::endl; // Find the created ChatUser auto chatUser = roomObj->findUserByName(name);