Update CMake configuration and refactor code to use smart pointers for memory management
This commit is contained in:
7
.vscode/launch.json
vendored
Normal file
7
.vscode/launch.json
vendored
Normal 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
28
.vscode/tasks.json
vendored
Normal 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"
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
6
main.cpp
6
main.cpp
@@ -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;
|
||||
}
|
||||
|
||||
55
room.cpp
55
room.cpp
@@ -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
22
room.h
@@ -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();
|
||||
|
||||
23
server.cpp
23
server.cpp
@@ -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;
|
||||
|
||||
10
server.h
10
server.h
@@ -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);
|
||||
|
||||
22
user.cpp
22
user.cpp
@@ -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
12
user.h
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user