From 73f70c8d882873edb61c2009e9afab96ccd18d41 Mon Sep 17 00:00:00 2001 From: jdomingu98 Date: Tue, 26 Mar 2024 16:50:56 +0100 Subject: [PATCH 1/3] feat: Applied singleton pattern to Server class --- includes/Server.hpp | 14 ++++++++--- includes/User.hpp | 4 ++-- includes/commands/ICommand.hpp | 2 +- includes/commands/JoinCommand.hpp | 3 +-- includes/commands/NickCommand.hpp | 2 +- includes/commands/PassCommand.hpp | 2 +- includes/commands/PrivateMessageCommand.hpp | 2 +- includes/commands/QuitCommand.hpp | 2 +- includes/commands/UserCommand.hpp | 2 +- includes/exceptions/ChannelException.hpp | 21 ----------------- includes/libsUtils.hpp | 14 ++++------- includes/utils.hpp | 15 ------------ src/Server.cpp | 20 ++++++++++++++++ src/User.cpp | 10 ++++---- src/commands/JoinCommand.cpp | 4 ++-- src/commands/NickCommand.cpp | 4 ++-- src/commands/PassCommand.cpp | 7 +++--- src/commands/PrivateMessageCommand.cpp | 26 ++++++++++++++++----- src/commands/QuitCommand.cpp | 4 ++-- src/commands/UserCommand.cpp | 5 ++-- src/{utils.cpp => libsUtils.cpp} | 2 +- src/main.cpp | 2 +- src/parser/PrivateMessageParser.cpp | 17 ++++++++++---- 23 files changed, 94 insertions(+), 90 deletions(-) delete mode 100644 includes/exceptions/ChannelException.hpp delete mode 100644 includes/utils.hpp rename src/{utils.cpp => libsUtils.cpp} (97%) diff --git a/includes/Server.hpp b/includes/Server.hpp index 67c3aa0..2a07464 100644 --- a/includes/Server.hpp +++ b/includes/Server.hpp @@ -38,6 +38,10 @@ class Server { std::vector _users; std::vector _channels; + static const Server *_server; + + Server(const std::string port, const std::string password); + bool isValidPort(const std::string port); void initServer(); void listenClients(); @@ -48,15 +52,19 @@ class Server { std::vector::iterator findUserByNickname(std::string nickname); public: - Server(const std::string port, const std::string password); ~Server(); + static void init(std::string port, std::string password); + static Server *getInstance() const; std::vector::iterator findChannel(std::string channelName); - void sendMessage(int clientFd, const std::string& message) const; - bool isValidPassword(const std::string& password); + //Getters User &getUserByFd(int clientFd); User &getUserByNickname(const std::string& nickname); + + //Operations + void sendMessage(int clientFd, const std::string& message) const; + bool isValidPassword(const std::string& password); bool isNicknameInUse(const std::string& nickname); bool userHasCheckedPassword(int clientFd); void removeUser(int clientFd); diff --git a/includes/User.hpp b/includes/User.hpp index 3f33aa7..b7737e4 100644 --- a/includes/User.hpp +++ b/includes/User.hpp @@ -54,10 +54,10 @@ class User { // Operations void checkPassword(); - void makeRegistration(Server &server); + void makeRegistration(); bool canRegister(); void addChannel(Channel &channel); - void sendPrivateMessageToUser(const Server &server, const User &destination, const std::string& message); + void sendPrivateMessageToUser(const User &destination, const std::string& message); }; #endif diff --git a/includes/commands/ICommand.hpp b/includes/commands/ICommand.hpp index 945c83e..250aed2 100644 --- a/includes/commands/ICommand.hpp +++ b/includes/commands/ICommand.hpp @@ -10,7 +10,7 @@ class ICommand { protected: bool _needValidate; public: - virtual void execute(Server &server, int clientFd) = 0; + virtual void execute(int clientFd) = 0; ICommand(bool needValidate) : _needValidate(needValidate) {}; }; diff --git a/includes/commands/JoinCommand.hpp b/includes/commands/JoinCommand.hpp index 8e2cc02..35db16d 100644 --- a/includes/commands/JoinCommand.hpp +++ b/includes/commands/JoinCommand.hpp @@ -8,7 +8,6 @@ # include "Server.hpp" # include "libsUtils.hpp" -# include "utils.hpp" /** * An ICommand implementation that is responsible for the binding and creation of a channel. @@ -22,7 +21,7 @@ class JoinCommand : public ICommand { JoinCommand(std::map _channels); ~JoinCommand(); - void execute(Server &server, int fd); + void execute(int clientFd); }; #endif \ No newline at end of file diff --git a/includes/commands/NickCommand.hpp b/includes/commands/NickCommand.hpp index 4ade1b7..72b46db 100644 --- a/includes/commands/NickCommand.hpp +++ b/includes/commands/NickCommand.hpp @@ -25,7 +25,7 @@ class NickCommand : public ICommand { NickCommand(const std::string& nickname); ~NickCommand(); - void execute(Server &server, int clientFd); + void execute(int clientFd); }; #endif \ No newline at end of file diff --git a/includes/commands/PassCommand.hpp b/includes/commands/PassCommand.hpp index ca4c9f9..49520ac 100644 --- a/includes/commands/PassCommand.hpp +++ b/includes/commands/PassCommand.hpp @@ -19,7 +19,7 @@ class PassCommand : public ICommand { PassCommand(const std::string& password); ~PassCommand(); - void execute(Server &server, int clientFd); + void execute(int clientFd); }; #endif \ No newline at end of file diff --git a/includes/commands/PrivateMessageCommand.hpp b/includes/commands/PrivateMessageCommand.hpp index 410a124..bc6beea 100644 --- a/includes/commands/PrivateMessageCommand.hpp +++ b/includes/commands/PrivateMessageCommand.hpp @@ -17,7 +17,7 @@ class PrivateMessageCommand : public ICommand { public: PrivateMessageCommand(std::vector receivers, std::string message); - void execute(Server &server, int fd); + void execute(int clientFd); }; #endif \ No newline at end of file diff --git a/includes/commands/QuitCommand.hpp b/includes/commands/QuitCommand.hpp index 38604f1..b55b698 100644 --- a/includes/commands/QuitCommand.hpp +++ b/includes/commands/QuitCommand.hpp @@ -19,7 +19,7 @@ class QuitCommand : public ICommand { QuitCommand(std::string msg); ~QuitCommand(); - void execute(Server &server, int clientFd); + void execute(int clientFd); }; #endif \ No newline at end of file diff --git a/includes/commands/UserCommand.hpp b/includes/commands/UserCommand.hpp index 56ec1c4..858cf3e 100644 --- a/includes/commands/UserCommand.hpp +++ b/includes/commands/UserCommand.hpp @@ -20,7 +20,7 @@ class UserCommand : public ICommand { public: UserCommand(); UserCommand(const std::string& username, const std::string& hostname, const std::string& serverName, const std::string& realName); - void execute(Server &server, int clientFd); + void execute(int clientFd); ~UserCommand(); }; diff --git a/includes/exceptions/ChannelException.hpp b/includes/exceptions/ChannelException.hpp deleted file mode 100644 index d9302b0..0000000 --- a/includes/exceptions/ChannelException.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CHANNEL_EXCEPTION_HPP -# define CHANNEL_EXCEPTION_HPP - -# include - -/** - * An exception that is thrown when a command fails to execute. - */ -class ChannelException : public std::exception { - private: - std::string _message; - public: - ChannelException(const std::string& msg) : _message(msg) {} - ~ChannelException() throw() {} - - virtual const char* what() const throw() { - return _message.c_str(); - } -}; - -#endif diff --git a/includes/libsUtils.hpp b/includes/libsUtils.hpp index f49d40d..e39b32a 100644 --- a/includes/libsUtils.hpp +++ b/includes/libsUtils.hpp @@ -8,12 +8,11 @@ # include # include # include +# include # include # include # include -# include "utils.hpp" - # include "exceptions.hpp" # include "Logger.hpp" @@ -37,13 +36,10 @@ # define RECV_EXPT "[ERROR] Unable to receive message." # define SEND_EXPT "[ERROR] Unable to send message." -# define INVALID_COMMAND "[ERROR] Invalid command sent to server socket." //??? - -# define AUTH_ERR "[ERROR] Unauthorized.\nPlease send connection password and set your nickname and username." -# define INVALID_PASSWORD "[ERROR] Password provided doesn't match server password." - # define USER_NOT_FOUND_ERR "[ERROR] User not found in list." - # define CHANNEL_ALREADY_ADDED_ERR "[ERROR] Channel already added." -# define USER_ALREADY_IN_CHANNEL_ERR "[ERROR] User already in channel." + +std::string trim(const std::string& str); +std::vector split(const std::string &s, char delim); + #endif \ No newline at end of file diff --git a/includes/utils.hpp b/includes/utils.hpp deleted file mode 100644 index 8ed8ab0..0000000 --- a/includes/utils.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef UTILS_HPP -# define UTILS_HPP - -/** - * A utility file that contains various utility functions. - */ - -# include -# include -# include - -std::string trim(const std::string& str); -std::vector split(const std::string &s, char delim); - -#endif \ No newline at end of file diff --git a/src/Server.cpp b/src/Server.cpp index 0001a54..ff41ff2 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -41,6 +41,26 @@ Server::~Server() { this->closeConnections(); } +/** + * This function aims to initialize the server. + * + * @param port The port number to listen for incoming connections. + * @param password The password to authenticate the clients. + * +*/ +void Server::init(std::string port, std::string password) { + _server = new Server(port, password); +} + +/** + * This function aims to get the instance of the server. + * + * @return The instance of the server. + */ +Server *Server::getInstance() const { + return _server; +} + /** * This function aims to close all the connections. */ diff --git a/src/User.cpp b/src/User.cpp index 9fb3a24..57868b7 100644 --- a/src/User.cpp +++ b/src/User.cpp @@ -183,10 +183,9 @@ bool User::canRegister() { /** * This function try to register the user and verify that it is the same password as on the server. * - * @param server The server where the user is trying to register. */ -void User::makeRegistration(Server &server) { - if (!server.isValidPassword(_password)) +void User::makeRegistration() { + if (!Server::getInstance().isValidPassword(_password)) throw PasswordMismatchException(); this->_registered = true; } @@ -212,12 +211,11 @@ void User::addChannel(Channel &channel) { /** * This function aims to send a private message to a user. * - * @param server The server where the user is connected. * @param destination The user who will receive the message. * @param message The message to send. */ -void User::sendPrivateMessageToUser(const Server &server, const User &destination, const std::string& message) { +void User::sendPrivateMessageToUser(const User &destination, const std::string& message) { Logger::debug("Sending private message to " + destination.getNickname() + " from " + this->getNickname() + ": " + message); std::string response = ":" + this->_nickname + " PRIVMSG " + destination.getNickname() + " :" + message; - server.sendMessage(destination.getFd(), response); + Server::getInstance().sendMessage(destination.getFd(), response); } \ No newline at end of file diff --git a/src/commands/JoinCommand.cpp b/src/commands/JoinCommand.cpp index 5fd61f0..0dfed20 100644 --- a/src/commands/JoinCommand.cpp +++ b/src/commands/JoinCommand.cpp @@ -28,11 +28,11 @@ JoinCommand::~JoinCommand() { /** * Executes the command JOIN. * - * @param server The server where the command will be executed * @param clientFd The socket file descriptor of the client * */ -void JoinCommand::execute(Server &server, int clientFd) { +void JoinCommand::execute(int clientFd) { + Server& server = Server::getInstance(); User user = server.getUserByFd(clientFd); std::vector serverChannels = server.getChannels(); diff --git a/src/commands/NickCommand.cpp b/src/commands/NickCommand.cpp index d1023b7..84a0d4e 100644 --- a/src/commands/NickCommand.cpp +++ b/src/commands/NickCommand.cpp @@ -20,7 +20,6 @@ NickCommand::~NickCommand() {} /** * Execute the command NICK. * - * @param server The server where the command will be executed * @param clientFd The socket file descriptor of the client * * @throws `NoNicknameGivenException` If the nickname is empty @@ -29,7 +28,8 @@ NickCommand::~NickCommand() {} * @throws `NicknameInUseException` If the nickname is already in use and the user is registered * */ -void NickCommand::execute(Server &server, int clientFd) { +void NickCommand::execute(int clientFd) { + Server& server = Server::getInstance(); if (this->_nickname.empty()) throw NoNicknameGivenException(); diff --git a/src/commands/PassCommand.cpp b/src/commands/PassCommand.cpp index ca9fdf0..052d6aa 100644 --- a/src/commands/PassCommand.cpp +++ b/src/commands/PassCommand.cpp @@ -20,13 +20,12 @@ PassCommand::~PassCommand() {} /** * Execute the command PASS. * - * @param server The server where the command will be executed - * @param fd The socket file descriptor of the client + * @param clientFd The socket file descriptor of the client * * @throws `AlreadyRegisteredException` If the user is already registered - * */ -void PassCommand::execute(Server &server, int clientFd) { +void PassCommand::execute(int clientFd) { + Server& server = Server::getInstance(); if (server.getUserByFd(clientFd).isRegistered()) throw AlreadyRegisteredException(); server.getUserByFd(clientFd).setPassword(_password); diff --git a/src/commands/PrivateMessageCommand.cpp b/src/commands/PrivateMessageCommand.cpp index 9fcb2dc..fb9ede9 100644 --- a/src/commands/PrivateMessageCommand.cpp +++ b/src/commands/PrivateMessageCommand.cpp @@ -1,20 +1,34 @@ #include "PrivateMessageCommand.hpp" +/** + * PrivateMessageCommand password constructor. + * + * @param receivers The users or channels that will receive the message + * @param message The message to be sent + */ PrivateMessageCommand::PrivateMessageCommand(std::vector receivers, std::string message) - : ICommand(true), _receivers(receivers), _message(message) {} + : ICommand(true), _receivers(receivers), _message(message) {} -void PrivateMessageCommand::execute(Server &server, int fd) { - User sender = server.getUserByFd(fd); +/** + * Execute the command PRIVMSG. + * + * @param clientFd The socket file descriptor of the client + * + * @throws `ServerException` no se que pasa si no se encuentra el usuario /// + */ +void PrivateMessageCommand::execute(int clientFd) { + Server& server = Server::getInstance(); + User sender = server.getUserByFd(clientFd); Logger::debug("Sending private message from " + sender.getNickname()); for (size_t i = 0; i < this->_receivers.size(); i++) { try { - User destinationUser = server.getUserByNickname(this->_receivers[i]); - sender.sendPrivateMessageToUser(server, destinationUser, this->_message); + User destinationUser = server.getUserByNickname(this->_receivers[i]); + sender.sendPrivateMessageToUser(server, destinationUser, this->_message); } catch (const ServerException &e) { // Uno de los usuarios no existe, deberiamos de cortar la ejecucion del comando? // throw NoSuchNickException(receiver); - server.sendMessage(fd, e.what()); + server.sendMessage(fd, e.what()); } } } diff --git a/src/commands/QuitCommand.cpp b/src/commands/QuitCommand.cpp index 510c232..677d705 100644 --- a/src/commands/QuitCommand.cpp +++ b/src/commands/QuitCommand.cpp @@ -20,11 +20,11 @@ QuitCommand::~QuitCommand() {} /** * Execute the command QUIT. * - * @param server The server where the command will be executed * @param clientFd The socket file descriptor of the client * */ -void QuitCommand::execute(Server &server, int clientFd) { +void QuitCommand::execute(int clientFd) { + Server& server = Server::getInstance(); if (_msg.length() == 0) { // message = user.getNickname(); //send message to all clients on channel and server diff --git a/src/commands/UserCommand.cpp b/src/commands/UserCommand.cpp index a631cf3..d3555aa 100644 --- a/src/commands/UserCommand.cpp +++ b/src/commands/UserCommand.cpp @@ -27,13 +27,12 @@ UserCommand::~UserCommand() {} /** * Execute the command USER. * - * @param server The server where the command will be executed * @param clientFd The socket file descriptor of the client * * @throws `AlreadyRegisteredException` If the user has already used the USER command - * */ -void UserCommand::execute(Server &server, int clientFd) { +void UserCommand::execute(int clientFd) { + Server& server = Server::getInstance(); User user = server.getUserByFd(clientFd); if (!user.getUsername().empty()) throw AlreadyRegisteredException(); diff --git a/src/utils.cpp b/src/libsUtils.cpp similarity index 97% rename from src/utils.cpp rename to src/libsUtils.cpp index f25cc8e..ff9d946 100644 --- a/src/utils.cpp +++ b/src/libsUtils.cpp @@ -1,4 +1,4 @@ -#include "utils.hpp" +#include "libsUtils.hpp" /** * Trims the string. Removes the leading and trailing whitespaces. diff --git a/src/main.cpp b/src/main.cpp index de1d0cd..82a3dfd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,7 +24,7 @@ int main(int argc, char **argv) { try { std::string port = std::string(argv[1]); std::string password = std::string(argv[2]); - Server server(port, password); + Server::init(port, password); } catch (ServerException& e) { std::cerr << e.what() << std::endl; } diff --git a/src/parser/PrivateMessageParser.cpp b/src/parser/PrivateMessageParser.cpp index ecd2a17..7a49a3e 100644 --- a/src/parser/PrivateMessageParser.cpp +++ b/src/parser/PrivateMessageParser.cpp @@ -1,12 +1,19 @@ #include "PrivateMessageParser.hpp" /** - * Parses the private message command. + * Parses the PRIVMSG command. * - * @param server the server - * @param fd the file descriptor - * @param message the message to parse with the following format: "PRIVMSG [, ] :" -*/ + * The format of the PRIVMSG command is as follows: + * + * Command: PRIVMSG + * Parameters: {,} + * + * @param tokens The parameters of the command. + * + * @throws `NoRecipientGivenException` if no recipient is given. + * @throws `NoTextToSendException` if no text is given. + * @return The parsed command. + */ ICommand* PrivateMessageParser::parse(const std::vector& tokens) { std::vector receivers; std::string message; From cb3bd30d05942313ba8d773ebf642934e3b440d5 Mon Sep 17 00:00:00 2001 From: jdomingu98 Date: Tue, 26 Mar 2024 17:00:35 +0100 Subject: [PATCH 2/3] fix: make it compile --- includes/Channel.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/includes/Channel.hpp b/includes/Channel.hpp index f9640ba..e3d4c13 100644 --- a/includes/Channel.hpp +++ b/includes/Channel.hpp @@ -3,8 +3,6 @@ # include "User.hpp" -# include "ChannelException.hpp" - # include "libsUtils.hpp" # define MAX_CHANNEL_NAME_LENGTH 20 From ff06e4fab0530e4ccc686753a7b3856eaf206ae6 Mon Sep 17 00:00:00 2001 From: Alejandro Ruzafa Date: Tue, 26 Mar 2024 17:40:44 +0100 Subject: [PATCH 3/3] fix: compile = true --- Makefile | 2 +- includes/Server.hpp | 6 +++--- includes/libsUtils.hpp | 3 +++ src/Server.cpp | 18 +++++++++++------- src/commands/PrivateMessageCommand.cpp | 4 ++-- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index c9a10ed..0c18194 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ PARSER_PREFIXS = Command User Pass Nick Quit PrivateMessage Join PARSER_FILES = $(addsuffix Parser, $(PARSER_PREFIXS)) PARSER_SRCS = $(addprefix $(PARSER_DIR), $(PARSER_FILES)) -FILES = main Server User Channel utils Logger +FILES = main Server User Channel libsUtils Logger SRCS_PATHS = $(addprefix $(SRC_DIR)/, $(FILES)) $(CMD_SRCS) $(PARSER_SRCS) SRCS = $(addsuffix .cpp, $(SRCS_PATHS)) diff --git a/includes/Server.hpp b/includes/Server.hpp index 2a07464..7fff2fb 100644 --- a/includes/Server.hpp +++ b/includes/Server.hpp @@ -38,8 +38,8 @@ class Server { std::vector _users; std::vector _channels; - static const Server *_server; - + // Singleton Pattern + static Server *_server; Server(const std::string port, const std::string password); bool isValidPort(const std::string port); @@ -54,7 +54,7 @@ class Server { public: ~Server(); static void init(std::string port, std::string password); - static Server *getInstance() const; + static Server &getInstance(); std::vector::iterator findChannel(std::string channelName); diff --git a/includes/libsUtils.hpp b/includes/libsUtils.hpp index e39b32a..df52849 100644 --- a/includes/libsUtils.hpp +++ b/includes/libsUtils.hpp @@ -22,6 +22,9 @@ # define SUCCESS 0 # define EXIT 1 +# define DEFAULT_PORT "6666" +# define DEFAULT_PASS "1234" + // ========================================= IRC SERVER ERROR MESSAGES ========================================= # define INVALID_ARGS "[ERROR] Invalid args.\nUsage: ./ircserv " diff --git a/src/Server.cpp b/src/Server.cpp index ff41ff2..91f15e8 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -1,5 +1,7 @@ #include "Server.hpp" +Server *Server::_server = NULL; + /** * This function aims to validate the port number. * A valid port number is between 1 and 65535. @@ -29,7 +31,6 @@ Server::Server(const std::string port, const std::string password) : _password(p throw ServerException(PORT_OUT_OF_RANGE_ERR); _port = std::atoi(port.c_str()); this->initServer(); - this->listenClients(); } /** @@ -47,9 +48,10 @@ Server::~Server() { * @param port The port number to listen for incoming connections. * @param password The password to authenticate the clients. * -*/ + */ void Server::init(std::string port, std::string password) { - _server = new Server(port, password); + Server::_server = new Server(port, password); + Server::_server->listenClients(); } /** @@ -57,8 +59,10 @@ void Server::init(std::string port, std::string password) { * * @return The instance of the server. */ -Server *Server::getInstance() const { - return _server; +Server &Server::getInstance() { + if (Server::_server == NULL) + Server::_server = new Server(DEFAULT_PORT, DEFAULT_PASS); + return *Server::_server; } /** @@ -190,7 +194,7 @@ void Server::handleExistingConnection(int clientFd) { Logger::debug("Mensaje del cliente: " + std::string(buffer, readBytes)); try { ICommand* command = CommandParser::parse(std::string(buffer, readBytes)); - command->execute(*this, clientFd); + command->execute(clientFd); } catch (IRCException& e) { std::string clientNickname = getUserByFd(clientFd).getNickname(); sendMessage(clientFd, @@ -295,7 +299,7 @@ void Server::removeUser(int fd) { * @param clientFd The file descriptor of the user. */ void Server::attemptUserRegistration(int clientFd) { - this->getUserByFd(clientFd).makeRegistration(*this); + this->getUserByFd(clientFd).makeRegistration(); } /** diff --git a/src/commands/PrivateMessageCommand.cpp b/src/commands/PrivateMessageCommand.cpp index fb9ede9..4f0ab8f 100644 --- a/src/commands/PrivateMessageCommand.cpp +++ b/src/commands/PrivateMessageCommand.cpp @@ -24,11 +24,11 @@ void PrivateMessageCommand::execute(int clientFd) { for (size_t i = 0; i < this->_receivers.size(); i++) { try { User destinationUser = server.getUserByNickname(this->_receivers[i]); - sender.sendPrivateMessageToUser(server, destinationUser, this->_message); + sender.sendPrivateMessageToUser(destinationUser, this->_message); } catch (const ServerException &e) { // Uno de los usuarios no existe, deberiamos de cortar la ejecucion del comando? // throw NoSuchNickException(receiver); - server.sendMessage(fd, e.what()); + server.sendMessage(clientFd, e.what()); } } }