Update CMake configuration and refactor code to use smart pointers for memory management

This commit is contained in:
Torsten Schulz
2025-08-11 11:15:54 +02:00
parent ba6b788075
commit f44d780537
10 changed files with 110 additions and 77 deletions

7
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": []
}

28
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,28 @@
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: gcc-13 build active file",
"command": "/usr/bin/gcc-13",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
project(YourChat VERSION 0.1)
set(CMAKE_CXX_STANDARD 20)
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)

View File

@@ -3,8 +3,8 @@
// main function
int main(int, char **) {
Yc::Lib::Config *config = new Yc::Lib::Config();
Yc::Lib::Server server(config);
server.run();
auto config = std::make_shared<Yc::Lib::Config>();
auto server = std::make_shared<Yc::Lib::Server>(config);
server->run();
return 0;
}

View File

@@ -12,11 +12,11 @@
namespace Yc {
namespace Lib {
Room::Room(Server *parent, Json::Value roomParams) :
_parent(parent),
_blocked(false),
_stop(false),
_roundRunning(false) {
Room::Room(std::shared_ptr<Server> parent, Json::Value roomParams) :
_parent(std::move(parent)),
_blocked(false),
_stop(false),
_roundRunning(false) {
_name = roomParams["name"].asString();
_password = roomParams["password"].asString();
std::vector<std::string> allowedUsers;
@@ -26,12 +26,10 @@ namespace Yc {
_type = (RoomType)roomParams["type"].asInt();
_roundLength = roomParams["roundlength"].asInt();
_lastRoundEnd = std::time(NULL);
thread = new std::thread(&Room::run, this);
thread = std::make_unique<std::thread>(&Room::run, this);
}
Room::~Room() {
delete thread;
}
Room::~Room() = default;
void Room::run() {
while (!_stop) {
@@ -57,7 +55,7 @@ namespace Yc {
if (_password != "" && _password == _password && std::find(std::begin(_allowedUsers), std::end(_allowedUsers), _userName) == std::end(_allowedUsers)) {
return false;
}
User *newUser = new User(this, _userName, color, socket);
auto newUser = std::make_shared<User>(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());
@@ -65,10 +63,10 @@ namespace Yc {
return true;
}
bool Room::addUser(User *user, std::string password) {
bool Room::addUser(std::shared_ptr<User> user, std::string password) {
if (password == _password) {
_users.push_back(user);
user->setParent(this);
user->setParent(shared_from_this());
_initRound();
return true;
}
@@ -76,7 +74,7 @@ namespace Yc {
}
bool Room::userNameExists(std::string userName) {
for (auto &user: _users) {
for (const auto &user: _users) {
if (user->name() == userName) {
return true;
}
@@ -85,24 +83,24 @@ namespace Yc {
}
void Room::removeUser(std::string _token, bool silent) {
for (std::vector<User*>::iterator user = _users.begin(); user != _users.end(); ++user) {
if ((*user)->validateToken(_token)) {
_users.erase(user);
for (auto it = _users.begin(); it != _users.end(); ++it) {
if ((*it)->validateToken(_token)) {
if (!silent) {
addMessage(User::system, "room_exit", (*user)->name(), (*user)->color());
addMessage(User::system, "room_exit", (*it)->name(), (*it)->color());
}
_users.erase(it);
break;
}
}
}
void Room::removeUser(User *userToRemove, bool silent) {
for (std::vector<User*>::iterator user = _users.begin(); user != _users.end(); ++user) {
if (*user == userToRemove) {
_users.erase(user);
void Room::removeUser(std::shared_ptr<User> userToRemove, bool silent) {
for (auto it = _users.begin(); it != _users.end(); ++it) {
if (*it == userToRemove) {
if (!silent) {
addMessage(User::system, "room_exit", (*user)->name(), (*user)->color());
addMessage(User::system, "room_exit", (*it)->name(), (*it)->color());
}
_users.erase(it);
break;
}
}
@@ -129,15 +127,15 @@ namespace Yc {
addMessage(type, getJsonString(messageText), userName, color);
}
void Room::addUserWhenQueueEmpty(User *user) {
void Room::addUserWhenQueueEmpty(std::shared_ptr<User> user) {
while (_msgQueue.size() > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
_users.push_back(user);
user->setParent(this);
user->setParent(shared_from_this());
}
bool Room::userToNewRoom(User *user, std::string newRoom, std::string password) {
bool Room::userToNewRoom(std::shared_ptr<User> user, std::string newRoom, std::string password) {
return _parent->changeRoom(user, newRoom, password);
}
@@ -171,7 +169,7 @@ namespace Yc {
return (_roundRunning || (_type & rounds) == rounds) && (_type & dice) == dice;
}
unsigned int Room::addDice(User *user, int diceValue) {
unsigned int Room::addDice(std::shared_ptr<User> user, int diceValue) {
if (!canDice()) {
return 1;
}
@@ -183,7 +181,6 @@ namespace Yc {
_diceValues.push_back(std::make_pair(user, diceValue));
addMessage(User::dice, std::to_string(diceValue), user->name(), user->color());
return 0;
}
bool Room::accessAllowed(std::string userName, std::string password) {
@@ -223,13 +220,13 @@ namespace Yc {
}
void Room::_showDiceRoundResults() {
std::sort(_diceValues.begin(), _diceValues.end(), [=](std::pair<User*, int> val1, std::pair<User*, int> val2) {
std::sort(_diceValues.begin(), _diceValues.end(), [=](const std::pair<std::shared_ptr<User>, int>& val1, const std::pair<std::shared_ptr<User>, 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;
entry["name"] = user.first->name();
entry["value"] = user.second;
userList.append(entry);
}

22
room.h
View File

@@ -16,7 +16,7 @@ namespace Yc {
class Server;
class Room: public Base {
class Room: public Base, public std::enable_shared_from_this<Room> {
public:
enum RoomType {
none = 0,
@@ -26,15 +26,15 @@ namespace Yc {
password = 8
};
Room(Server *parent, Json::Value roomParams);
Room(std::shared_ptr<Server> parent, Json::Value roomParams);
~Room();
void run();
std::string name();
bool addUser(std::string userName, std::string color, std::string password, int socket);
bool addUser(User *user, std::string password);
bool addUser(std::shared_ptr<User> user, std::string password);
bool userNameExists(std::string userName);
void removeUser(std::string _token, bool silent = false);
void removeUser(User *user, bool silent = false);
void removeUser(std::shared_ptr<User> 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 = "");
@@ -42,11 +42,11 @@ namespace Yc {
RoomType type();
bool isType(RoomType type);
bool canDice();
unsigned int addDice(User *user, int diceValue);
unsigned int addDice(std::shared_ptr<User> user, int diceValue);
bool accessAllowed(std::string userName, std::string password);
bool userIsInRoom(std::string userName);
void addUserWhenQueueEmpty(User *user);
bool userToNewRoom(User *user, std::string newRoom, std::string password);
void addUserWhenQueueEmpty(std::shared_ptr<User> user);
bool userToNewRoom(std::shared_ptr<User> user, std::string newRoom, std::string password);
unsigned int flags();
Json::Value userList();
private:
@@ -57,21 +57,21 @@ namespace Yc {
std::string color;
};
Server *_parent;
std::shared_ptr<Server> _parent;
std::string _name;
std::string _password;
std::vector<std::string> _allowedUsers;
RoomType _type;
std::vector<User*> _users;
std::vector<std::shared_ptr<User>> _users;
bool _blocked;
bool _stop;
std::queue<Message> _msgQueue;
std::thread *thread;
std::unique_ptr<std::thread> thread;
bool _roundRunning;
time_t _roundStart;
time_t _lastRoundEnd;
int _roundLength;
std::vector<std::pair<User *, int>> _diceValues;
std::vector<std::pair<std::shared_ptr<User>, int>> _diceValues;
void _handleDice();
void _startDiceRound();
void _endDiceRound();

View File

@@ -15,9 +15,9 @@
namespace Yc {
namespace Lib {
Server::Server(Yc::Lib::Config *config) :
_config(config),
_stop(false) {
Server::Server(std::shared_ptr<Yc::Lib::Config> config) :
_config(std::move(config)),
_stop(false) {
struct sockaddr_in serverAddr;
int opt = true;
_socket = socket(AF_INET, SOCK_STREAM, 0);
@@ -31,7 +31,7 @@ namespace Yc {
std::cout << "bind not possible" << std::endl;
exit(-1);
}
createRooms(config->group("rooms"));
createRooms(_config->group("rooms"));
}
void Server::run() {
@@ -49,14 +49,14 @@ namespace Yc {
FD_ZERO(&fd);
FD_SET(_socket, &fd);
if (select(_maxSd + 1, &fd, NULL, NULL, &tv) > 0) {
std::async(std::launch::async, &Server::handleRequest, this);
std::thread(&Server::handleRequest, this).detach();
}
}
}
std::vector<std::string> Server::roomList() {
std::vector<std::string> list;
for (auto &room: _rooms) {
for (const auto &room: _rooms) {
list.push_back(room->name());
}
return list;
@@ -82,7 +82,7 @@ namespace Yc {
return false;
}
bool Server::changeRoom(User *user, std::string newRoom, std::string password) {
bool Server::changeRoom(std::shared_ptr<User> user, std::string newRoom, std::string password) {
if (!roomAllowed(newRoom, user->name(), password)) {
return false;
}
@@ -113,8 +113,9 @@ namespace Yc {
}
void Server::createRooms(Json::Value roomList) {
auto self = shared_from_this();
for (auto &room: roomList) {
Room *newRoom = new Room(this, room);
auto newRoom = std::make_shared<Room>(self, room);
_rooms.push_back(newRoom);
}
}
@@ -143,7 +144,7 @@ namespace Yc {
}
bool Server::userExists(std::string userName) {
for (auto &room: _rooms) {
for (const auto &room: _rooms) {
if (room->userNameExists(userName)) {
return true;
}
@@ -160,10 +161,10 @@ namespace Yc {
close(userSocket);
return;
}
std::string room = data["room"].asString();
std::string roomName = data["room"].asString();
bool added(false);
for (auto &room: _rooms) {
if (room->name() == data["room"].asString()) {
if (room->name() == roomName) {
if (room->addUser(data["name"].asString(), data["color"].asString(), data["password"].asString(), userSocket)) {
added = true;
break;

View File

@@ -10,20 +10,20 @@
namespace Yc {
namespace Lib {
class Server: public Base
class Server: public Base, public std::enable_shared_from_this<Server>
{
public:
Server(Yc::Lib::Config *config);
Server(std::shared_ptr<Yc::Lib::Config> config);
void run();
std::vector<std::string> roomList();
Json::Value jsonRoomList();
bool roomAllowed(std::string roomName, std::string userName, std::string password);
bool changeRoom(User *user, std::string newRoom, std::string password);
bool changeRoom(std::shared_ptr<User> user, std::string newRoom, std::string password);
private:
int _socket;
Yc::Lib::Config *_config;
std::shared_ptr<Yc::Lib::Config> _config;
bool _stop;
std::vector<Yc::Lib::Room*> _rooms;
std::vector<std::shared_ptr<Yc::Lib::Room>> _rooms;
void createRooms(Json::Value roomList);
void handleRequest();
void inputSwitcher(int userSocket, std::string input);

View File

@@ -14,15 +14,15 @@
namespace Yc {
namespace Lib {
User::User(Room *parent, std::string name, std::string color, int socket) :
_parent(parent),
_name(name),
_color(color),
User::User(std::shared_ptr<Room> 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 = new std::thread(&User::checkerTask, this);
thread = std::make_unique<std::thread>(&User::checkerTask, this);
}
User::~User() {
@@ -37,8 +37,8 @@ namespace Yc {
return (token == _token);
}
bool User::isUser(User *toValidate) {
return (toValidate == this);
bool User::isUser(std::shared_ptr<User> toValidate) {
return (toValidate.get() == this);
}
void User::sendMsg(MsgType type, const char *message, std::string userName, std::string color) {
@@ -94,8 +94,8 @@ namespace Yc {
return _color;
}
void User::setParent(Room *parent) {
_parent = parent;
void User::setParent(std::shared_ptr<Room> parent) {
_parent = std::move(parent);
}
void User::send(std::string out) {
@@ -151,7 +151,7 @@ namespace Yc {
}
void User::doDice() {
switch (_parent->addDice(this, (rand() % 6) + 1)) {
switch (_parent->addDice(shared_from_this(), (rand() % 6) + 1)) {
case 1:
sendMsg(system, "dice_not_possible", "", "");
break;
@@ -164,7 +164,7 @@ namespace Yc {
}
void User::changeRoom(std::string newRoom, std::string password) {
if (!_parent->userToNewRoom(this, newRoom, password)) {
if (!_parent->userToNewRoom(shared_from_this(), newRoom, password)) {
sendMsg(User::system, "room_not_possible", "", "");
}
}

12
user.h
View File

@@ -11,7 +11,7 @@ namespace Yc {
class Room;
class User: public Base {
class User: public Base, public std::enable_shared_from_this<User> {
public:
enum MsgType {
error = -1,
@@ -26,26 +26,26 @@ namespace Yc {
result = 9
};
User(Room *parent, std::string name, std::string color, int socket);
User(std::shared_ptr<Room> parent, std::string name, std::string color, int socket);
~User();
std::string name() const;
bool validateToken(std::string token);
bool isUser(User *toValidate);
bool isUser(std::shared_ptr<User> 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(Room *parent);
void setParent(std::shared_ptr<Room> parent);
private:
Room *_parent;
std::shared_ptr<Room> _parent;
std::string _name;
std::string _color;
int _socket;
std::string _token;
bool _stop;
std::thread *thread;
std::unique_ptr<std::thread> thread;
void send(std::string out);
void send(Json::Value out);
void handleMessage(std::string message);