From 2fba378d7e22a54fbde8e1b68f0a53f18bcf9365 Mon Sep 17 00:00:00 2001 From: romain Date: Sun, 1 Oct 2023 18:35:13 +0200 Subject: [PATCH] NITWOK: Refactor implementatin of Nitwork Add Interface and Abstract classes, with fonctionnal begin implementation of NitworkServer (receive is working) PATCH --- src/Nitwork/{Nitwork.cpp => ANitwork.cpp} | 250 ++++++---------- src/Nitwork/ANitwork.hpp | 153 ++++++++++ src/Nitwork/CMakeLists.txt | 6 +- src/Nitwork/INitwork.hpp | 81 ++++++ src/Nitwork/Nitwork.h | 4 +- src/Nitwork/Nitwork.hpp | 336 ---------------------- src/Nitwork/NitworkServer.cpp | 112 ++++++++ src/Nitwork/NitworkServer.hpp | 119 ++++++++ src/main_client.cpp | 2 +- src/main_server.cpp | 17 +- 10 files changed, 573 insertions(+), 507 deletions(-) rename src/Nitwork/{Nitwork.cpp => ANitwork.cpp} (51%) create mode 100644 src/Nitwork/ANitwork.hpp create mode 100644 src/Nitwork/INitwork.hpp delete mode 100644 src/Nitwork/Nitwork.hpp create mode 100644 src/Nitwork/NitworkServer.cpp create mode 100644 src/Nitwork/NitworkServer.hpp diff --git a/src/Nitwork/Nitwork.cpp b/src/Nitwork/ANitwork.cpp similarity index 51% rename from src/Nitwork/Nitwork.cpp rename to src/Nitwork/ANitwork.cpp index 0795d8b4..deb5acbb 100644 --- a/src/Nitwork/Nitwork.cpp +++ b/src/Nitwork/ANitwork.cpp @@ -1,40 +1,30 @@ /* ** EPITECH PROJECT, 2023 -** R-Bus +** r-type ** File description: -** Implementation of nitwork +** ANitwork */ -#include "Nitwork.hpp" - +#include "ANitwork.hpp" namespace Nitwork { - // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) - Nitwork Nitwork::_instance = Nitwork(); - // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) - - Nitwork &Nitwork::getInstance() - { - return _instance; - } + ANitwork::ANitwork() + : _socket(_context) {} - /* Start Section */ - bool Nitwork::start(int port, int threadNb, int tick) + bool ANitwork::start(int port, int threadNb, int tick) { try { startReceiveHandler(); startInputHandler(); startOutputHandler(); - if (!startServerConfig(port)) { - std::cerr << "Error: server config failed" << std::endl; + if (!startNitworkConfig(port)) { + std::cerr << "Error: Nitwork config failed" << std::endl; return false; } - if (!startServerThreads(threadNb, tick)) { - std::cerr << "Error: server threads failed" << std::endl; + if (!startNitworkThreads(threadNb, tick)) { + std::cerr << "Error: Nitwork threads failed" << std::endl; return false; } - std::cout << "Server started on port " << port << " on " - << boost::asio::ip::host_name() << " with ip " - << _endpoint.address().to_string() << std::endl; + std::cout << "Nitwork started on port " << port << std::endl; } catch (std::exception &e) { std::cerr << "Nitwork Error : " << e.what() << std::endl; return false; @@ -42,49 +32,7 @@ namespace Nitwork { return true; } - bool Nitwork::startServerConfig(int port) - { - _endpoint = - boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port); - _socket.open(boost::asio::ip::udp::v4()); - if (!_socket.is_open()) { - std::cerr << "Error: socket not open" << std::endl; - return false; - } - _socket.bind(_endpoint); - return true; - } - - bool Nitwork::startClockThread(int tick) - { - _clockThread = std::thread([this, tick]() { - while (true) { - std::this_thread::sleep_for( - std::chrono::milliseconds(ONE_SECOND / tick)); - _tickConvVar.notify_all(); - } - }); - if (!_clockThread.joinable()) { - std::cerr << "Error: clock thread not joinable" << std::endl; - return false; - } - return true; - } - - bool Nitwork::startServerThreads(int threadNb, int tick) - { - if (!startContextThreads(threadNb)) { - std::cerr << "Error: context threads failed" << std::endl; - return false; - } - if (!startClockThread(tick)) { - std::cerr << "Error: clock thread failed" << std::endl; - return false; - } - return true; - } - - bool Nitwork::startContextThreads(int threadNb) + bool ANitwork::startContextThreads(int threadNb) { std::cout << "Starting context threads" << std::endl; for (int i = 0; i < threadNb; i++) { @@ -104,67 +52,63 @@ namespace Nitwork { return true; } - void Nitwork::startInputHandler() + bool ANitwork::startClockThread(int tick) { - boost::asio::post(_context, [this]() { - std::unique_lock lockTick(_tickMutex); - - std::cout << std::endl << "Starting input handler" << std::endl; + std::cout << "Starting clock thread" << std::endl; + _clockThread = std::thread([this, tick]() { try { while (true) { - _tickConvVar.wait(lockTick); - for (auto &action : _actions) { - action.second(action.first.data, action.first.endpoint); - } - _actions.clear(); + std::this_thread::sleep_for(std::chrono::milliseconds(tick)); + std::unique_lock lockTick(_tickMutex); + _tickConvVar.notify_one(); } } catch (std::exception &e) { - std::cerr << e.what() << std::endl; + std::cerr << "Error: " << e.what() << std::endl; } }); + if (!_clockThread.joinable()) { + std::cerr << "Error: clock thread not joinable" << std::endl; + return false; + } + return true; } - void Nitwork::startOutputHandler() + bool ANitwork::startNitworkThreads(int threadNb, int tick) { - boost::asio::post(_context, [this]() { - std::unique_lock lockQueue(_outputQueueMutex); - std::unique_lock lockTick(_tickMutex); + if (!startContextThreads(threadNb)) { + std::cerr << "Error: context threads failed" << std::endl; + return false; + } + if (!startClockThread(tick)) { + std::cerr << "Error: clock thread failed" << std::endl; + return false; + } + return true; + } - std::cout << std::endl << "Starting output handler" << std::endl; - try { - while (true) { - _tickConvVar.wait(lockTick); - for (auto &data : _outputQueue) { - lockQueue.lock(); - _actionToSendHandlers[data.second.action]( - data.first, - data.second.body); - lockQueue.unlock(); - } - _outputQueue.clear(); - } - } catch (std::exception &e) { - std::cerr << e.what() << std::endl; - } - }); + void ANitwork::stop() + { + _context.stop(); + for (auto &thread : _pool) + thread.join(); + _pool.clear(); + _clockThread.join(); } - /* End Start Section */ - /* Receive Section */ - void Nitwork::startReceiveHandler() + void ANitwork::startReceiveHandler() { std::cout << "Starting receive handler" << std::endl; _socket.async_receive_from( boost::asio::buffer(_receiveBuffer), - _clientEndpoint, + _senderEndpoint, boost::bind( - &Nitwork::headerHandler, + &ANitwork::headerHandler, this, boost::asio::placeholders::bytes_transferred, boost::asio::placeholders::error)); } - void Nitwork::headerHandler( + void ANitwork::headerHandler( std::size_t bytes_received, const boost::system::error_code &error) { @@ -189,77 +133,59 @@ namespace Nitwork { } std::cout << "header received" << std::endl; for (int i = 0; i < header->nb_action; i++) { - handleBodyAction(*header, _clientEndpoint); + handleBodyAction(*header, _senderEndpoint); } } catch (std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; } } - void Nitwork::handleBodyAction( - const struct header_s header, - const boost::asio::ip::udp::endpoint &endpoint) + void ANitwork::startInputHandler() { - auto *action = reinterpret_cast( - _receiveBuffer.data() + sizeof(struct header_s)); - std::cout << "action.magick: " << action->magick << std::endl; - auto endPointIt = - std::find(_endpoints.begin(), _endpoints.end(), endpoint); - if (endPointIt == _endpoints.end() && action->magick != INIT) { - std::cerr << "Error: endpoint not found" << std::endl; - startReceiveHandler(); - return; - } - auto it = _actionsHandlers.find(action->magick); - if (it == _actionsHandlers.end()) { - std::cerr << "Error: action not found" << std::endl; - startReceiveHandler(); - return; - } - it->second.first(header, it->second.second); - startReceiveHandler(); - } - /* End Receive Section */ + boost::asio::post(_context, [this]() { + std::unique_lock lockTick(_tickMutex); - /* Stop Section */ - void Nitwork::stop() - { - _inputThread.join(); - _clockThread.join(); - _outputThread.join(); - _context.stop(); - std::cout << "Server stopped" << std::endl; + std::cout << std::endl << "Starting input handler" << std::endl; + try { + while (true) { + _tickConvVar.wait(lockTick); + for (auto &action : _actions) { + action.second(action.first.data, action.first.endpoint); + } + _actions.clear(); + } + } catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + }); } - /* End Stop Section */ - /* Handle packet (msg) Section */ - void Nitwork::handleInitMsg( - const std::any &msg, - boost::asio::ip::udp::endpoint &endpoint) + void ANitwork::startOutputHandler() { - const struct msgInit_s &initMsg = std::any_cast(msg); - - std::cout << "init" << std::endl; - if (_endpoints.size() >= MAX_CLIENTS) { - std::cerr << "Error: too many clients" << std::endl; - return; - } - auto endPointIt = - std::find(_endpoints.begin(), _endpoints.end(), endpoint); - if (endPointIt != _endpoints.end()) { - std::cerr << "Error: endpoint already init" << std::endl; - return; - } - _endpoints.emplace_back(endpoint); - } + boost::asio::post(_context, [this]() { + std::unique_lock lockQueue(_outputQueueMutex); + std::unique_lock lockTick(_tickMutex); + const std::map &actionToSendHandlers = getActionToSendHandlers(); - void Nitwork::handleReadyMsg( - const std::any &msg, - boost::asio::ip::udp::endpoint &endpoint) - { - const struct msgReady_s &readyMsg = - std::any_cast(msg); - std::cout << "ready" << std::endl; + std::cout << std::endl << "Starting output handler" << std::endl; + try { + while (true) { + _tickConvVar.wait(lockTick); + for (auto &data : _outputQueue) { + lockQueue.lock(); + auto it = actionToSendHandlers.find(data.second.action); + if (it == actionToSendHandlers.end()) { + std::cerr << "Error: action not found" << std::endl; + continue; + } + it->second(data.second.body, data.first); + lockQueue.unlock(); + } + _outputQueue.clear(); + } + } catch (std::exception &e) { + std::cerr << e.what() << std::endl; + } + }); } - /* End Handle packet (msg) Section */ } // namespace Nitwork diff --git a/src/Nitwork/ANitwork.hpp b/src/Nitwork/ANitwork.hpp new file mode 100644 index 00000000..f01a9fca --- /dev/null +++ b/src/Nitwork/ANitwork.hpp @@ -0,0 +1,153 @@ +/* +** EPITECH PROJECT, 2023 +** r-type +** File description: +** ANitwork +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "INitwork.hpp" + +namespace Nitwork { + constexpr int MAX_PACKET_SIZE = 1024; + + class ANitwork : public INitwork { + public: + ANitwork(); + virtual ~ANitwork() = default; + + // start the NitworkServer + bool start(int port, int threadNb, int tick) override; + + void stop() override; + // send data to the endpoint with the given data + template + void sendData( + std::any &rawData, + boost::asio::ip::udp::endpoint &endpoint) + { + if (rawData.type() != typeid(T)) { + std::cerr << "Error: invalid type" << std::endl; + return; + } + if (sizeof(T) > MAX_PACKET_SIZE) { + std::cerr << "Error: package too big" << std::endl; + return; + } + T data = std::any_cast(rawData); + + _socket.async_send_to( + boost::asio::buffer(&data, sizeof(T)), + endpoint, + [](const boost::system::error_code &error, + std::size_t bytes_sent) { + if (error) { + std::cerr << "Error: " << error.message() + << std::endl; + return; + } + if (bytes_sent != sizeof(T)) { + std::cerr << "Error: package not sent" << std::endl; + return; + } + }); + } + protected: + void startReceiveHandler() final; + // handler func for receive handler which handle the header + template + void handleBody( + const struct header_s &header, + const actionHandler &handler) + { + B *body = reinterpret_cast( + _receiveBuffer.data() + sizeof(struct header_s) + + sizeof(struct action_s)); + handleBodyDatas( + header, + handler, + *body, + boost::system::error_code(), + sizeof(B)); + } + private: + // start the NitworkServer threads (context threads, clock thread, input thread and output thread) + bool startNitworkThreads(int threadNb, int tick) final; + // start the context threads + bool startContextThreads(int threadNb) final; + // start the clock thread + bool startClockThread(int tick) final; + // start the input thread inside the context (post) + void startInputHandler() final; + // start the output thread inside the context (post) + void startOutputHandler() final; + // start receive handler + void headerHandler( + std::size_t bytes_received, + const boost::system::error_code &error) final; + + // handler func for receive handler which handle the action + template + void handleBodyDatas( + const struct header_s &header, + const actionHandler &handler, + B body, + const boost::system::error_code &error, + const std::size_t bytes_received) + { + if (error) { + std::cerr << "Error: " << error.message() << std::endl; + startReceiveHandler(); + return; + } + if (bytes_received != sizeof(B)) { + std::cerr << "Error: body not received" << std::endl; + startReceiveHandler(); + return; + } + std::lock_guard lock(_inputQueueMutex); + SenderData senderData(_senderEndpoint, std::any(body)); + std::cout << "adding action to queue" << std::endl; + _actions.emplace_back(senderData, handler); + std::cout << "action added to queue" << std::endl; + startReceiveHandler(); + } + + protected: + boost::asio::io_context _context; // The main context + boost::asio::ip::udp::socket _socket; // The socket which will be used to send and receive the actions + + // The buffer used to receive the actions + boost::array _receiveBuffer; // The buffer used to receive the actions + + private: + std::mutex _outputQueueMutex; // Mutex for the output queue + std::mutex _inputQueueMutex; // Mutex for the input queue + std::mutex _tickMutex; // Mutex for the tick + std::condition_variable _tickConvVar; // Condition variable for the tick + + // Threads + std::vector _pool; // The context threads pool + std::thread _clockThread; // The clock thread + + // Endpoints + boost::asio::ip::udp::endpoint _senderEndpoint; // The sender endpoint + + // Body handler vars + std::list + > _actions; // A list of actions which will be handled by the second context + std::list< + std::pair + > _outputQueue; // A queue of actions which will be sent to the clients + }; // class INitwork +} // namespace NitworkServer + diff --git a/src/Nitwork/CMakeLists.txt b/src/Nitwork/CMakeLists.txt index 2369b803..cd8a6696 100644 --- a/src/Nitwork/CMakeLists.txt +++ b/src/Nitwork/CMakeLists.txt @@ -14,11 +14,13 @@ target_include_directories( target_sources( ${PROJECT_NAME_CLIENT} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/Nitwork.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ANitwork.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/NitworkServer.cpp ) target_sources( ${PROJECT_NAME_SERVER} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/Nitwork.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ANitwork.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/NitworkServer.cpp ) diff --git a/src/Nitwork/INitwork.hpp b/src/Nitwork/INitwork.hpp new file mode 100644 index 00000000..7dd84477 --- /dev/null +++ b/src/Nitwork/INitwork.hpp @@ -0,0 +1,81 @@ +/* +** EPITECH PROJECT, 2023 +** r-type +** File description: +** INitwork +*/ + +#pragma once + +#include +#include +#include +#include + +extern "C" +{ +#include "Nitwork.h" +} + +namespace Nitwork { + typedef std::function actionHandler; + typedef std::function handleBodyT; + + class SenderData { + public: + SenderData(boost::asio::ip::udp::endpoint &endpoint, std::any data) + : endpoint(endpoint), + data(std::move(data)) + { + } + + boost::asio::ip::udp::endpoint endpoint; + std::any data; + }; + struct packet_s { + n_actionType_t action; + std::any body; + }; + class INitwork { + public: + virtual ~INitwork() = default; + + // start the NitworkServer + virtual bool start(int port, int threadNb, int tick) = 0; + + virtual void stop() = 0; + protected: + // start the NitworkServer config + virtual bool startNitworkConfig(int port) = 0; + // start the NitworkServer threads (context threads, clock thread, input thread and output thread) + virtual bool startNitworkThreads(int threadNb, int tick) = 0; + // start the context threads + virtual bool startContextThreads(int threadNb) = 0; + // start the clock thread + virtual bool startClockThread(int tick) = 0; + // start the input thread inside the context (post) + virtual void startInputHandler() = 0; + // start the output thread inside the context (post) + virtual void startOutputHandler() = 0; + + // start receive handler + virtual void startReceiveHandler() = 0; + // handler func for receive handler which handle the header + virtual void headerHandler( + std::size_t bytes_received, + const boost::system::error_code &error) = 0; + // handler func for headerHandler which handle the action + virtual void handleBodyAction( + const struct header_s header, + const boost::asio::ip::udp::endpoint &endpoint) = 0; + + // getters + virtual const std::map< + enum n_actionType_t, + actionHandler + >& getActionToSendHandlers() const = 0; + }; // class INitwork +} // namespace NitworkServer diff --git a/src/Nitwork/Nitwork.h b/src/Nitwork/Nitwork.h index 354bb86f..20d61a99 100644 --- a/src/Nitwork/Nitwork.h +++ b/src/Nitwork/Nitwork.h @@ -2,7 +2,7 @@ ** EPITECH PROJECT, 2023 ** R-Bus ** File description: -** Internal header for Nitwork C +** Internal header for NitworkServer C */ #ifndef NITWORK_H @@ -11,7 +11,9 @@ #define HEADER_SIZE sizeof(struct header_s) #define TICKS_PER_SECOND 20 #define ONE_SECOND 1000 + #define DEFAULT_THREAD_NB 4 #define MAX_NB_ACTION 16 + #define MAX_CLIENTS 4 typedef char n_magick_t; typedef int n_idsReceived_t; diff --git a/src/Nitwork/Nitwork.hpp b/src/Nitwork/Nitwork.hpp deleted file mode 100644 index e1c4576d..00000000 --- a/src/Nitwork/Nitwork.hpp +++ /dev/null @@ -1,336 +0,0 @@ -/* -** EPITECH PROJECT, 2023 -** R-Bus -** File description: -** Nitwork library, a portable network library -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" -{ -#include "Nitwork.h" -} - -namespace Nitwork { - constexpr int MAX_CLIENTS = 4; - - class ClientData { - public: - ClientData(boost::asio::ip::udp::endpoint &endpoint, std::any data) - : endpoint(endpoint), - data(std::move(data)) - { - } - - boost::asio::ip::udp::endpoint endpoint; - std::any data; - }; - struct packet_s { - n_actionType_t action; - std::any body; - }; - class Nitwork { - public: - Nitwork() : _socket(_context) - { - } - - static Nitwork &getInstance(); - - // start the server - bool start(int port, int threadNb = 4, int tick = TICKS_PER_SECOND); - - private: - // start the server config - bool startServerConfig(int port); - // start the server threads (context threads, clock thread, input - // thread and output thread) - bool startServerThreads(int threadNb, int tick); - // start the context threads - bool startContextThreads(int threadNb); - // start the clock thread - bool startClockThread(int tick); - // start the input thread inside the context (post) - void startInputHandler(); - // start the output thread inside the context (post) - void startOutputHandler(); - - // start receive handler - void startReceiveHandler(); - // handler func for receive handler which handle the header - void headerHandler( - std::size_t bytes_received, - const boost::system::error_code &error); - // handler func for headerHandler which handle the action - void handleBodyAction( - const struct header_s header, - const boost::asio::ip::udp::endpoint &endpoint); - - public: - void stop(); - - // Method which handle clock and unlock client threads each n ticks - - template - void sendDatasToEndpoint( - boost::asio::ip::udp::endpoint &endpoint, - T &datas) - { - _socket.send_to( - boost::asio::buffer(&datas, sizeof(T)), - endpoint); - } - - template - void sendDatasToAll(T &datas) - { - for (auto &endpoint : _endpoints) { - sendDatasToEndpoint(endpoint, datas); - } - } - - template - void handleBodyDatas( - const struct header_s &header, - const std::function< - void(const std::any &, boost::asio::ip::udp::endpoint &)> - &handler, - B body, - const boost::system::error_code &error, - const std::size_t bytes_received) - { - if (error) { - std::cerr << "Error: " << error.message() << std::endl; - startReceiveHandler(); - return; - } - if (bytes_received != sizeof(B)) { - std::cerr << "Error: body not received" << std::endl; - startReceiveHandler(); - return; - } - std::lock_guard lock(_inputQueueMutex); - ClientData clientData(_endpoint, std::any(body)); - std::cout << "adding action to queue" << std::endl; - _actions.emplace_back(clientData, handler); - std::cout << "action added to queue" << std::endl; - startReceiveHandler(); - } - - template - void handleBody( - const struct header_s &header, - const std::function< - void(const std::any &, boost::asio::ip::udp::endpoint &)> - &handler) - { - B *body = reinterpret_cast( - _receiveBuffer.data() + sizeof(struct header_s) - + sizeof(struct action_s)); - handleBodyDatas( - header, - handler, - *body, - boost::system::error_code(), - sizeof(B)); - } - - template - void sendDataFromQueue( - const boost::asio::ip::udp::endpoint &endpoint, - std::any &rawData) - { - T data = std::any_cast(rawData); - - _socket.async_send_to( - boost::asio::buffer(&data, sizeof(T)), - endpoint, - [](const boost::system::error_code &error, - std::size_t bytes_sent) { - if (error) { - std::cerr << "Error: " << error.message() - << std::endl; - return; - } - if (bytes_sent != sizeof(T)) { - std::cerr << "Error: package not sent" << std::endl; - return; - } - }); - } - - void handleInitMsg( - const std::any &msg, - boost::asio::ip::udp::endpoint &endpoint); - - void handleReadyMsg( - const std::any &msg, - boost::asio::ip::udp::endpoint &endpoint); - - protected: - - private: - // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) - static Nitwork _instance; - // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) - - // Main vars for the server - boost::asio::ip::udp::endpoint - _endpoint; // The endpoint which will be used to send and - // receive the actions - boost::asio::io_context _context; // The main context - boost::asio::ip::udp::socket - _socket; // The socket which will be used to send and receive - // the actions - std::list - _endpoints; // A vector of endpoints which will be used to send - // the actions to the clients and identify them - - // contexts threads, clock thread, input thread and output thread(s) - std::vector _pool; // A pool of threads which will be - // used to handle the clients - std::thread _clockThread; // A thread for the clock which is in the - // second context - std::thread _inputThread; // A thread for the input handler which is - // in the second context - std::thread _outputThread; // A thread for the output handler which - // is in the second context - - // Body handler var - std::list - &>> - _actions; // A list of actions which will be handled by the - // second context - std::list< - std::pair> - _outputQueue; // A queue of actions which will be sent to the - // clients - - // Mutex and condition variables - std::mutex _inputQueueMutex; // A mutex to lock the input queue - std::mutex _outputQueueMutex; // A mutex to lock the output queue - std::mutex - _tickMutex; // A mutex to lock the tick condition variable - std::condition_variable - _tickConvVar; // A condition variable which will be handled by - // the clock thread to unlock the clients threads - // each n ticks - - // Packets vars - struct header_s _headerPacket = { - 'N', - 0, - 0, - 0, - 0, - 'N'}; // A packet which will be used to receive the header - struct action_s _actionPacket = { - NO_ACTION}; // A packet which will be used to receive the action - struct msgInit_s _initPacket = { - 'N'}; // A packet which will be used to receive the init message - struct msgReady_s _readyPacket = { - 'N'}; // A packet which will be used to receive the ready - // message - boost::asio::ip::udp::endpoint - _clientEndpoint; // An endpoint which will be used to receive - // the actions - boost::array - _receiveBuffer; // A buffer which will be used to receive the - // actions - - // Actions ids - std::array - _ids {}; // An array of ids which will be used to identify the - // actions - - // maps that will be used to handle the actions, in order to send or - // receive them - std::map< - enum n_actionType_t, - std::pair< - std::function &)>, - std::function>> - _actionsHandlers = { - {INIT, - std::make_pair( - std::function &)>( - std::bind( - &Nitwork::handleBody, - this, std::placeholders::_1, - std::placeholders::_2)), - std::function( - std::bind( - &Nitwork::handleInitMsg, - this, std::placeholders::_1, - std::placeholders::_2)))}, - {READY, - std::make_pair( - std::function &)>( - std::bind( - &Nitwork::handleBody, - this, std::placeholders::_1, - std::placeholders::_2)), - std::function( - std::bind( - &Nitwork::handleReadyMsg, - this, std::placeholders::_1, - std::placeholders::_2)))} - }; - std::map< - enum n_actionType_t, - std::function< - void(const boost::asio::ip::udp::endpoint &, std::any &)>> - _actionToSendHandlers = { - {INIT, - std::function( - std::bind( - &Nitwork::sendDataFromQueue, - this, std::placeholders::_1, - std::placeholders::_2))}, - {READY, - std::function( - std::bind( - &Nitwork::sendDataFromQueue, - this, std::placeholders::_1, - std::placeholders::_2))} - }; - }; -} // namespace Nitwork diff --git a/src/Nitwork/NitworkServer.cpp b/src/Nitwork/NitworkServer.cpp new file mode 100644 index 00000000..34b502f8 --- /dev/null +++ b/src/Nitwork/NitworkServer.cpp @@ -0,0 +1,112 @@ +/* +** EPITECH PROJECT, 2023 +** r-type +** File description: +** NitworkServer +*/ + +#include "NitworkServer.hpp" + +namespace Nitwork { + NitworkServer::NitworkServer() + : ANitwork() {} + + // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) + NitworkServer NitworkServer::_instance = NitworkServer(); + // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) + + NitworkServer &NitworkServer::getInstance() + { + return _instance; + } + + bool NitworkServer::start(int port, int threadNb, int tick) + { + return ANitwork::start(port, threadNb, tick); + } + + bool NitworkServer::startNitworkConfig(int port) + { + _endpoint = + boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port); + _socket.open(boost::asio::ip::udp::v4()); + if (!_socket.is_open()) { + std::cerr << "Error: socket not open" << std::endl; + return false; + } + _socket.bind(_endpoint); + return true; + } + + void NitworkServer::handleBodyAction( + const struct header_s header, + const boost::asio::ip::udp::endpoint &endpoint) + { + auto *action = reinterpret_cast( + _receiveBuffer.data() + sizeof(struct header_s)); + std::cout << "action.magick: " << action->magick << std::endl; + auto endPointIt = std::find_if( + _endpoints.begin(), _endpoints.end(), + [&endpoint](const boost::asio::ip::udp::endpoint &e) { + return e.address() == endpoint.address(); + }); + if (endPointIt == _endpoints.end() && action->magick != INIT) { + std::cerr << "Error: endpoint not found" << std::endl; + startReceiveHandler(); + return; + } + auto it = _actionsHandlers.find(action->magick); + if (it == _actionsHandlers.end()) { + std::cerr << "Error: action not found" << std::endl; + startReceiveHandler(); + return; + } + it->second.first(header, it->second.second); + startReceiveHandler(); + } + + /* Getters Section */ + const std::map< + enum n_actionType_t, + actionHandler + >& + NitworkServer::getActionToSendHandlers() const + { + return _actionToSendHandlers; + } + /* End Getters Section */ + + /* Handle packet (msg) Section */ + void NitworkServer::handleInitMsg( + const std::any &msg, + boost::asio::ip::udp::endpoint &endpoint) + { + const struct msgInit_s &initMsg = std::any_cast(msg); + + std::cout << "init" << std::endl; + if (_endpoints.size() >= MAX_CLIENTS) { + std::cerr << "Too many clients, can't add an other one" << std::endl; + return; + } + auto endPointIt = std::find_if( + _endpoints.begin(), _endpoints.end(), + [&endpoint](const boost::asio::ip::udp::endpoint &e) { + return e.address() == endpoint.address(); + }); + if (endPointIt != _endpoints.end()) { + std::cerr << "Error: endpoint already init" << std::endl; + return; + } + _endpoints.emplace_back(endpoint); + } + + void NitworkServer::handleReadyMsg( + const std::any &msg, + boost::asio::ip::udp::endpoint &endpoint) + { + const struct msgReady_s &readyMsg = + std::any_cast(msg); + std::cout << "ready" << std::endl; + } + /* End Handle packet (msg) Section */ +} \ No newline at end of file diff --git a/src/Nitwork/NitworkServer.hpp b/src/Nitwork/NitworkServer.hpp new file mode 100644 index 00000000..3d841e6c --- /dev/null +++ b/src/Nitwork/NitworkServer.hpp @@ -0,0 +1,119 @@ +/* +** EPITECH PROJECT, 2023 +** r-type +** File description: +** NitworkServer +*/ + +#pragma once + +#include "ANitwork.hpp" + +namespace Nitwork { + class NitworkServer : public ANitwork { + public: + NitworkServer(); + ~NitworkServer() = default; + + static NitworkServer &getInstance(); + + bool start(int port, int threadNb = DEFAULT_THREAD_NB, int tick = TICKS_PER_SECOND) final; + + bool startNitworkConfig(int port) final; + + void handleBodyAction( + const struct header_s header, + const boost::asio::ip::udp::endpoint &endpoint) final; + private: + [[nodiscard]] const std::map< + enum n_actionType_t, + actionHandler + >& getActionToSendHandlers() const final; + + void handleInitMsg( + const std::any &msg, + boost::asio::ip::udp::endpoint &endpoint); + + void handleReadyMsg( + const std::any &msg, + boost::asio::ip::udp::endpoint &endpoint); + protected: + private: + // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) + static NitworkServer + _instance; // instance of the NitworkServer (singleton) + // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) + boost::asio::ip::udp::endpoint _endpoint; // endpoint of the NitworkServer + std::list _endpoints; // A vector of endpoints which will be used to send the actions to the clients and identify them + + // maps that will be used to handle the actions, in order to send or receive them + std::map< + enum n_actionType_t, + std::pair + > _actionsHandlers = { + { + INIT, + std::make_pair( + handleBodyT( + std::bind( + &NitworkServer::handleBody, + this, std::placeholders::_1, + std::placeholders::_2 + ) + ), + actionHandler( + std::bind( + &NitworkServer::handleInitMsg, + this, std::placeholders::_1, + std::placeholders::_2 + ) + ) + ) + }, + { + READY, + std::make_pair( + handleBodyT( + std::bind( + &NitworkServer::handleBody, + this, std::placeholders::_1, + std::placeholders::_2 + ) + ), + actionHandler( + std::bind( + &NitworkServer::handleReadyMsg, + this, std::placeholders::_1, + std::placeholders::_2 + ) + ) + ) + }, + }; + std::map< + enum n_actionType_t, + actionHandler + > _actionToSendHandlers = { + { + INIT, + actionHandler( + std::bind( + &ANitwork::sendData, + this, std::placeholders::_1, + std::placeholders::_2 + ) + ) + }, + { + READY, + actionHandler( + std::bind( + &ANitwork::sendData, + this, std::placeholders::_1, + std::placeholders::_2 + ) + ) + } + }; + }; +} \ No newline at end of file diff --git a/src/main_client.cpp b/src/main_client.cpp index e9225c22..3849a26a 100644 --- a/src/main_client.cpp +++ b/src/main_client.cpp @@ -5,7 +5,7 @@ ** main */ -#include +#include struct packetData_s { struct header_s header; diff --git a/src/main_server.cpp b/src/main_server.cpp index faf1839c..8a638b22 100644 --- a/src/main_server.cpp +++ b/src/main_server.cpp @@ -1,14 +1,21 @@ -#include "Nitwork.hpp" -#include "boost/asio.hpp" +//#include "NitworkServer.hpp" +#include "NitworkServer.hpp" int main() { +// try { +// std::cout << "Starting server..." << std::endl; +// NitworkServer::NitworkServer::getInstance().start(4242); +// std::cout << "Server started." << std::endl; +// while (true); +// } catch (std::exception& e) { +// std::cerr << e.what() << std::endl; +// } try { std::cout << "Starting server..." << std::endl; - Nitwork::Nitwork::getInstance().start(4242); + Nitwork::NitworkServer::getInstance().start(4242); std::cout << "Server started." << std::endl; - while (true) - ; + while (true); } catch (std::exception& e) { std::cerr << e.what() << std::endl; }