diff --git a/Makefile b/Makefile index 48edd22..adde70c 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,14 @@ -# **************************************************************************** # +#******************************************************************************# # # # ::: :::::::: # # Makefile :+: :+: :+: # # +:+ +:+ +:+ # -# By: sben-tay +#+ +:+ +#+ # +# By: omoudni +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2025/05/02 15:40:00 by rparodi #+# #+# # # Updated: 2025/05/24 16:48:43 by rparodi ### ########.fr # # # -# **************************************************************************** # +#******************************************************************************# # Name @@ -85,30 +85,37 @@ debug: CXXFLAGS += -g # debug: CXXFLAGS += -fsanitize=address debug: re +PORT ?= 4243 + test: debug - @printf '$(GREY) now running with\n\t- Port:\t\t$(GREEN)4243$(GREY)\n\t- Password:\t$(GREEN)irc$(END)\n' + @printf '$(GREY) now running with\n\t- Port:\t\t$(GREEN)$(PORT)$(GREY)\n\t- Password:\t$(GREEN)irc$(END)\n' @if tmux has-session -t $(SESSION) 2>/dev/null; then \ tmux kill-session -t $(SESSION); \ fi @tmux new-session -d -s $(SESSION) \ - 'bash -lc "./$(NAME) 4243 irc; exec bash"' + 'bash -lc "./$(NAME) $(PORT) irc; exec bash"' @tmux split-window -h -p 70 -t $(SESSION):0 \ - 'bash -lc "irssi -c localhost -p 4243 -w irc || exec yes \"irssi exit code: $?\""' + 'bash -lc "irssi -c localhost -p $(PORT) -w irc || exec yes \"irssi exit code: $?\""' @tmux split-window -v -p 50 -t $(SESSION):0.1 \ - 'bash -lc "nc localhost 4243 || exec yes \"netcat exit code: $?\""' + 'bash -lc "nc localhost $(PORT) || exec yes \"netcat exit code: $?\""' + @tmux split-window -v -p 50 -t $(SESSION):0.2 \ + 'bash -lc "nc localhost $(PORT) || exec yes \"netcat exit code: $?\""' + @tmux split-window -v -p 50 -t $(SESSION):0.3 \ + 'bash -lc "nc localhost $(PORT) || exec yes \"netcat exit code: $?\""' @tmux attach -t $(SESSION) + run: re - @printf '$(GREY) now running with\n\t- Port:\t\t$(GREEN)4243$(GREY)\n\t- Password:\t$(GREEN)irc$(END)\n' + @printf '$(GREY) now running with\n\t- Port:\t\t$(GREEN)$(PORT)$(GREY)\n\t- Password:\t$(GREEN)irc$(END)\n' @if tmux has-session -t $(SESSION) 2>/dev/null; then \ tmux kill-session -t $(SESSION); \ fi @tmux new-session -d -s $(SESSION) \ - 'bash -lc "./$(NAME) 4243 irc; exec bash"' + 'bash -lc "./$(NAME) $(PORT) irc; exec bash"' @tmux split-window -h -p 70 -t $(SESSION):0 \ - 'bash -lc "irssi -c localhost -p 4243 -w irc || exec yes \"irssi exit code: $?\""' + 'bash -lc "irssi -c localhost -p $(PORT) -w irc || exec yes \"irssi exit code: $?\""' @tmux split-window -v -p 50 -t $(SESSION):0.1 \ - 'bash -lc "nc localhost 4243 || exec yes \"netcat exit code: $?\""' + 'bash -lc "nc localhost $(PORT) || exec yes \"netcat exit code: $?\""' @tmux attach -t $(SESSION) # Header diff --git a/diagram.puml b/diagram.puml index 9c966d4..dc9e88b 100644 --- a/diagram.puml +++ b/diagram.puml @@ -10,11 +10,13 @@ class "main()" ' ======================== class Server { - _port : int + - _serverFd : int - _password : string - - _server_fd : int - - _poll : PollManager + - _pollManager : PollManager + - _users : map + Server(port : int, password : string) + + ~Server() + start() : void + getPort() : int + showInfo() : void @@ -25,38 +27,42 @@ class Server { ' ============================ class PollManager { - _fds : vector - - _users : map - + addUser(fd : int) : void - + removeUser(fd : int) : void - + updateUser(fd : int, events : short) : void - + pollLoop(server_fd : int) : void - + readFromUser(fd : int) : void - + writeToUser(fd : int) : void + + PollManager() + + ~PollManager() + + setServerFd(fd : int) : void + + addClient(fd : short unsigned) : void + + removeClient(fd : short unsigned) : void + + updateServer(fd : short unsigned) : void + + pollLoop(server_fd : int, newClients : vector, disconnected : vector, readyClients : vector>) : void } ' ======================== ' CLASS: User ' ======================== class User { - - _fd : int - - _nickname : string - - _username : string - - _hostname : string - - _readBuffer : string - - _writeBuffer : string + - _fd : short unsigned int - _registered : bool - - + getFd() : int - + getName() : string - + setNickname(name : string) : void - + appendToReadBuffer(data : string) : void - + appendToWriteBuffer(data : string) : void - + extractFullCommand() : string + - _nickname : string + - _hostname : string + - _read_buffer : string + - _write_buffer : string + - _username : string + - _hasNick : bool + - _hasUser : bool + + + User(fd : short unsigned int) + + getFd() : short unsigned int + isReadyToSend() : bool + isRegistered() : bool + + getName() : string + + extractFullCommand() : string + + appendToReadBuffer(data : string) : void + + appendToWriteBuffer(data : string) : void + + setNickname(nickname : string) : void + + setUsername(username : string) : void + + checkRegistration() : void } - ' ======================== ' CLASS: Channel ' ======================== diff --git a/include/PollManager.hpp b/include/PollManager.hpp index 008f843..562614c 100644 --- a/include/PollManager.hpp +++ b/include/PollManager.hpp @@ -1,14 +1,14 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* PollManager.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sben-tay +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/19 19:15:13 by omoudni #+# #+# */ -/* Updated: 2025/05/20 17:22:59 by sben-tay ### ########.fr */ +/* Updated: 2025/05/22 17:30:00 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #pragma once @@ -16,19 +16,18 @@ #include #include -class PollManager { +class PollManager +{ public: - PollManager(); - ~PollManager(); + PollManager(); + ~PollManager(); - void addClient(int fd); - void removeClient(int fd); - void updateServer(int fd); - void pollLoop(int server_fd); + void setServerFd(int fd); + void addClient(short unsigned fd); + void removeClient(short unsigned fd); + void updateServer(short unsigned fd); + void pollLoop(int server_fd, std::vector &newClients, std::vector &disconnected, std::vector > &readyClients); private: - std::vector _fds; - std::map _buffers; - }; diff --git a/include/core/core.hpp b/include/core/core.hpp index a50d333..a837f41 100644 --- a/include/core/core.hpp +++ b/include/core/core.hpp @@ -1,14 +1,14 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* core.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sben-tay +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/12 14:16:03 by rparodi #+# #+# */ -/* Updated: 2025/05/20 17:23:41 by sben-tay ### ########.fr */ +/* Updated: 2025/05/21 21:18:22 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #pragma once @@ -28,8 +28,13 @@ enum e_state { CMD, MSG }; - + +// INCLUDES (not to repeat) +#include +#include +#include +#include "user.hpp" #include "PollManager.hpp" #include "color.hpp" #include "server.hpp" diff --git a/include/server.hpp b/include/server.hpp index 57a0d00..eb674d3 100644 --- a/include/server.hpp +++ b/include/server.hpp @@ -1,35 +1,36 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: rparodi +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 21:50:32 by rparodi #+# #+# */ /* Updated: 2025/05/24 16:48:04 by rparodi ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #pragma once -#include -#include "PollManager.hpp" -#include -#include "user.hpp" -#include "channel.hpp" +#include "core.hpp" -class Server { - private: - int _port; - int _serverFd; - std::string _password; - PollManager _pollManager; - public: - Server(int port, const std::string &password); - ~Server(); - void start(); - std::list getUsersList() const; - std::list getChannelsList() const; - unsigned short int getPort() const; - void showInfo() const; +class User; +class Server +{ +private: + int _port; + int _serverFd; + std::string _password; + PollManager _pollManager; + std::map _users; + +public: + Server(int port, const std::string &password); + ~Server(); + void start(); + unsigned short int getPort() const; + std::list getUsersList() const; + std::list getChannelsList() const; + void showInfo() const; + void printUsers() const; }; diff --git a/include/user.hpp b/include/user.hpp index d62366f..866ca37 100644 --- a/include/user.hpp +++ b/include/user.hpp @@ -1,36 +1,42 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* user.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: rparodi +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/20 21:57:49 by rparodi #+# #+# */ -/* Updated: 2025/05/20 22:13:41 by rparodi ### ########.fr */ +/* Updated: 2025/05/21 21:16:56 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #pragma once -#include -#include -#include "color.hpp" +#include "core.hpp" -class User { - private: - int _fd; - bool _registered; - std::string _nickname; - std::string _hostname; - std::string _read_buffer; - std::string _write_buffer; - public: - int getFd() const; - bool isReadyToSend() const; - bool isRegistered() const; - std::string getName() const; - std::string extractFullCommand(); - void appendToReadBuffer(const std::string &data); - void appendToWriteBuffer(const std::string &data); - void setNickname(const std::string &nickname); +class User +{ +private: + short unsigned int _fd; + bool _registered; + std::string _nickname; + std::string _hostname; + std::string _read_buffer; + std::string _write_buffer; + std::string _username; + bool _hasNick; + bool _hasUser; + +public: + User(short unsigned fd); + short unsigned int getFd() const; + bool isReadyToSend() const; + bool isRegistered() const; + std::string getName() const; + std::string extractFullCommand(); + void appendToReadBuffer(const std::string &data); + void appendToWriteBuffer(const std::string &data); + void setNickname(const std::string &nickname); + void setUsername(const std::string &username); + void checkRegistration(); }; diff --git a/sources/core/PollManager.cpp b/sources/core/PollManager.cpp index 29d8485..d789bdd 100644 --- a/sources/core/PollManager.cpp +++ b/sources/core/PollManager.cpp @@ -10,72 +10,86 @@ PollManager::PollManager() {} -PollManager::~PollManager() { - for (size_t i = 0; i < _fds.size(); ++i) { - close(_fds[i].fd); - } -} - -void PollManager::pollLoop(int server_fd) { - - struct pollfd server_pollfd; - server_pollfd.fd = server_fd; - server_pollfd.events = POLLIN; - _fds.push_back(server_pollfd); - - std::cout << "Serveur prêt à accepter des connexions..." << std::endl; - - while (true) { - int poll_count = poll(&_fds[0], _fds.size(), -1); - if (poll_count == -1) { - std::cerr << "poll error\n" << std::endl; - continue; - } - for (size_t i = 0; i < _fds.size(); ++i) { - int fd = _fds[i].fd; - - if ((fd == server_fd) && (_fds[i].revents & POLLIN)) { - int client_fd = accept(server_fd, NULL, NULL); - if (client_fd == -1) { - std::cerr << "Error accept()" << std::endl; - continue; - } - addClient(client_fd); - } - else if (_fds[i].revents & POLLIN) { - char buffer[1024]; - ssize_t bytes = recv(fd, buffer, sizeof(buffer) -1, 0); - if (bytes > 0) { - buffer[bytes] = '\0'; - _buffers[fd] += buffer; - std::cout << "Client " << fd << " send : " << buffer; - } else { - std::cout << "Client " << fd << " disconected." << std::endl; - // removeClient(fd); - --i; - } - } - } +PollManager::~PollManager() +{ + for (size_t i = 0; i < _fds.size(); ++i) + { + close(_fds[i].fd); } } -void PollManager::addClient(int fd) { +void PollManager::pollLoop(int server_fd, std::vector &newClients, std::vector &disconnected, std::vector > &readyClients) +{ + int poll_count = poll(&_fds[0], _fds.size(), -1); + if (poll_count == -1) + { + std::cerr << "poll error\n" + << std::endl; + return; + } + for (size_t i = 0; i < _fds.size(); ++i) + { + short unsigned fd = _fds[i].fd; + if ((fd == server_fd) && (_fds[i].revents & POLLIN)) + { + int client_fd = accept(server_fd, NULL, NULL); + if (client_fd == -1) + { + std::cerr << "Error accept()" << std::endl; + continue; + } + addClient(client_fd); + newClients.push_back(client_fd); + } + else if (_fds[i].revents & POLLIN) + { + char buffer[1024]; + ssize_t bytes = recv(fd, buffer, sizeof(buffer) - 1, 0); + if (bytes > 0) + { + buffer[bytes] = '\0'; + readyClients.push_back(std::make_pair(fd, std::string(buffer))); + std::cout << "Received data from fd " << fd << ": " << buffer << std::endl; + std::cout << std::flush; + } + else + { + removeClient(fd); + disconnected.push_back(fd); + --i; + } + } + } + // } +} + +void PollManager::addClient(short unsigned fd) +{ struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; _fds.push_back(pfd); - _buffers[fd] = ""; - std::cout << "Client connecté (fd " << fd << ")" << std::endl; + std::cout << "Client connected (fd " << fd << ")" << std::endl; } -void PollManager::removeClient(int fd) { - for (size_t i = 0; i < _fds.size(); ++i) { - if (_fds[i].fd == fd) { +void PollManager::removeClient(short unsigned fd) +{ + for (size_t i = 0; i < _fds.size(); ++i) + { + if (_fds[i].fd == fd) + { _fds.erase(_fds.begin() + i); break; } } - _buffers.erase(fd); close(fd); - std::cout << "Client retiré (fd " << fd << ")" << std::endl; + std::cout << "Client disconnected (fd " << fd << ")" << std::endl; +} + +void PollManager::setServerFd(int fd) +{ + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + _fds.push_back(pfd); } diff --git a/sources/core/Server.cpp b/sources/core/Server.cpp index 5f0cdbd..0691c62 100644 --- a/sources/core/Server.cpp +++ b/sources/core/Server.cpp @@ -1,18 +1,19 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: sben-tay +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/05/13 11:11:07 by rparodi #+# #+# */ -/* Updated: 2025/05/21 13:03:51 by rparodi ### ########.fr */ +/* Updated: 2025/05/22 18:45:41 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ #include "color.hpp" #include "server.hpp" #include "core.hpp" +#include "PollManager.hpp" #include #include #include @@ -28,21 +29,28 @@ * * @note Thanks to check the port / password before give them to the constructor. */ -Server::Server(int port, const std::string &password) : _port(port), _password(password) { - std::cout << CLR_GREY << "Info: Server constructor called" << CLR_RESET << std::endl; +Server::Server(int port, const std::string &password) : _port(port), _password(password) +{ + std::cout << CLR_GREY << "Info: Server constructor called" << CLR_RESET << std::endl; } /** * @brief The default destructor of the Server class. */ -Server::~Server() { - std::cout << CLR_GREY << "Info: Server destructor called" << CLR_RESET << std::endl; +Server::~Server() +{ + std::cout << CLR_GREY << "Info: Server destructor called" << CLR_RESET << std::endl; + if (_serverFd != -1) + { + close(_serverFd); + } } - -void Server::start() { +void Server::start() +{ _serverFd = socket(AF_INET, SOCK_STREAM, 0); - if (_serverFd == -1) { + if (_serverFd == -1) + { std::cerr << "Erreur socket" << std::endl; return; } @@ -53,16 +61,57 @@ void Server::start() { addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(_port); - if (bind(_serverFd, (sockaddr*)&addr, sizeof(addr)) == -1 || - listen(_serverFd, 10) == -1) { + if (bind(_serverFd, (sockaddr *)&addr, sizeof(addr)) == -1 || + listen(_serverFd, 10) == -1) + { std::cerr << "Erreur bind/listen" << std::endl; close(_serverFd); return; } std::cout << "Serveur lancé sur le port " << _port << std::endl; + _pollManager.setServerFd(_serverFd); + std::vector newClients; + std::vector disconnected; + std::vector > readyClients; + while (true) + { + printUsers(); + newClients.clear(); + disconnected.clear(); + readyClients.clear(); + _pollManager.pollLoop(_serverFd, newClients, disconnected, + readyClients); + std::cout << "Poll loop finished" << std::endl; + std::cout << "New clients: " << newClients.size() << std::endl; + for (size_t i = 0; i < newClients.size(); ++i) + { + _users[newClients[i]] = new User(newClients[i]); + } + // Handle disconnected clients + for (size_t i = 0; i < disconnected.size(); ++i) + { + delete _users[disconnected[i]]; + _users.erase(disconnected[i]); + } + for (size_t i = 0; i < readyClients.size(); ++i) + { + int fd = readyClients[i].first; + const std::string &data = readyClients[i].second; + if (_users.count(fd)) + { + _users[fd]->appendToReadBuffer(data); + std::string cmd; + while (!(cmd = _users[fd]->extractFullCommand()).empty()) + { + // This prints every command/message received from any client + std::cout << "Client " << fd << " says: " << cmd << std::endl; + } + } + } - _pollManager.pollLoop(_serverFd); + // Optionally: handle server shutdown, signals, etc. + } close(_serverFd); } @@ -73,12 +122,12 @@ void Server::start() { * It is used for debug purpose. */ -void Server::showInfo() const { - std::cout << std::endl; - std::cout << CLR_BLUE << "IRCSettings:" << CLR_RESET << std::endl; - std::cout << CLR_BLUE << "\t- Port:\t\t" << CLR_GOLD << this->_port << CLR_RESET << std::endl; - std::cout << CLR_BLUE << "\t- Password:\t" << CLR_GOLD << this->_password << CLR_RESET << std::endl; - +void Server::showInfo() const +{ + std::cout << std::endl; + std::cout << CLR_BLUE << "IRCSettings:" << CLR_RESET << std::endl; + std::cout << CLR_BLUE << "\t- Port:\t\t" << CLR_GOLD << this->_port << CLR_RESET << std::endl; + std::cout << CLR_BLUE << "\t- Password:\t" << CLR_GOLD << this->_password << CLR_RESET << std::endl; } /** @@ -86,7 +135,14 @@ void Server::showInfo() const { * * @return the port of the server */ -unsigned short int Server::getPort() const { - return this->_port; -} +unsigned short int Server::getPort() const { return this->_port; } +void Server::printUsers() const +{ + std::cout << "Connected users:" << std::endl; + for (std::map::const_iterator it = _users.begin(); it != _users.end(); ++it) + { + std::cout << "User fd: " << it->first << std::endl; + std::cout << "Nickname: " << it->second->getNickname() << std::endl; + } +} diff --git a/sources/user/user.cpp b/sources/user/user.cpp index ed1f862..a47b20f 100644 --- a/sources/user/user.cpp +++ b/sources/user/user.cpp @@ -1,24 +1,24 @@ -/* ************************************************************************** */ +/******************************************************************************/ /* */ /* ::: :::::::: */ /* user.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: rparodi +#+ +:+ +#+ */ +/* By: omoudni +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ -/* Created: 2025/05/20 22:03:36 by rparodi #+# #+# */ -/* Updated: 2025/05/20 22:15:14 by rparodi ### ########.fr */ +/* Created: 2025/05/21 20:37:12 by omoudni #+# #+# */ +/* Updated: 2025/05/22 17:13:35 by omoudni ### ########.fr */ /* */ -/* ************************************************************************** */ +/******************************************************************************/ -#include "user.hpp" +#include "core.hpp" -/** - * @brief Getter for the fd of the user - * - * @return the actual fd of the user - */ -int User::getFd() const { - return this->_fd; +// Constructor +User::User(short unsigned int fd) : _fd(fd), _registered(false), _hasNick(false), _hasUser(false) {} + +// Getter for fd +short unsigned int User::getFd() const +{ + return _fd; } /** @@ -30,47 +30,85 @@ std::string User::getName() const { return this->_nickname; } -/** - * @brief Setter for the nickname of the user (also checker) - * - * @param nickname the nickname given to set to the user - */ -void User::setNickname(const std::string &nickname) { - if (nickname.empty()) { - throw std::invalid_argument("Nickname cannot be empty"); - } else if (nickname == "anonymous") { - throw std::invalid_argument("Nickname cannot be 'anonymous'"); - } else if (nickname.length() > 9) { - throw std::length_error("Nickname is too long"); - } else if (nickname == this->_nickname) { - throw std::invalid_argument("The nickname is the same"); - } else { - this->_nickname = nickname; - } +void User::setUsername(const std::string &username) +{ + _username = username; + _hasUser = true; + checkRegistration(); } -/** - * @brief Getter for the state of the user - * - * @return true if the user is registered, false otherwise - */ -bool User::isRegistered() const { - return this->_registered; +// Setter for nickname (with basic checks) +void User::setNickname(const std::string &nickname) +{ + if (nickname.empty()) + { + throw std::invalid_argument("Nickname cannot be empty"); + } + else if (nickname == "anonymous") + { + throw std::invalid_argument("Nickname cannot be 'anonymous'"); + } + else if (nickname.length() > 9) + { + throw std::length_error("Nickname is too long"); + } + else if (nickname == _nickname) + { + throw std::invalid_argument("The nickname is the same"); + } + else + { + _nickname = nickname; + _hasNick = true; + checkRegistration(); + } } -void User::appendToReadBuffer(const std::string &data) { - std::cerr << CLR_RED << "Error: Method not found (" << __FILE_NAME__ ":" << __LINE__ << ")" << CLR_RESET << std::endl; - (void)data; + +// Registration state +bool User::isRegistered() const +{ + return _registered; } -void User::appendToWriteBuffer(const std::string &data) { - std::cerr << CLR_RED << "Error: Method not found (" << __FILE_NAME__ ":" << __LINE__ << ")" << CLR_RESET << std::endl; - (void)data; + +// Append to read buffer +void User::appendToReadBuffer(const std::string &data) +{ + _read_buffer += data; } + +// Append to write buffer +void User::appendToWriteBuffer(const std::string &data) +{ + _write_buffer += data; +} + +// Check registration +void User::checkRegistration() +{ + if (!_registered && _hasNick && _hasUser) + { + _registered = true; + } +} + +// Check if the user is ready to send +bool User::isReadyToSend() const +{ + return !_write_buffer.empty(); +} + +// Extract full command from read buffer std::string User::extractFullCommand() { - std::cerr << CLR_RED << "Error: Method not found (" << __FILE_NAME__ ":" << __LINE__ << ")" << CLR_RESET << std::endl; - return nullptr; -} + std::string command; + size_t pos = _read_buffer.find("\r\n"); + if (pos == std::string::npos) + pos = _read_buffer.find("\n"); // fallback -bool User::isReadyToSend() const { - std::cerr << CLR_RED << "Error: Method not found (" << __FILE_NAME__ ":" << __LINE__ << ")" << CLR_RESET << std::endl; - return (false); + if (pos != std::string::npos) { + command = _read_buffer.substr(0, pos); + _read_buffer.erase(0, pos + 1); + if (_read_buffer[pos] == '\r') // clean up stray \r + _read_buffer.erase(0, 1); + } + return command; }