From ff593562b9969ec3b84787ad88fc37d30334c22c Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Sun, 14 Nov 2021 19:41:04 +0300 Subject: [PATCH 01/15] add sharing document logic --- CMakeLists.txt | 16 ++- project/sharedDocument/include/Client.h | 46 ++++++++ .../sharedDocument/include/SharedDocument.h | 39 +++++++ project/sharedDocument/src/Client.cpp | 98 +++++++++++++++++ project/sharedDocument/src/SharedDocument.cpp | 104 ++++++++++++++++++ project/sharedDocument/src/main.cpp | 10 ++ project/src/main.cpp | 7 -- 7 files changed, 307 insertions(+), 13 deletions(-) create mode 100644 project/sharedDocument/include/Client.h create mode 100644 project/sharedDocument/include/SharedDocument.h create mode 100644 project/sharedDocument/src/Client.cpp create mode 100644 project/sharedDocument/src/SharedDocument.cpp create mode 100644 project/sharedDocument/src/main.cpp delete mode 100644 project/src/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d2919ae..77651ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,14 @@ -project(DeepPic CXX) - -cmake_minimum_required(VERSION 3.6) +cmake_minimum_required(VERSION 3.20) +project(boost_asio_async_server) set(CMAKE_CXX_STANDARD 20) -file(GLOB_RECURSE HEADER_FILES project/include/*.h) -file(GLOB_RECURSE SOURCE_FILES project/src/*.cpp) +find_package(Boost 1.40.0 REQUIRED system) +find_package(Boost COMPONENTS log log_setup REQUIRED) +link_directories(${Boost_LIBRARY_DIR}) + +include_directories(project/sharedDocument/include ${Boost_INCLUDE_DIR}) +aux_source_directory(project/sharedDocument/src SRC) +add_executable(boost_asio_async_server ${SRC}) -add_executable(main ${HEADER_FILES} ${SOURCE_FILES}) \ No newline at end of file +target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES}) diff --git a/project/sharedDocument/include/Client.h b/project/sharedDocument/include/Client.h new file mode 100644 index 0000000..58ad992 --- /dev/null +++ b/project/sharedDocument/include/Client.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +#define BUFFERS_RESERVE 1024 + +class Client : public std::enable_shared_from_this { +public: + Client(boost::asio::io_service &service, + std::function command_handler, + std::function check_token, std::function on_delete); + + void readAuthToken(); // вызывается при подключении клиента. вызывает функцию асинхронного чтения + + // вызовется после чтения токена. если все пройдет успешно, отправит клиенту сообщение об успехе, иначе об ошибки + void checkAuthToken(const boost::system::error_code &e, std::size_t bytes_transferred); + + size_t end_of_token(const boost::system::error_code &, size_t bytes); + + // отправляет клиенту сообщение об успешной аутентификации и handler'ом делает read_command() + void authSuccess(); + + void startReadCommand(const boost::system::error_code &e, + std::size_t bytes_transferred); + + void readCommand(); // вызывает асинхронное чтение команд + + // вызовется после получения команды. отправит документу уведомление что нужно отправить команду остальным клиентам. + void notifyOtherClients(const boost::system::error_code &e, std::size_t bytes_transferred); + + // вызовется классом SharedDocument, если вдруг придут команды от других пользователей + // TODO: на время вызова функции до того момента, пока не отправится одна команда, заблокировать эту функцию + // иначе перезаатрется send_buf_. Возможно с помощью мьютекса + void writeCommand(std::string &command); + + boost::asio::ip::tcp::socket &sock() { return sock_; } + +private: + boost::asio::ip::tcp::socket sock_; + std::function command_handler_; + std::function check_auth_token_; + std::function on_delete_; + char read_buf_[BUFFERS_RESERVE]; + char send_buf_[BUFFERS_RESERVE]; +}; \ No newline at end of file diff --git a/project/sharedDocument/include/SharedDocument.h b/project/sharedDocument/include/SharedDocument.h new file mode 100644 index 0000000..261ba29 --- /dev/null +++ b/project/sharedDocument/include/SharedDocument.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +#include + +class SharedDocument { +public: + static int start_since_port; // начиная с какого порта начнут создаваться объекты SharedDocument + static void init_start_port(int port); + + SharedDocument(); + + void startShared(); + +private: + void generateAuthToken(); + + void startAcceptClients(); + + void handleAcceptClient(std::shared_ptr client, const boost::system::error_code &err); + + void onDeleteClient(Client *client); + + bool checkAuthToken(std::string &token); + + void sharingCommand(std::string &command, Client *author); + + void run(); + + boost::asio::io_service service_; + std::string auth_token_; + boost::asio::ip::tcp::acceptor acceptor_; + int port_; + std::vector> clients; + //boost::log::sources::logger logger_; +}; diff --git a/project/sharedDocument/src/Client.cpp b/project/sharedDocument/src/Client.cpp new file mode 100644 index 0000000..485192b --- /dev/null +++ b/project/sharedDocument/src/Client.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + +#include "Client.h" + + +Client::Client(boost::asio::io_service &service, + std::function command_handler, + std::function check_token, + std::function on_delete) : sock_(service), + command_handler_(std::move(command_handler)), + check_auth_token_(std::move(check_token)), + on_delete_(std::move(on_delete)) { +} + +void Client::readAuthToken() { + boost::asio::async_read(sock_, boost::asio::buffer(read_buf_), + boost::bind(&Client::end_of_token, shared_from_this(), boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred), + boost::bind(&Client::checkAuthToken, shared_from_this(), boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + std::cerr << "client sock addr: " << sock_.remote_endpoint().address().to_string() << std::endl; +} + + +void Client::checkAuthToken(const boost::system::error_code &e, std::size_t bytes_transferred) { + if (e) { + on_delete_(this); + return; + } + std::cerr << "check auth token" << std::endl; + std::cerr << read_buf_ << " " << bytes_transferred << std::endl; + std::string auth_token(read_buf_, read_buf_ + bytes_transferred - 1); + if (check_auth_token_(auth_token)) { + authSuccess(); + } else { + + on_delete_(this); + // TODO: возможно сделать какую-нибудь отправку о неуспешной авторизации + return; + } +} + +void Client::authSuccess() { + strcpy(send_buf_, "auth success"); + std::cerr << "auth success" << std::endl; + sock_.async_write_some(boost::asio::buffer(send_buf_, strlen("auth success")), + [this_obj = shared_from_this()](auto &&PH1, auto &&PH2) { + this_obj->startReadCommand(std::forward(PH1), + std::forward(PH2)); + }); +} + +void Client::startReadCommand(const boost::system::error_code &e, std::size_t bytes_transferred) { + if (e) { + on_delete_(this); + return; + } + readCommand(); +} + +void Client::readCommand() { + sock_.async_read_some(boost::asio::buffer(read_buf_), [this_obj = shared_from_this()](auto &&PH1, auto &&PH2) { + this_obj->notifyOtherClients(std::forward(PH1), + std::forward(PH2)); + }); +} + +void Client::notifyOtherClients(const boost::system::error_code &e, std::size_t bytes_transferred) { + if (e) { + on_delete_(this); + return; + } + command_handler_(read_buf_, this); + readCommand(); +} + +void Client::writeCommand(std::string &command) { + // TODO: сделать так, чтобы единовременно могла отправляться только одна команда. мб как-то через мьютекс + for (int i = 0; i < command.length(); ++i) { + send_buf_[i] = command[i]; + } + sock_.async_write_some(boost::asio::buffer(send_buf_, command.length()), [this_obj = shared_from_this()](auto &&PH1, auto &&PH2) { + this_obj->startReadCommand(std::forward(PH1), + std::forward(PH2)); + }); +} + +size_t Client::end_of_token(const boost::system::error_code &err, size_t bytes) { + std::cout << read_buf_ << std::endl; + if (bytes > 0 && read_buf_[bytes - 1] == '\n') { + return 0; + } + return 1; +} diff --git a/project/sharedDocument/src/SharedDocument.cpp b/project/sharedDocument/src/SharedDocument.cpp new file mode 100644 index 0000000..331f603 --- /dev/null +++ b/project/sharedDocument/src/SharedDocument.cpp @@ -0,0 +1,104 @@ +#include +#include +#include +#include + +#include "SharedDocument.h" +#include "Client.h" +#include +#include + +SharedDocument::SharedDocument() : acceptor_(service_), port_(start_since_port++) { + generateAuthToken(); +} + +void SharedDocument::generateAuthToken() { + auth_token_ = "dummy_aboba"; +} + +void SharedDocument::startShared() { + boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port_); + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(1024); + startAcceptClients(); + + std::cerr << "Start shared on port " << port_ << std::endl; + + service_.run(); + /* + std::vector threads; + threads.reserve(4); + for (int i = 0; i < 4; ++i) { + threads.emplace_back([this] { run(); }); + } + + for (auto &thread : threads) { + thread.join(); + } + */ +} + + +bool SharedDocument::checkAuthToken(std::string &token) { + return token == auth_token_; +} + +void SharedDocument::startAcceptClients() { + std::shared_ptr client(new Client(service_, + [this](std::string command, Client *author) { + return this->sharingCommand(command, author); + }, + [this](std::string &token) { return this->checkAuthToken(token); }, + [this](Client *client) { return this->onDeleteClient(client); })); + clients.push_back(client); + + acceptor_.async_accept(client->sock(), boost::bind(&SharedDocument::handleAcceptClient, this, client, + boost::asio::placeholders::error)); +} + +void SharedDocument::sharingCommand(std::string &command, Client *author) { + for (auto &client: clients) { + if (&(*client) != author) { + client->writeCommand(command); + } + } +} + +void SharedDocument::onDeleteClient(Client *client) { + auto pos = clients.begin(); + for (auto &cl: clients) { + if (&(*cl) == client) { + break; + } + pos++; + } + try { + std::cerr << "delete client" << std::endl; + clients.erase(pos); + } + catch (...) { + + } +} + +void SharedDocument::handleAcceptClient(std::shared_ptr client, const boost::system::error_code &err) { + if (err) { + onDeleteClient(&(*client)); + std::cerr << "Error while accept client" << std::endl; + return; + } + + std::cerr << "Accept client" << std::endl; + client->readAuthToken(); + startAcceptClients(); +} + +void SharedDocument::init_start_port(int port) { + SharedDocument::start_since_port = port; +} + +void SharedDocument::run() { + service_.run(); +} diff --git a/project/sharedDocument/src/main.cpp b/project/sharedDocument/src/main.cpp new file mode 100644 index 0000000..c4f3705 --- /dev/null +++ b/project/sharedDocument/src/main.cpp @@ -0,0 +1,10 @@ +#include + +#include "SharedDocument.h" + +int SharedDocument::start_since_port = 5555; + +int main() { + SharedDocument document; + document.startShared(); +} \ No newline at end of file diff --git a/project/src/main.cpp b/project/src/main.cpp deleted file mode 100644 index f330cc7..0000000 --- a/project/src/main.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// -// Created by tesserakt on 30.10.2021. -// - -int main() { - return 0; -} \ No newline at end of file From 57442b16df72b0fbc26557f24d0e04996d71d88d Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Thu, 18 Nov 2021 15:49:13 +0300 Subject: [PATCH 02/15] made headers and public interfaces tests --- CMakeLists.txt | 6 +- project/backend/include/BaseClient.h | 29 ++++ project/backend/include/DocumentClient.h | 29 ++++ project/backend/include/Server.h | 23 ++++ project/backend/include/Settings.h | 7 + project/backend/include/SharedDocument.h | 50 +++++++ project/backend/src/BaseClient.cpp | 65 +++++++++ project/backend/src/DocumentClient.cpp | 72 ++++++++++ .../src/SharedDocument.cpp | 65 +++++---- .../{sharedDocument => backend}/src/main.cpp | 0 project/backend/unit_tests/main.cpp | 125 ++++++++++++++++++ project/sharedDocument/include/Client.h | 46 ------- .../sharedDocument/include/SharedDocument.h | 39 ------ project/sharedDocument/src/Client.cpp | 98 -------------- 14 files changed, 439 insertions(+), 215 deletions(-) create mode 100644 project/backend/include/BaseClient.h create mode 100644 project/backend/include/DocumentClient.h create mode 100644 project/backend/include/Server.h create mode 100644 project/backend/include/Settings.h create mode 100644 project/backend/include/SharedDocument.h create mode 100644 project/backend/src/BaseClient.cpp create mode 100644 project/backend/src/DocumentClient.cpp rename project/{sharedDocument => backend}/src/SharedDocument.cpp (53%) rename project/{sharedDocument => backend}/src/main.cpp (100%) create mode 100644 project/backend/unit_tests/main.cpp delete mode 100644 project/sharedDocument/include/Client.h delete mode 100644 project/sharedDocument/include/SharedDocument.h delete mode 100644 project/sharedDocument/src/Client.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 77651ce..54d8b8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ find_package(Boost 1.40.0 REQUIRED system) find_package(Boost COMPONENTS log log_setup REQUIRED) link_directories(${Boost_LIBRARY_DIR}) -include_directories(project/sharedDocument/include ${Boost_INCLUDE_DIR}) -aux_source_directory(project/sharedDocument/src SRC) -add_executable(boost_asio_async_server ${SRC}) +include_directories(project/backend/include ${Boost_INCLUDE_DIR}) +aux_source_directory(project/backend/src SRC) +add_executable(boost_asio_async_server ${SRC} project/backend/include/BaseClient.h project/backend/src/BaseClient.cpp project/backend/include/DocumentClient.h project/backend/src/DocumentClient.cpp project/backend/include/Server.h project/backend/include/Settings.h project/backend/unit_tests/main.cpp) target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES}) diff --git a/project/backend/include/BaseClient.h b/project/backend/include/BaseClient.h new file mode 100644 index 0000000..f04f829 --- /dev/null +++ b/project/backend/include/BaseClient.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "Settings.h" + +class BaseClient { +public: + BaseClient(boost::asio::io_service &service, + std::function command_handler, + std::function on_delete); + + boost::asio::ip::tcp::socket &getSock(); + + virtual void afterConnect(); + virtual void writeCommand(std::string &command); + +protected: + virtual void readCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred); + virtual std::size_t checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred); + virtual void writeCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred); + virtual void readCommand(); + + boost::asio::ip::tcp::socket sock_; + std::function command_handler_; + std::function on_delete_; + char read_buf_[BUFFER_LENGTH]; + char send_buf_[BUFFER_LENGTH]; +}; \ No newline at end of file diff --git a/project/backend/include/DocumentClient.h b/project/backend/include/DocumentClient.h new file mode 100644 index 0000000..02465e8 --- /dev/null +++ b/project/backend/include/DocumentClient.h @@ -0,0 +1,29 @@ +#pragma once + +#include "BaseClient.h" + +class DocumentClient : public BaseClient { +public: + DocumentClient(boost::asio::io_service &service, + std::function command_handler, + std::function on_delete, + std::function check_auth_token); + + void afterConnect() override; + +private: + void checkAuthToken(const boost::system::error_code &err, std::size_t bytes_transferred); + + void authSuccess(); + + void authSuccessHandler(const boost::system::error_code &err, std::size_t bytes_transferred); + + void authError(); + + void authErrorHandler(const boost::system::error_code &err, std::size_t bytes_transferred); + + + std::function check_auth_token_; + + bool is_auth = false; +}; \ No newline at end of file diff --git a/project/backend/include/Server.h b/project/backend/include/Server.h new file mode 100644 index 0000000..04f4529 --- /dev/null +++ b/project/backend/include/Server.h @@ -0,0 +1,23 @@ +#include + +#include "BaseClient.h" +#include "Settings.h" + +class Server { +public: + Server(int port); + + void runServer(); + +private: + void startAcceptClients(); + void handleAcceptClient(std::shared_ptr client, boost::system::error_code &err); + void writeDocumentPortToClient(); + void handleWriteDocumentPort(const boost::system::error_code &err, std::size_t bytes_transferred); + + boost::asio::io_service service_; + boost::asio::ip::tcp::acceptor acceptor_; + int port_; + char read_buf_[BUFFER_LENGTH]; + char send_buf_[BUFFER_LENGTH]; +}; \ No newline at end of file diff --git a/project/backend/include/Settings.h b/project/backend/include/Settings.h new file mode 100644 index 0000000..1b48218 --- /dev/null +++ b/project/backend/include/Settings.h @@ -0,0 +1,7 @@ +#pragma once + +#define BUFFER_LENGTH 1024 +#define END_STR "\r\n" +#define MAX_DOCUMENT_LENGTH 2048 + +#define AUTH_SUCCESS_COMMAND "auth success" \ No newline at end of file diff --git a/project/backend/include/SharedDocument.h b/project/backend/include/SharedDocument.h new file mode 100644 index 0000000..7c32198 --- /dev/null +++ b/project/backend/include/SharedDocument.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +#include "DocumentClient.h" +#include "Settings.h" + +class SharedDocument { +public: + static int start_since_port;// начиная с какого порта начнут создаваться объекты SharedDocument + + SharedDocument(); + + void startShared(); + + int getPort(); + + std::string getAuthToken(); + +private: + void generateAuthToken(); + + void startAcceptClients(); + + void handleAcceptClient(std::shared_ptr client, const boost::system::error_code &err); + + void deleteClient(BaseClient *client); + + bool checkAuthToken(std::string &token); + + void sharingCommand(std::string &command, BaseClient *author); + + void run(); + + void getDocumentFromClient(); + + void handleGetDocumentFromClient(const boost::system::error_code &err, std::size_t bytes_transferred); + + void sendDocumentToNewClients(); + + boost::asio::io_service service_; + std::string auth_token_; + boost::asio::ip::tcp::acceptor acceptor_; + int port_; + std::vector> clients_; + std::vector> toGetDocument_; + char document_[MAX_DOCUMENT_LENGTH]; +}; diff --git a/project/backend/src/BaseClient.cpp b/project/backend/src/BaseClient.cpp new file mode 100644 index 0000000..4db55e1 --- /dev/null +++ b/project/backend/src/BaseClient.cpp @@ -0,0 +1,65 @@ +#include +#include + +#include "BaseClient.h" + + +BaseClient::BaseClient(boost::asio::io_service &service, std::function command_handler, + std::function on_delete) : sock_(service), + command_handler_(std::move(command_handler)), + on_delete_(std::move(on_delete)) { +} + + +void BaseClient::afterConnect() { + readCommand(); +} + +void BaseClient::readCommand() { + boost::asio::async_read(sock_, boost::asio::buffer(read_buf_), + boost::bind(&BaseClient::checkEndOfRead, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred), + boost::bind(&BaseClient::readCommandHandler, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void BaseClient::writeCommand(std::string &command) { + for (int i = 0; i < command.length(); ++i) { + send_buf_[i] = command[i]; + } + sock_.async_write_some(boost::asio::buffer(send_buf_, command.length()), [this_obj = this](auto &&PH1, auto &&PH2) { + this_obj->writeCommandHandler(std::forward(PH1), + std::forward(PH2)); + }); +} + + +void BaseClient::readCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { + if (err) { + on_delete_(this); + return; + } + + command_handler_(std::string(read_buf_, read_buf_ + bytes_transferred - 1), this); + readCommand(); +} + + +std::size_t BaseClient::checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred) { + if (bytes_transferred > 0 && std::string(read_buf_ + bytes_transferred - 1 - std::strlen(END_STR), read_buf_ + bytes_transferred - 1) == std::string(END_STR)) { + return 0; + } + return 1; +} + + +void BaseClient::writeCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { + if (err) { + on_delete_(this); + } +} + + +boost::asio::ip::tcp::socket &BaseClient::getSock() { + return sock_; +} diff --git a/project/backend/src/DocumentClient.cpp b/project/backend/src/DocumentClient.cpp new file mode 100644 index 0000000..cc450da --- /dev/null +++ b/project/backend/src/DocumentClient.cpp @@ -0,0 +1,72 @@ +#include +#include +#include + +#include "DocumentClient.h" + + +void DocumentClient::afterConnect() { + boost::asio::async_read(sock_, boost::asio::buffer(read_buf_), + boost::bind(&DocumentClient::checkEndOfRead, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred), + boost::bind(&DocumentClient::checkAuthToken, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + + +DocumentClient::DocumentClient(boost::asio::io_service &service, std::function command_handler, + std::function on_delete, + std::function check_auth_token) : BaseClient(service, std::move(command_handler), std::move(on_delete)), + check_auth_token_(std::move(check_auth_token)) { +} + + +void DocumentClient::checkAuthToken(const boost::system::error_code &err, std::size_t bytes_transferred) { + if (err) { + on_delete_(this); + return; + } + std::string auth_token(read_buf_, read_buf_ + bytes_transferred - 1); + if (check_auth_token_(auth_token)) { + authSuccess(); + } else { + + on_delete_(this); + // TODO: возможно сделать какую-нибудь отправку о неуспешной авторизации + return; + } +} + + +void DocumentClient::authSuccess() { + std::strcpy(send_buf_, "auth success"); + sock_.async_write_some(boost::asio::buffer(send_buf_, strlen("auth success")), + [this_obj = this](auto &&PH1, auto &&PH2) { + this_obj->authSuccessHandler(PH1, PH2); + }); +} + + +void DocumentClient::authSuccessHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { + if (err) { + on_delete_(this); + return; + } + is_auth = true; + + readCommand(); +} + + +void DocumentClient::authError() { + std::strcpy(send_buf_, "auth error"); + sock_.async_write_some(boost::asio::buffer(send_buf_, strlen("auth error")), + [this_obj = this](auto &&PH1, auto &&PH2) { + this_obj->authErrorHandler(PH1, PH2); + }); +} + + +void DocumentClient::authErrorHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { + on_delete_(this); +} diff --git a/project/sharedDocument/src/SharedDocument.cpp b/project/backend/src/SharedDocument.cpp similarity index 53% rename from project/sharedDocument/src/SharedDocument.cpp rename to project/backend/src/SharedDocument.cpp index 331f603..e02f9c9 100644 --- a/project/sharedDocument/src/SharedDocument.cpp +++ b/project/backend/src/SharedDocument.cpp @@ -1,12 +1,9 @@ -#include #include #include -#include +#include #include "SharedDocument.h" -#include "Client.h" #include -#include SharedDocument::SharedDocument() : acceptor_(service_), port_(start_since_port++) { generateAuthToken(); @@ -45,30 +42,34 @@ bool SharedDocument::checkAuthToken(std::string &token) { return token == auth_token_; } + void SharedDocument::startAcceptClients() { - std::shared_ptr client(new Client(service_, - [this](std::string command, Client *author) { - return this->sharingCommand(command, author); - }, - [this](std::string &token) { return this->checkAuthToken(token); }, - [this](Client *client) { return this->onDeleteClient(client); })); - clients.push_back(client); - - acceptor_.async_accept(client->sock(), boost::bind(&SharedDocument::handleAcceptClient, this, client, - boost::asio::placeholders::error)); + std::shared_ptr client(new DocumentClient( + service_, + [this](std::string command, BaseClient *author) { + return this->sharingCommand(command, author); + }, + [this](BaseClient *client) { return this->deleteClient(client); }, + [this](std::string &token) { return this->checkAuthToken(token); })); + clients_.push_back(client); + + acceptor_.async_accept(client->getSock(), boost::bind(&SharedDocument::handleAcceptClient, this, client, + boost::asio::placeholders::error)); } -void SharedDocument::sharingCommand(std::string &command, Client *author) { - for (auto &client: clients) { + +void SharedDocument::sharingCommand(std::string &command, BaseClient *author) { + for (auto &client : clients_) { if (&(*client) != author) { client->writeCommand(command); } } } -void SharedDocument::onDeleteClient(Client *client) { - auto pos = clients.begin(); - for (auto &cl: clients) { + +void SharedDocument::deleteClient(BaseClient *client) { + auto pos = clients_.begin(); + for (auto &cl : clients_) { if (&(*cl) == client) { break; } @@ -76,29 +77,35 @@ void SharedDocument::onDeleteClient(Client *client) { } try { std::cerr << "delete client" << std::endl; - clients.erase(pos); - } - catch (...) { - + clients_.erase(pos); + } catch (...) { } } -void SharedDocument::handleAcceptClient(std::shared_ptr client, const boost::system::error_code &err) { + +void SharedDocument::handleAcceptClient(std::shared_ptr client, const boost::system::error_code &err) { if (err) { - onDeleteClient(&(*client)); + deleteClient(&(*client)); std::cerr << "Error while accept client" << std::endl; return; } std::cerr << "Accept client" << std::endl; - client->readAuthToken(); + client->afterConnect(); startAcceptClients(); } -void SharedDocument::init_start_port(int port) { - SharedDocument::start_since_port = port; -} void SharedDocument::run() { service_.run(); } + + +int SharedDocument::getPort() { + return port_; +} + + +std::string SharedDocument::getAuthToken() { + return auth_token_; +} diff --git a/project/sharedDocument/src/main.cpp b/project/backend/src/main.cpp similarity index 100% rename from project/sharedDocument/src/main.cpp rename to project/backend/src/main.cpp diff --git a/project/backend/unit_tests/main.cpp b/project/backend/unit_tests/main.cpp new file mode 100644 index 0000000..53f21c1 --- /dev/null +++ b/project/backend/unit_tests/main.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include + + +#include "Server.h" +#include "Settings.h" +#include "SharedDocument.h" + +using namespace boost::asio; + +#define SHARING_DOCUMENT_COMMAND "sharing document" +#define AUTH_COMMAND "auth_token=" + +class TestServer : public ::testing::Test { +protected: + void SetUp() { + myServer_ = new Server(5555); + myServer_->runServer(); + ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"), 5555); + sock_ = new ip::tcp::socket(service_); + sock_->connect(ep); + } + + void TearDown() { + delete myServer_; + delete sock_; + } + + Server *myServer_; + io_service service_; + ip::tcp::socket *sock_; + char buf[1024]; +}; + +class TestSharingDocument : public ::testing::Test { +protected: + void SetUp() { + SharedDocument::start_since_port = 8001; + document_ = new SharedDocument(); + document_->startShared(); + auth_token_ = document_->getAuthToken(); + port_ = document_->getPort(); + } + + void TearDown() { + delete document_; + } + + SharedDocument *document_; + std::string auth_token_; + int port_; + io_service service_; + char buf[1024]; +}; + +size_t read_complete(char *buf, const std::error_code &err, size_t bytes_transferred) { + if (bytes_transferred > 0 && std::string(buf + bytes_transferred - 1 - std::strlen(END_STR), buf + bytes_transferred - 1) == std::string(END_STR)) { + return 0; + } + return 1; +} + +TEST_F(TestServer, test) { + std::strcpy(buf, SHARING_DOCUMENT_COMMAND); + std::strcpy(buf + std::strlen(SHARING_DOCUMENT_COMMAND), END_STR); + sock_->write_some(buffer(buf, std::strlen(SHARING_DOCUMENT_COMMAND) + std::strlen(END_STR))); + + int bytes = read(*sock_, buffer(buf), boost::bind(read_complete, buf, _1, _2)); + std::string copy(buf, bytes - 1); + int port = -1; + EXPECT_NO_THROW([&]() { port = std::stoi(copy); }); + EXPECT_GE(port, 0); + ip::tcp::socket to_shared_document_socket(service_); + ip::tcp::endpoint shared_document_ep(ip::address::from_string("127.0.0.1"), port); + EXPECT_NO_THROW(to_shared_document_socket.connect(shared_document_ep)); +} + +TEST_F(TestSharingDocument, test) { + EXPECT_EQ(port_, 8001); + + ip::tcp::endpoint shared_doc_ep(ip::address::from_string("127.0.0.1"), port_); + ip::tcp::socket client1(service_); + EXPECT_NO_THROW(client1.connect(shared_doc_ep)); // подключаемся к расшаренному документы + + // аутентификация в документе + std::strcpy(buf, AUTH_COMMAND); + std::strcpy(buf + std::strlen(AUTH_COMMAND), (document_->getAuthToken() + END_STR).c_str()); + client1.write_some(buffer(buf, std::strlen(AUTH_COMMAND) + document_->getAuthToken().length() + std::strlen(END_STR))); + + // проверка успешности аутентификации + int bytes = read(client1, buffer(buf), boost::bind(read_complete, buf, _1, _2)); + EXPECT_STREQ(buf, AUTH_SUCCESS_COMMAND); + + // подключение к документу второго клиента + ip::tcp::socket client2(service_); + EXPECT_NO_THROW(client2.connect(shared_doc_ep)); + + // аутентификация второго клиента в документе + std::strcpy(buf, AUTH_COMMAND); + std::strcpy(buf + std::strlen(AUTH_COMMAND), (document_->getAuthToken() + END_STR).c_str()); + client2.write_some(buffer(buf, std::strlen(AUTH_COMMAND) + document_->getAuthToken().length() + std::strlen(END_STR))); + + // проверка аутентификации + bytes = read(client1, buffer(buf), boost::bind(read_complete, buf, _1, _2)); + EXPECT_STREQ(buf, AUTH_SUCCESS_COMMAND); + + // отправка команды вторым клиентом + std::string command = "aboba welcomes you"; + command += END_STR; + std::strcpy(buf, command.c_str()); + client2.write_some(buffer(buf, command.length())); + + // проверка получение первым клиентом команды второго клиента + bytes = read(client1, buffer(buf), boost::bind(read_complete, buf, _1, _2)); + EXPECT_STREQ(buf, command.c_str()); +} + + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/project/sharedDocument/include/Client.h b/project/sharedDocument/include/Client.h deleted file mode 100644 index 58ad992..0000000 --- a/project/sharedDocument/include/Client.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include - -#define BUFFERS_RESERVE 1024 - -class Client : public std::enable_shared_from_this { -public: - Client(boost::asio::io_service &service, - std::function command_handler, - std::function check_token, std::function on_delete); - - void readAuthToken(); // вызывается при подключении клиента. вызывает функцию асинхронного чтения - - // вызовется после чтения токена. если все пройдет успешно, отправит клиенту сообщение об успехе, иначе об ошибки - void checkAuthToken(const boost::system::error_code &e, std::size_t bytes_transferred); - - size_t end_of_token(const boost::system::error_code &, size_t bytes); - - // отправляет клиенту сообщение об успешной аутентификации и handler'ом делает read_command() - void authSuccess(); - - void startReadCommand(const boost::system::error_code &e, - std::size_t bytes_transferred); - - void readCommand(); // вызывает асинхронное чтение команд - - // вызовется после получения команды. отправит документу уведомление что нужно отправить команду остальным клиентам. - void notifyOtherClients(const boost::system::error_code &e, std::size_t bytes_transferred); - - // вызовется классом SharedDocument, если вдруг придут команды от других пользователей - // TODO: на время вызова функции до того момента, пока не отправится одна команда, заблокировать эту функцию - // иначе перезаатрется send_buf_. Возможно с помощью мьютекса - void writeCommand(std::string &command); - - boost::asio::ip::tcp::socket &sock() { return sock_; } - -private: - boost::asio::ip::tcp::socket sock_; - std::function command_handler_; - std::function check_auth_token_; - std::function on_delete_; - char read_buf_[BUFFERS_RESERVE]; - char send_buf_[BUFFERS_RESERVE]; -}; \ No newline at end of file diff --git a/project/sharedDocument/include/SharedDocument.h b/project/sharedDocument/include/SharedDocument.h deleted file mode 100644 index 261ba29..0000000 --- a/project/sharedDocument/include/SharedDocument.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -class SharedDocument { -public: - static int start_since_port; // начиная с какого порта начнут создаваться объекты SharedDocument - static void init_start_port(int port); - - SharedDocument(); - - void startShared(); - -private: - void generateAuthToken(); - - void startAcceptClients(); - - void handleAcceptClient(std::shared_ptr client, const boost::system::error_code &err); - - void onDeleteClient(Client *client); - - bool checkAuthToken(std::string &token); - - void sharingCommand(std::string &command, Client *author); - - void run(); - - boost::asio::io_service service_; - std::string auth_token_; - boost::asio::ip::tcp::acceptor acceptor_; - int port_; - std::vector> clients; - //boost::log::sources::logger logger_; -}; diff --git a/project/sharedDocument/src/Client.cpp b/project/sharedDocument/src/Client.cpp deleted file mode 100644 index 485192b..0000000 --- a/project/sharedDocument/src/Client.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include -#include -#include -#include - -#include "Client.h" - - -Client::Client(boost::asio::io_service &service, - std::function command_handler, - std::function check_token, - std::function on_delete) : sock_(service), - command_handler_(std::move(command_handler)), - check_auth_token_(std::move(check_token)), - on_delete_(std::move(on_delete)) { -} - -void Client::readAuthToken() { - boost::asio::async_read(sock_, boost::asio::buffer(read_buf_), - boost::bind(&Client::end_of_token, shared_from_this(), boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred), - boost::bind(&Client::checkAuthToken, shared_from_this(), boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); - std::cerr << "client sock addr: " << sock_.remote_endpoint().address().to_string() << std::endl; -} - - -void Client::checkAuthToken(const boost::system::error_code &e, std::size_t bytes_transferred) { - if (e) { - on_delete_(this); - return; - } - std::cerr << "check auth token" << std::endl; - std::cerr << read_buf_ << " " << bytes_transferred << std::endl; - std::string auth_token(read_buf_, read_buf_ + bytes_transferred - 1); - if (check_auth_token_(auth_token)) { - authSuccess(); - } else { - - on_delete_(this); - // TODO: возможно сделать какую-нибудь отправку о неуспешной авторизации - return; - } -} - -void Client::authSuccess() { - strcpy(send_buf_, "auth success"); - std::cerr << "auth success" << std::endl; - sock_.async_write_some(boost::asio::buffer(send_buf_, strlen("auth success")), - [this_obj = shared_from_this()](auto &&PH1, auto &&PH2) { - this_obj->startReadCommand(std::forward(PH1), - std::forward(PH2)); - }); -} - -void Client::startReadCommand(const boost::system::error_code &e, std::size_t bytes_transferred) { - if (e) { - on_delete_(this); - return; - } - readCommand(); -} - -void Client::readCommand() { - sock_.async_read_some(boost::asio::buffer(read_buf_), [this_obj = shared_from_this()](auto &&PH1, auto &&PH2) { - this_obj->notifyOtherClients(std::forward(PH1), - std::forward(PH2)); - }); -} - -void Client::notifyOtherClients(const boost::system::error_code &e, std::size_t bytes_transferred) { - if (e) { - on_delete_(this); - return; - } - command_handler_(read_buf_, this); - readCommand(); -} - -void Client::writeCommand(std::string &command) { - // TODO: сделать так, чтобы единовременно могла отправляться только одна команда. мб как-то через мьютекс - for (int i = 0; i < command.length(); ++i) { - send_buf_[i] = command[i]; - } - sock_.async_write_some(boost::asio::buffer(send_buf_, command.length()), [this_obj = shared_from_this()](auto &&PH1, auto &&PH2) { - this_obj->startReadCommand(std::forward(PH1), - std::forward(PH2)); - }); -} - -size_t Client::end_of_token(const boost::system::error_code &err, size_t bytes) { - std::cout << read_buf_ << std::endl; - if (bytes > 0 && read_buf_[bytes - 1] == '\n') { - return 0; - } - return 1; -} From b52d0511b9a27905af8533cda84d77b31ed822e8 Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Thu, 18 Nov 2021 16:59:40 +0300 Subject: [PATCH 03/15] add IManageCommand --- CMakeLists.txt | 2 +- project/backend/include/BaseClient.h | 12 ++-- project/backend/include/DocumentClient.h | 4 +- project/backend/include/IManageCommand.h | 73 ++++++++++++++++++++++++ project/backend/include/Server.h | 7 ++- project/backend/include/SharedDocument.h | 19 +++--- project/backend/src/BaseClient.cpp | 18 +++--- project/backend/src/DocumentClient.cpp | 26 ++++----- project/backend/src/SharedDocument.cpp | 14 +++-- 9 files changed, 131 insertions(+), 44 deletions(-) create mode 100644 project/backend/include/IManageCommand.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 54d8b8a..8dac74d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,6 @@ link_directories(${Boost_LIBRARY_DIR}) include_directories(project/backend/include ${Boost_INCLUDE_DIR}) aux_source_directory(project/backend/src SRC) -add_executable(boost_asio_async_server ${SRC} project/backend/include/BaseClient.h project/backend/src/BaseClient.cpp project/backend/include/DocumentClient.h project/backend/src/DocumentClient.cpp project/backend/include/Server.h project/backend/include/Settings.h project/backend/unit_tests/main.cpp) +add_executable(boost_asio_async_server ${SRC} project/backend/include/BaseClient.h project/backend/src/BaseClient.cpp project/backend/include/DocumentClient.h project/backend/src/DocumentClient.cpp project/backend/include/Server.h project/backend/include/Settings.h project/backend/unit_tests/main.cpp project/backend/include/IManageCommand.h) target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES}) diff --git a/project/backend/include/BaseClient.h b/project/backend/include/BaseClient.h index f04f829..ee14fda 100644 --- a/project/backend/include/BaseClient.h +++ b/project/backend/include/BaseClient.h @@ -13,17 +13,21 @@ class BaseClient { boost::asio::ip::tcp::socket &getSock(); virtual void afterConnect(); + virtual void writeCommand(std::string &command); protected: virtual void readCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred); + virtual std::size_t checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred); + virtual void writeCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred); + virtual void readCommand(); boost::asio::ip::tcp::socket sock_; - std::function command_handler_; - std::function on_delete_; - char read_buf_[BUFFER_LENGTH]; - char send_buf_[BUFFER_LENGTH]; + std::function commandHandler_; + std::function onDelete_; + char readBuf_[BUFFER_LENGTH]; + char sendBuf_[BUFFER_LENGTH]; }; \ No newline at end of file diff --git a/project/backend/include/DocumentClient.h b/project/backend/include/DocumentClient.h index 02465e8..39d17be 100644 --- a/project/backend/include/DocumentClient.h +++ b/project/backend/include/DocumentClient.h @@ -23,7 +23,7 @@ class DocumentClient : public BaseClient { void authErrorHandler(const boost::system::error_code &err, std::size_t bytes_transferred); - std::function check_auth_token_; + std::function checkAuthToken_; - bool is_auth = false; + bool isAuth_ = false; }; \ No newline at end of file diff --git a/project/backend/include/IManageCommand.h b/project/backend/include/IManageCommand.h new file mode 100644 index 0000000..033cf8d --- /dev/null +++ b/project/backend/include/IManageCommand.h @@ -0,0 +1,73 @@ +#pragma once + +#include "Settings.h" +#include "SharedDocument.h" + +enum { + SHARING_COMMAND = 0x01, + GET_DOCUMENT = 0x02 +} command_t; + +class IManageCommand { +public: + IManageCommand(command_t type_command, SharedDocument *document); + + IManageCommand(const IManageCommand &) = delete; + + IManageCommand &operator=(IManageCommand &) = delete; + + virtual bool do_command(std::string &command, DocumentClient *author); + + ~IManageCommand(); + +protected: + IManageCommand() : letter_(NULL); + + + SharedDocument *document_; + +private: + IManageCommand *letter_; +}; + +class GetDocument : public IManageCommand { +public: + virtual bool do_command(std::string &command, DocumentClient *author); + + GetDocument(const GetDocument &) = delete; + + GetDocument &operator=(GetDocument &) = delete; + + ~GetDocument(); + +private: + friend class IManageCommand; + + GetDocument(); + + void getDocumentFromClient(); + + void handleGetDocumentFromClient(const boost::system::error_code &err, std::size_t bytes_transferred); + + void sendDocumentToNewClients(); + + char[MAX_DOCUMENT_LENGTH] document_; + + std::vector> clientsToGetDocument_; +}; + +class SharingCommand : public IManageCommand { +public: + virtual bool do_command(std::string &command, DocumentClient *author); + + SharingCommand(const SharingCommand &) = delete; + + SharingCommand &operator=(SharingCommand &) = delete; + + ~SharingCommand(); + +private: + friend class IManageCommand; + + SharingCommand(); +}; \ No newline at end of file diff --git a/project/backend/include/Server.h b/project/backend/include/Server.h index 04f4529..5d0f3ba 100644 --- a/project/backend/include/Server.h +++ b/project/backend/include/Server.h @@ -11,13 +11,16 @@ class Server { private: void startAcceptClients(); + void handleAcceptClient(std::shared_ptr client, boost::system::error_code &err); + void writeDocumentPortToClient(); + void handleWriteDocumentPort(const boost::system::error_code &err, std::size_t bytes_transferred); boost::asio::io_service service_; boost::asio::ip::tcp::acceptor acceptor_; int port_; - char read_buf_[BUFFER_LENGTH]; - char send_buf_[BUFFER_LENGTH]; + char readBuf_[BUFFER_LENGTH]; + char sendBuf_[BUFFER_LENGTH]; }; \ No newline at end of file diff --git a/project/backend/include/SharedDocument.h b/project/backend/include/SharedDocument.h index 7c32198..ac57b1e 100644 --- a/project/backend/include/SharedDocument.h +++ b/project/backend/include/SharedDocument.h @@ -7,6 +7,8 @@ #include "DocumentClient.h" #include "Settings.h" +class IManageCommand; + class SharedDocument { public: static int start_since_port;// начиная с какого порта начнут создаваться объекты SharedDocument @@ -19,6 +21,8 @@ class SharedDocument { std::string getAuthToken(); + ~SharedDocument(); + private: void generateAuthToken(); @@ -30,21 +34,20 @@ class SharedDocument { bool checkAuthToken(std::string &token); - void sharingCommand(std::string &command, BaseClient *author); + void commandHandler(std::string &command, BaseClient *author); void run(); - void getDocumentFromClient(); - - void handleGetDocumentFromClient(const boost::system::error_code &err, std::size_t bytes_transferred); - - void sendDocumentToNewClients(); - boost::asio::io_service service_; - std::string auth_token_; + std::string authToken_; boost::asio::ip::tcp::acceptor acceptor_; int port_; std::vector> clients_; + + IManageCommand *sharingCommand_; + IManageCommand *getDocument_; + + std::vector> toGetDocument_; char document_[MAX_DOCUMENT_LENGTH]; }; diff --git a/project/backend/src/BaseClient.cpp b/project/backend/src/BaseClient.cpp index 4db55e1..60655c1 100644 --- a/project/backend/src/BaseClient.cpp +++ b/project/backend/src/BaseClient.cpp @@ -6,8 +6,8 @@ BaseClient::BaseClient(boost::asio::io_service &service, std::function command_handler, std::function on_delete) : sock_(service), - command_handler_(std::move(command_handler)), - on_delete_(std::move(on_delete)) { + commandHandler_(std::move(command_handler)), + onDelete_(std::move(on_delete)) { } @@ -16,7 +16,7 @@ void BaseClient::afterConnect() { } void BaseClient::readCommand() { - boost::asio::async_read(sock_, boost::asio::buffer(read_buf_), + boost::asio::async_read(sock_, boost::asio::buffer(readBuf_), boost::bind(&BaseClient::checkEndOfRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), boost::bind(&BaseClient::readCommandHandler, this, boost::asio::placeholders::error, @@ -25,9 +25,9 @@ void BaseClient::readCommand() { void BaseClient::writeCommand(std::string &command) { for (int i = 0; i < command.length(); ++i) { - send_buf_[i] = command[i]; + sendBuf_[i] = command[i]; } - sock_.async_write_some(boost::asio::buffer(send_buf_, command.length()), [this_obj = this](auto &&PH1, auto &&PH2) { + sock_.async_write_some(boost::asio::buffer(sendBuf_, command.length()), [this_obj = this](auto &&PH1, auto &&PH2) { this_obj->writeCommandHandler(std::forward(PH1), std::forward(PH2)); }); @@ -36,17 +36,17 @@ void BaseClient::writeCommand(std::string &command) { void BaseClient::readCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { if (err) { - on_delete_(this); + onDelete_(this); return; } - command_handler_(std::string(read_buf_, read_buf_ + bytes_transferred - 1), this); + commandHandler_(std::string(readBuf_, readBuf_ + bytes_transferred - 1), this); readCommand(); } std::size_t BaseClient::checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred) { - if (bytes_transferred > 0 && std::string(read_buf_ + bytes_transferred - 1 - std::strlen(END_STR), read_buf_ + bytes_transferred - 1) == std::string(END_STR)) { + if (bytes_transferred > 0 && std::string(readBuf_ + bytes_transferred - 1 - std::strlen(END_STR), readBuf_ + bytes_transferred - 1) == std::string(END_STR)) { return 0; } return 1; @@ -55,7 +55,7 @@ std::size_t BaseClient::checkEndOfRead(const boost::system::error_code &err, std void BaseClient::writeCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { if (err) { - on_delete_(this); + onDelete_(this); } } diff --git a/project/backend/src/DocumentClient.cpp b/project/backend/src/DocumentClient.cpp index cc450da..6258e9d 100644 --- a/project/backend/src/DocumentClient.cpp +++ b/project/backend/src/DocumentClient.cpp @@ -6,7 +6,7 @@ void DocumentClient::afterConnect() { - boost::asio::async_read(sock_, boost::asio::buffer(read_buf_), + boost::asio::async_read(sock_, boost::asio::buffer(readBuf_), boost::bind(&DocumentClient::checkEndOfRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), boost::bind(&DocumentClient::checkAuthToken, this, boost::asio::placeholders::error, @@ -17,21 +17,21 @@ void DocumentClient::afterConnect() { DocumentClient::DocumentClient(boost::asio::io_service &service, std::function command_handler, std::function on_delete, std::function check_auth_token) : BaseClient(service, std::move(command_handler), std::move(on_delete)), - check_auth_token_(std::move(check_auth_token)) { + checkAuthToken_(std::move(check_auth_token)) { } void DocumentClient::checkAuthToken(const boost::system::error_code &err, std::size_t bytes_transferred) { if (err) { - on_delete_(this); + onDelete_(this); return; } - std::string auth_token(read_buf_, read_buf_ + bytes_transferred - 1); - if (check_auth_token_(auth_token)) { + std::string auth_token(readBuf_, readBuf_ + bytes_transferred - 1); + if (checkAuthToken_(auth_token)) { authSuccess(); } else { - on_delete_(this); + onDelete_(this); // TODO: возможно сделать какую-нибудь отправку о неуспешной авторизации return; } @@ -39,8 +39,8 @@ void DocumentClient::checkAuthToken(const boost::system::error_code &err, std::s void DocumentClient::authSuccess() { - std::strcpy(send_buf_, "auth success"); - sock_.async_write_some(boost::asio::buffer(send_buf_, strlen("auth success")), + std::strcpy(sendBuf_, "auth success"); + sock_.async_write_some(boost::asio::buffer(sendBuf_, strlen("auth success")), [this_obj = this](auto &&PH1, auto &&PH2) { this_obj->authSuccessHandler(PH1, PH2); }); @@ -49,18 +49,18 @@ void DocumentClient::authSuccess() { void DocumentClient::authSuccessHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { if (err) { - on_delete_(this); + onDelete_(this); return; } - is_auth = true; + isAuth_ = true; readCommand(); } void DocumentClient::authError() { - std::strcpy(send_buf_, "auth error"); - sock_.async_write_some(boost::asio::buffer(send_buf_, strlen("auth error")), + std::strcpy(sendBuf_, "auth error"); + sock_.async_write_some(boost::asio::buffer(sendBuf_, strlen("auth error")), [this_obj = this](auto &&PH1, auto &&PH2) { this_obj->authErrorHandler(PH1, PH2); }); @@ -68,5 +68,5 @@ void DocumentClient::authError() { void DocumentClient::authErrorHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { - on_delete_(this); + onDelete_(this); } diff --git a/project/backend/src/SharedDocument.cpp b/project/backend/src/SharedDocument.cpp index e02f9c9..80bf7fb 100644 --- a/project/backend/src/SharedDocument.cpp +++ b/project/backend/src/SharedDocument.cpp @@ -10,7 +10,7 @@ SharedDocument::SharedDocument() : acceptor_(service_), port_(start_since_port++ } void SharedDocument::generateAuthToken() { - auth_token_ = "dummy_aboba"; + authToken_ = "dummy_aboba"; } void SharedDocument::startShared() { @@ -39,7 +39,7 @@ void SharedDocument::startShared() { bool SharedDocument::checkAuthToken(std::string &token) { - return token == auth_token_; + return token == authToken_; } @@ -47,7 +47,7 @@ void SharedDocument::startAcceptClients() { std::shared_ptr client(new DocumentClient( service_, [this](std::string command, BaseClient *author) { - return this->sharingCommand(command, author); + return this->commandHandler(command, author); }, [this](BaseClient *client) { return this->deleteClient(client); }, [this](std::string &token) { return this->checkAuthToken(token); })); @@ -58,7 +58,7 @@ void SharedDocument::startAcceptClients() { } -void SharedDocument::sharingCommand(std::string &command, BaseClient *author) { +void SharedDocument::commandHandler(std::string &command, BaseClient *author) { for (auto &client : clients_) { if (&(*client) != author) { client->writeCommand(command); @@ -107,5 +107,9 @@ int SharedDocument::getPort() { std::string SharedDocument::getAuthToken() { - return auth_token_; + return authToken_; +} +SharedDocument::~SharedDocument() { + delete getDocument_; + delete sharingCommand_; } From 4b968befbc5375da41a97a00bb1d5541117f4520 Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Thu, 2 Dec 2021 19:30:56 +0300 Subject: [PATCH 04/15] server is work --- CMakeLists.txt | 2 +- project/backend/include/BaseClient.h | 33 ----- project/backend/include/Connection.h | 36 ++++++ project/backend/include/DocumentClient.h | 29 ----- project/backend/include/IManageCommand.h | 55 ++++++--- project/backend/include/MainServer.h | 21 ++++ project/backend/include/Server.h | 25 ++-- project/backend/include/SharedDocument.h | 53 -------- .../backend/include/SharedDocumentServer.h | 45 +++++++ project/backend/src/BaseClient.cpp | 65 ---------- project/backend/src/Connection.cpp | 81 ++++++++++++ project/backend/src/DocumentClient.cpp | 72 ----------- project/backend/src/IManageCommand.cpp | 58 +++++++++ project/backend/src/MainServer.cpp | 42 +++++++ project/backend/src/Server.cpp | 53 ++++++++ project/backend/src/SharedDocument.cpp | 115 ------------------ project/backend/src/SharedDocumentServer.cpp | 78 ++++++++++++ project/backend/src/main.cpp | 9 +- project/backend/unit_tests/main.cpp | 8 +- 19 files changed, 475 insertions(+), 405 deletions(-) delete mode 100644 project/backend/include/BaseClient.h create mode 100644 project/backend/include/Connection.h delete mode 100644 project/backend/include/DocumentClient.h create mode 100644 project/backend/include/MainServer.h delete mode 100644 project/backend/include/SharedDocument.h create mode 100644 project/backend/include/SharedDocumentServer.h delete mode 100644 project/backend/src/BaseClient.cpp create mode 100644 project/backend/src/Connection.cpp delete mode 100644 project/backend/src/DocumentClient.cpp create mode 100644 project/backend/src/IManageCommand.cpp create mode 100644 project/backend/src/MainServer.cpp create mode 100644 project/backend/src/Server.cpp delete mode 100644 project/backend/src/SharedDocument.cpp create mode 100644 project/backend/src/SharedDocumentServer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dac74d..d5722c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,6 @@ link_directories(${Boost_LIBRARY_DIR}) include_directories(project/backend/include ${Boost_INCLUDE_DIR}) aux_source_directory(project/backend/src SRC) -add_executable(boost_asio_async_server ${SRC} project/backend/include/BaseClient.h project/backend/src/BaseClient.cpp project/backend/include/DocumentClient.h project/backend/src/DocumentClient.cpp project/backend/include/Server.h project/backend/include/Settings.h project/backend/unit_tests/main.cpp project/backend/include/IManageCommand.h) +add_executable(boost_asio_async_server ${SRC} project/backend/src/IManageCommand.cpp) target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES}) diff --git a/project/backend/include/BaseClient.h b/project/backend/include/BaseClient.h deleted file mode 100644 index ee14fda..0000000 --- a/project/backend/include/BaseClient.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -#include "Settings.h" - -class BaseClient { -public: - BaseClient(boost::asio::io_service &service, - std::function command_handler, - std::function on_delete); - - boost::asio::ip::tcp::socket &getSock(); - - virtual void afterConnect(); - - virtual void writeCommand(std::string &command); - -protected: - virtual void readCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred); - - virtual std::size_t checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred); - - virtual void writeCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred); - - virtual void readCommand(); - - boost::asio::ip::tcp::socket sock_; - std::function commandHandler_; - std::function onDelete_; - char readBuf_[BUFFER_LENGTH]; - char sendBuf_[BUFFER_LENGTH]; -}; \ No newline at end of file diff --git a/project/backend/include/Connection.h b/project/backend/include/Connection.h new file mode 100644 index 0000000..37f5758 --- /dev/null +++ b/project/backend/include/Connection.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "Settings.h" + +class Connection : public std::enable_shared_from_this { +public: + Connection(boost::asio::io_context &service, + std::function, std::string &&)> on_read_cb, + std::function)> on_delete_cb = {}); + + boost::asio::ip::tcp::socket &getSock(); + + void afterConnect(); + + void write(std::string &command, std::function)> onWriteCb = {}); + + void stop(); + +private: + void read(); + + void readHandler(const boost::system::error_code &err, std::size_t bytes_transferred); + + std::size_t checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred); + + void writeHandler(const boost::system::error_code &err, std::size_t bytes_transferred, + std::function)> onWriteCb); + + boost::asio::ip::tcp::socket sock_; + std::function, std::string &&)> onReadCb_; + std::function)> onDeleteCb_; + char readBuf_[BUFFER_LENGTH]; + char sendBuf_[BUFFER_LENGTH]; +}; \ No newline at end of file diff --git a/project/backend/include/DocumentClient.h b/project/backend/include/DocumentClient.h deleted file mode 100644 index 39d17be..0000000 --- a/project/backend/include/DocumentClient.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "BaseClient.h" - -class DocumentClient : public BaseClient { -public: - DocumentClient(boost::asio::io_service &service, - std::function command_handler, - std::function on_delete, - std::function check_auth_token); - - void afterConnect() override; - -private: - void checkAuthToken(const boost::system::error_code &err, std::size_t bytes_transferred); - - void authSuccess(); - - void authSuccessHandler(const boost::system::error_code &err, std::size_t bytes_transferred); - - void authError(); - - void authErrorHandler(const boost::system::error_code &err, std::size_t bytes_transferred); - - - std::function checkAuthToken_; - - bool isAuth_ = false; -}; \ No newline at end of file diff --git a/project/backend/include/IManageCommand.h b/project/backend/include/IManageCommand.h index 033cf8d..59b27e3 100644 --- a/project/backend/include/IManageCommand.h +++ b/project/backend/include/IManageCommand.h @@ -1,73 +1,90 @@ #pragma once #include "Settings.h" -#include "SharedDocument.h" +#include "SharedDocumentServer.h" +#include "Connection.h" -enum { +typedef enum { SHARING_COMMAND = 0x01, - GET_DOCUMENT = 0x02 + GET_DOCUMENT = 0x02, + CREATE_DOCUMENT = 0x04 } command_t; class IManageCommand { public: - IManageCommand(command_t type_command, SharedDocument *document); + IManageCommand(command_t type_command); + + IManageCommand(command_t type_command, std::vector> *connection); IManageCommand(const IManageCommand &) = delete; IManageCommand &operator=(IManageCommand &) = delete; - virtual bool do_command(std::string &command, DocumentClient *author); + virtual bool do_command(std::string &command, std::shared_ptr author); ~IManageCommand(); protected: - IManageCommand() : letter_(NULL); - - - SharedDocument *document_; + IManageCommand() : letter_(NULL) {} private: IManageCommand *letter_; + std::optional> *> connections_; }; class GetDocument : public IManageCommand { public: - virtual bool do_command(std::string &command, DocumentClient *author); + virtual bool do_command(std::string &command, std::shared_ptr author) override; GetDocument(const GetDocument &) = delete; GetDocument &operator=(GetDocument &) = delete; - ~GetDocument(); + ~GetDocument() = default; private: friend class IManageCommand; - GetDocument(); + GetDocument() = default; + /* void getDocumentFromClient(); void handleGetDocumentFromClient(const boost::system::error_code &err, std::size_t bytes_transferred); - void sendDocumentToNewClients(); - - char[MAX_DOCUMENT_LENGTH] document_; + void sendDocumentToNewClients(std::string &document); +*/ + char document_[MAX_DOCUMENT_LENGTH]; - std::vector> clientsToGetDocument_; + std::vector> clientsToGetDocument_; }; class SharingCommand : public IManageCommand { public: - virtual bool do_command(std::string &command, DocumentClient *author); + virtual bool do_command(std::string &command, std::shared_ptr author) override; SharingCommand(const SharingCommand &) = delete; SharingCommand &operator=(SharingCommand &) = delete; - ~SharingCommand(); + ~SharingCommand() = default; private: friend class IManageCommand; - SharingCommand(); + SharingCommand() = default; +}; + +class CreateNewDocumentCommand : public IManageCommand { +public: + virtual bool do_command(std::string &command, std::shared_ptr author) override; + + ~CreateNewDocumentCommand(); + +private: + friend class IManageCommand; + + CreateNewDocumentCommand() = default; + + std::vector> sharedDocuments_; }; \ No newline at end of file diff --git a/project/backend/include/MainServer.h b/project/backend/include/MainServer.h new file mode 100644 index 0000000..806452e --- /dev/null +++ b/project/backend/include/MainServer.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Server.h" +#include "Connection.h" +#include "IManageCommand.h" + +class MainServer { +public: + MainServer(int port, int countThreads); + void runServer(); + +private: + void handleAcceptConnection(std::shared_ptr connection); + + void onReadCb(std::shared_ptr, std::string &&command); + + boost::asio::io_context service_; + Server server_; + IManageCommand *createNewDocumentCommand_; + int countThreads_; +}; \ No newline at end of file diff --git a/project/backend/include/Server.h b/project/backend/include/Server.h index 5d0f3ba..ca8fea3 100644 --- a/project/backend/include/Server.h +++ b/project/backend/include/Server.h @@ -1,26 +1,31 @@ +#pragma once + #include -#include "BaseClient.h" +#include "Connection.h" #include "Settings.h" -class Server { +class Server : public std::enable_shared_from_this { public: - Server(int port); + Server(int port, std::function)> onAcceptCb, + std::function, std::string &&)> onReadCb, + boost::asio::io_context &service, + std::function)> = {}); void runServer(); -private: - void startAcceptClients(); - - void handleAcceptClient(std::shared_ptr client, boost::system::error_code &err); + int getPort(); - void writeDocumentPortToClient(); +private: + void startAcceptConnections(); - void handleWriteDocumentPort(const boost::system::error_code &err, std::size_t bytes_transferred); + void handleAcceptConnection(std::shared_ptr connection, const boost::system::error_code &err); - boost::asio::io_service service_; boost::asio::ip::tcp::acceptor acceptor_; int port_; + std::function)> onAcceptCb_; + std::function, std::string &&)> onReadCb_; + std::function)> onDeleteCb_; char readBuf_[BUFFER_LENGTH]; char sendBuf_[BUFFER_LENGTH]; }; \ No newline at end of file diff --git a/project/backend/include/SharedDocument.h b/project/backend/include/SharedDocument.h deleted file mode 100644 index ac57b1e..0000000 --- a/project/backend/include/SharedDocument.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "DocumentClient.h" -#include "Settings.h" - -class IManageCommand; - -class SharedDocument { -public: - static int start_since_port;// начиная с какого порта начнут создаваться объекты SharedDocument - - SharedDocument(); - - void startShared(); - - int getPort(); - - std::string getAuthToken(); - - ~SharedDocument(); - -private: - void generateAuthToken(); - - void startAcceptClients(); - - void handleAcceptClient(std::shared_ptr client, const boost::system::error_code &err); - - void deleteClient(BaseClient *client); - - bool checkAuthToken(std::string &token); - - void commandHandler(std::string &command, BaseClient *author); - - void run(); - - boost::asio::io_service service_; - std::string authToken_; - boost::asio::ip::tcp::acceptor acceptor_; - int port_; - std::vector> clients_; - - IManageCommand *sharingCommand_; - IManageCommand *getDocument_; - - - std::vector> toGetDocument_; - char document_[MAX_DOCUMENT_LENGTH]; -}; diff --git a/project/backend/include/SharedDocumentServer.h b/project/backend/include/SharedDocumentServer.h new file mode 100644 index 0000000..7283933 --- /dev/null +++ b/project/backend/include/SharedDocumentServer.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +#include "Server.h" +#include "Connection.h" +#include "Settings.h" + +class IManageCommand; + +class SharedDocumentServer { +public: + static int start_since_port; // начиная с какого порта начнут создаваться объекты SharedDocumentServer + + SharedDocumentServer(boost::asio::io_context &service); + + void startShared(); + + int getPort(); + + std::string getAuthToken(); + + ~SharedDocumentServer(); + +private: + void generateAuthToken(); + + void handleAcceptConnection(std::shared_ptr connection); + + void onDeleteConnection(std::shared_ptr connection); + + bool checkAuthToken(std::string &token); + + void onReadCb(std::shared_ptr author, std::string &&command); + + + Server server_; + std::string authToken_; + std::vector> connections_; + + IManageCommand *sharingCommand_; + IManageCommand *getDocument_; +}; diff --git a/project/backend/src/BaseClient.cpp b/project/backend/src/BaseClient.cpp deleted file mode 100644 index 60655c1..0000000 --- a/project/backend/src/BaseClient.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -#include "BaseClient.h" - - -BaseClient::BaseClient(boost::asio::io_service &service, std::function command_handler, - std::function on_delete) : sock_(service), - commandHandler_(std::move(command_handler)), - onDelete_(std::move(on_delete)) { -} - - -void BaseClient::afterConnect() { - readCommand(); -} - -void BaseClient::readCommand() { - boost::asio::async_read(sock_, boost::asio::buffer(readBuf_), - boost::bind(&BaseClient::checkEndOfRead, this, boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred), - boost::bind(&BaseClient::readCommandHandler, this, boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); -} - -void BaseClient::writeCommand(std::string &command) { - for (int i = 0; i < command.length(); ++i) { - sendBuf_[i] = command[i]; - } - sock_.async_write_some(boost::asio::buffer(sendBuf_, command.length()), [this_obj = this](auto &&PH1, auto &&PH2) { - this_obj->writeCommandHandler(std::forward(PH1), - std::forward(PH2)); - }); -} - - -void BaseClient::readCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { - if (err) { - onDelete_(this); - return; - } - - commandHandler_(std::string(readBuf_, readBuf_ + bytes_transferred - 1), this); - readCommand(); -} - - -std::size_t BaseClient::checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred) { - if (bytes_transferred > 0 && std::string(readBuf_ + bytes_transferred - 1 - std::strlen(END_STR), readBuf_ + bytes_transferred - 1) == std::string(END_STR)) { - return 0; - } - return 1; -} - - -void BaseClient::writeCommandHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { - if (err) { - onDelete_(this); - } -} - - -boost::asio::ip::tcp::socket &BaseClient::getSock() { - return sock_; -} diff --git a/project/backend/src/Connection.cpp b/project/backend/src/Connection.cpp new file mode 100644 index 0000000..af7b001 --- /dev/null +++ b/project/backend/src/Connection.cpp @@ -0,0 +1,81 @@ +#include +#include +#include + +#include "Connection.h" + +Connection::Connection(boost::asio::io_context &service, std::function, std::string &&)> on_read_cb, + std::function)> on_delete_cb) : sock_(service), + onReadCb_(std::move(on_read_cb)), + onDeleteCb_(std::move(on_delete_cb)) { + +} + + +void Connection::afterConnect() { + read(); +} + +void Connection::read() { + std::cerr << "we are in Connection::read" << std::endl; + boost::asio::async_read(sock_, boost::asio::buffer(readBuf_), + boost::bind(&Connection::checkEndOfRead, shared_from_this(), boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred), + boost::bind(&Connection::readHandler, shared_from_this(), boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void Connection::write(std::string &command, std::function)> onWriteCb) { + for (int i = 0; i < command.length(); ++i) { + sendBuf_[i] = command[i]; + } + sock_.async_write_some(boost::asio::buffer(sendBuf_, command.length()), + boost::bind(&Connection::writeHandler, shared_from_this(), _1, _2, onWriteCb)); +} + + +void Connection::readHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { + if (err) { + if (onDeleteCb_) { + onDeleteCb_(shared_from_this()); + } + return; + } + + std::cerr << "read = " << std::string(readBuf_, readBuf_ + bytes_transferred) << std::endl; + onReadCb_(shared_from_this(), std::string(readBuf_, readBuf_ + bytes_transferred)); + read(); +} + + +std::size_t Connection::checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred) { + if (bytes_transferred > 0 && + std::string(readBuf_ + bytes_transferred - 1 - std::strlen(END_STR), readBuf_ + bytes_transferred - 1) == std::string(END_STR)) { + return 0; + } + return 1; +} + + +void Connection::writeHandler(const boost::system::error_code &err, std::size_t bytes_transferred, + std::function)> onWriteCb) { + if (err) { + if (onDeleteCb_) { + onDeleteCb_(shared_from_this()); + } + return; + } + std::cerr << "we are on Connection::writeHandler" << std::endl; + + if (onWriteCb) { + onWriteCb(shared_from_this()); + } +} + +void Connection::stop() { + sock_.close(); +} + +boost::asio::ip::tcp::socket &Connection::getSock() { + return sock_; +} diff --git a/project/backend/src/DocumentClient.cpp b/project/backend/src/DocumentClient.cpp deleted file mode 100644 index 6258e9d..0000000 --- a/project/backend/src/DocumentClient.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include -#include - -#include "DocumentClient.h" - - -void DocumentClient::afterConnect() { - boost::asio::async_read(sock_, boost::asio::buffer(readBuf_), - boost::bind(&DocumentClient::checkEndOfRead, this, boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred), - boost::bind(&DocumentClient::checkAuthToken, this, boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); -} - - -DocumentClient::DocumentClient(boost::asio::io_service &service, std::function command_handler, - std::function on_delete, - std::function check_auth_token) : BaseClient(service, std::move(command_handler), std::move(on_delete)), - checkAuthToken_(std::move(check_auth_token)) { -} - - -void DocumentClient::checkAuthToken(const boost::system::error_code &err, std::size_t bytes_transferred) { - if (err) { - onDelete_(this); - return; - } - std::string auth_token(readBuf_, readBuf_ + bytes_transferred - 1); - if (checkAuthToken_(auth_token)) { - authSuccess(); - } else { - - onDelete_(this); - // TODO: возможно сделать какую-нибудь отправку о неуспешной авторизации - return; - } -} - - -void DocumentClient::authSuccess() { - std::strcpy(sendBuf_, "auth success"); - sock_.async_write_some(boost::asio::buffer(sendBuf_, strlen("auth success")), - [this_obj = this](auto &&PH1, auto &&PH2) { - this_obj->authSuccessHandler(PH1, PH2); - }); -} - - -void DocumentClient::authSuccessHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { - if (err) { - onDelete_(this); - return; - } - isAuth_ = true; - - readCommand(); -} - - -void DocumentClient::authError() { - std::strcpy(sendBuf_, "auth error"); - sock_.async_write_some(boost::asio::buffer(sendBuf_, strlen("auth error")), - [this_obj = this](auto &&PH1, auto &&PH2) { - this_obj->authErrorHandler(PH1, PH2); - }); -} - - -void DocumentClient::authErrorHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { - onDelete_(this); -} diff --git a/project/backend/src/IManageCommand.cpp b/project/backend/src/IManageCommand.cpp new file mode 100644 index 0000000..87ac90a --- /dev/null +++ b/project/backend/src/IManageCommand.cpp @@ -0,0 +1,58 @@ +#include + +#include "IManageCommand.h" + +IManageCommand::IManageCommand(command_t type_command) { + switch (type_command) { + case GET_DOCUMENT: + letter_ = new GetDocument(); + case SHARING_COMMAND: + letter_ = new SharingCommand(); + case CREATE_DOCUMENT: + letter_ = new CreateNewDocumentCommand(); + } +} + +IManageCommand::IManageCommand(command_t type_command, std::vector> *connection) : IManageCommand( + type_command) { + connections_ = connection; +} + +bool IManageCommand::do_command(std::string &command, std::shared_ptr author) { + letter_->do_command(command, author); + + return true; +} + +IManageCommand::~IManageCommand() { + delete letter_; +} + +bool GetDocument::do_command(std::string &command, std::shared_ptr author) { + std::cerr << "we are in get document" << std::endl; + return true; +} + +bool SharingCommand::do_command(std::string &command, std::shared_ptr author) { + std::cerr << "we are in sharing command" << std::endl; + + return true; +} + +bool CreateNewDocumentCommand::do_command(std::string &command, std::shared_ptr author) { + std::cerr << "we are in create new document" << std::endl; + + std::string response = "nu chto tebe skazatt pro sahalin\r\n"; + author->write(response); + + std::shared_ptr shared_document( + new SharedDocumentServer(static_cast(author->getSock().get_executor().context()))); + sharedDocuments_.push_back(shared_document); + shared_document->startShared(); + + return true; +} + +CreateNewDocumentCommand::~CreateNewDocumentCommand() { + std::cerr << "~CreateNewDocumentCommand()" << std::endl; +} \ No newline at end of file diff --git a/project/backend/src/MainServer.cpp b/project/backend/src/MainServer.cpp new file mode 100644 index 0000000..c6b1192 --- /dev/null +++ b/project/backend/src/MainServer.cpp @@ -0,0 +1,42 @@ +#include "MainServer.h" +#include "IManageCommand.h" + +#include +#include + +MainServer::MainServer(int port, int countThreads) : service_(), server_(port, + [this](std::shared_ptr connection) { + this->handleAcceptConnection(std::move(connection)); + }, + [this](std::shared_ptr connection, + std::string &&command) { + this->onReadCb(std::move(connection), std::move(command)); + }, + service_), + countThreads_(countThreads) { + createNewDocumentCommand_ = new IManageCommand(CREATE_DOCUMENT); +} + +void MainServer::runServer() { + server_.runServer(); + + std::vector threads; + threads.reserve(countThreads_); + for (int i = 0; i < countThreads_; ++i) { + threads.emplace_back([this]() { + service_.run(); + }); + } + + for (auto &thread: threads) { + thread.join(); + } +} + +void MainServer::handleAcceptConnection(std::shared_ptr connection) { + connection->afterConnect(); +} + +void MainServer::onReadCb(std::shared_ptr connection, std::string &&command) { + createNewDocumentCommand_->do_command(command, std::move(connection)); +} diff --git a/project/backend/src/Server.cpp b/project/backend/src/Server.cpp new file mode 100644 index 0000000..24dd4a9 --- /dev/null +++ b/project/backend/src/Server.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +#include "Server.h" + + +Server::Server(int port, std::function)> onAcceptCb, + std::function, std::string &&)> onReadCb, + boost::asio::io_context &service, + std::function)> onDeleteCb) : acceptor_(service), + port_(port), + onAcceptCb_(std::move( + onAcceptCb)), + onReadCb_(std::move( + onReadCb)), + onDeleteCb_(std::move(onDeleteCb)) { + +} + +void Server::runServer() { + std::cerr << "runServer()" << std::endl; + boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port_); + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(1024); + + startAcceptConnections(); +} + +int Server::getPort() { + return port_; +} + +void Server::startAcceptConnections() { + std::shared_ptr connection( + new Connection(static_cast(acceptor_.get_executor().context()), onReadCb_)); + acceptor_.async_accept(connection->getSock(), boost::bind(&Server::handleAcceptConnection, this, + connection, boost::asio::placeholders::error)); + std::cerr << "start accept connections" << std::endl; +} + +void Server::handleAcceptConnection(std::shared_ptr connection, const boost::system::error_code &err) { + if (err) { + startAcceptConnections(); + } + + onAcceptCb_(connection); + startAcceptConnections(); +} + diff --git a/project/backend/src/SharedDocument.cpp b/project/backend/src/SharedDocument.cpp deleted file mode 100644 index 80bf7fb..0000000 --- a/project/backend/src/SharedDocument.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include - -#include "SharedDocument.h" -#include - -SharedDocument::SharedDocument() : acceptor_(service_), port_(start_since_port++) { - generateAuthToken(); -} - -void SharedDocument::generateAuthToken() { - authToken_ = "dummy_aboba"; -} - -void SharedDocument::startShared() { - boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port_); - acceptor_.open(endpoint.protocol()); - acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); - acceptor_.bind(endpoint); - acceptor_.listen(1024); - startAcceptClients(); - - std::cerr << "Start shared on port " << port_ << std::endl; - - service_.run(); - /* - std::vector threads; - threads.reserve(4); - for (int i = 0; i < 4; ++i) { - threads.emplace_back([this] { run(); }); - } - - for (auto &thread : threads) { - thread.join(); - } - */ -} - - -bool SharedDocument::checkAuthToken(std::string &token) { - return token == authToken_; -} - - -void SharedDocument::startAcceptClients() { - std::shared_ptr client(new DocumentClient( - service_, - [this](std::string command, BaseClient *author) { - return this->commandHandler(command, author); - }, - [this](BaseClient *client) { return this->deleteClient(client); }, - [this](std::string &token) { return this->checkAuthToken(token); })); - clients_.push_back(client); - - acceptor_.async_accept(client->getSock(), boost::bind(&SharedDocument::handleAcceptClient, this, client, - boost::asio::placeholders::error)); -} - - -void SharedDocument::commandHandler(std::string &command, BaseClient *author) { - for (auto &client : clients_) { - if (&(*client) != author) { - client->writeCommand(command); - } - } -} - - -void SharedDocument::deleteClient(BaseClient *client) { - auto pos = clients_.begin(); - for (auto &cl : clients_) { - if (&(*cl) == client) { - break; - } - pos++; - } - try { - std::cerr << "delete client" << std::endl; - clients_.erase(pos); - } catch (...) { - } -} - - -void SharedDocument::handleAcceptClient(std::shared_ptr client, const boost::system::error_code &err) { - if (err) { - deleteClient(&(*client)); - std::cerr << "Error while accept client" << std::endl; - return; - } - - std::cerr << "Accept client" << std::endl; - client->afterConnect(); - startAcceptClients(); -} - - -void SharedDocument::run() { - service_.run(); -} - - -int SharedDocument::getPort() { - return port_; -} - - -std::string SharedDocument::getAuthToken() { - return authToken_; -} -SharedDocument::~SharedDocument() { - delete getDocument_; - delete sharingCommand_; -} diff --git a/project/backend/src/SharedDocumentServer.cpp b/project/backend/src/SharedDocumentServer.cpp new file mode 100644 index 0000000..88dfabd --- /dev/null +++ b/project/backend/src/SharedDocumentServer.cpp @@ -0,0 +1,78 @@ +#include +#include +#include + +#include "SharedDocumentServer.h" +#include "IManageCommand.h" +#include + +SharedDocumentServer::SharedDocumentServer(boost::asio::io_context &service) : server_(start_since_port++, [this](std::shared_ptr connection) { + this->handleAcceptConnection(std::move(connection)); + }, [this](std::shared_ptr author, std::string &&command) + { this->onReadCb(std::move(author), std::move(command)); }, + service, + [this](std::shared_ptr connection) { + this->onDeleteConnection(std::move(connection)); + }) { + + generateAuthToken(); + sharingCommand_ = new IManageCommand(SHARING_COMMAND, &connections_); + getDocument_ = new IManageCommand(GET_DOCUMENT, &connections_); +} + +void SharedDocumentServer::generateAuthToken() { + authToken_ = "dummy_aboba"; +} + +void SharedDocumentServer::startShared() { + std::cerr << "startShared()" << std::endl; + server_.runServer(); +} + + +bool SharedDocumentServer::checkAuthToken(std::string &token) { + return token == authToken_; +} + + +void SharedDocumentServer::onReadCb(std::shared_ptr author, std::string &&command) { + std::cout << "We are in onReadCb" << std::endl; + // TODO: возможно переделать логику обработки команд на CommandBus +} + + +void SharedDocumentServer::onDeleteConnection(std::shared_ptr connection) { + auto pos = connections_.begin(); + for (auto &cl: connections_) { + if (*pos == connection) { + break; + } + pos++; + } + try { + std::cerr << "delete client" << std::endl; + (*pos)->stop(); + connections_.erase(pos); + } catch (...) { + } +} + +int SharedDocumentServer::getPort() { + return server_.getPort(); +} + + +std::string SharedDocumentServer::getAuthToken() { + return authToken_; +} + +SharedDocumentServer::~SharedDocumentServer() { + delete getDocument_; + delete sharingCommand_; +} + +void SharedDocumentServer::handleAcceptConnection(std::shared_ptr connection) { + std::cerr << "we are in SharedDocumentServer::handleAcceptConnection" << std::endl; + connections_.push_back(connection); + connection->afterConnect(); +} diff --git a/project/backend/src/main.cpp b/project/backend/src/main.cpp index c4f3705..3d32f49 100644 --- a/project/backend/src/main.cpp +++ b/project/backend/src/main.cpp @@ -1,10 +1,11 @@ #include -#include "SharedDocument.h" +#include "SharedDocumentServer.h" +#include "MainServer.h" -int SharedDocument::start_since_port = 5555; +int SharedDocumentServer::start_since_port = 6070; int main() { - SharedDocument document; - document.startShared(); + MainServer server(8080, 4); + server.runServer(); } \ No newline at end of file diff --git a/project/backend/unit_tests/main.cpp b/project/backend/unit_tests/main.cpp index 53f21c1..5822dd7 100644 --- a/project/backend/unit_tests/main.cpp +++ b/project/backend/unit_tests/main.cpp @@ -6,7 +6,7 @@ #include "Server.h" #include "Settings.h" -#include "SharedDocument.h" +#include "SharedDocumentServer.h" using namespace boost::asio; @@ -37,8 +37,8 @@ class TestServer : public ::testing::Test { class TestSharingDocument : public ::testing::Test { protected: void SetUp() { - SharedDocument::start_since_port = 8001; - document_ = new SharedDocument(); + SharedDocumentServer::start_since_port = 8001; + document_ = new SharedDocumentServer(); document_->startShared(); auth_token_ = document_->getAuthToken(); port_ = document_->getPort(); @@ -48,7 +48,7 @@ class TestSharingDocument : public ::testing::Test { delete document_; } - SharedDocument *document_; + SharedDocumentServer *document_; std::string auth_token_; int port_; io_service service_; From a98d4e118b4cd635c8feb14de5787f3951c1c417 Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Sat, 4 Dec 2021 11:55:23 +0300 Subject: [PATCH 05/15] done command logic --- project/backend/include/IManageCommand.h | 11 +++---- project/backend/include/Server.h | 19 ++++++----- project/backend/src/Connection.cpp | 4 +++ project/backend/src/IManageCommand.cpp | 34 +++++++++++++++++++- project/backend/src/MainServer.cpp | 20 ++++++------ project/backend/src/Server.cpp | 19 ++++------- project/backend/src/SharedDocumentServer.cpp | 30 +++++++++++------ 7 files changed, 92 insertions(+), 45 deletions(-) diff --git a/project/backend/include/IManageCommand.h b/project/backend/include/IManageCommand.h index 59b27e3..34020ff 100644 --- a/project/backend/include/IManageCommand.h +++ b/project/backend/include/IManageCommand.h @@ -27,9 +27,10 @@ class IManageCommand { protected: IManageCommand() : letter_(NULL) {} + std::vector> *connections_ = nullptr; + private: IManageCommand *letter_; - std::optional> *> connections_; }; class GetDocument : public IManageCommand { @@ -47,14 +48,12 @@ class GetDocument : public IManageCommand { GetDocument() = default; - /* + void getDocumentFromClient(); - void handleGetDocumentFromClient(const boost::system::error_code &err, std::size_t bytes_transferred); + void handleGetDocumentFromClient(std::shared_ptr &connection); - void sendDocumentToNewClients(std::string &document); -*/ - char document_[MAX_DOCUMENT_LENGTH]; + void sendDocumentToNewClients(std::string &&document); std::vector> clientsToGetDocument_; }; diff --git a/project/backend/include/Server.h b/project/backend/include/Server.h index ca8fea3..cf3b860 100644 --- a/project/backend/include/Server.h +++ b/project/backend/include/Server.h @@ -5,12 +5,15 @@ #include "Connection.h" #include "Settings.h" -class Server : public std::enable_shared_from_this { +struct ServerCallbacks { + std::function)> onAcceptCb_; + std::function, std::string &&)> onReadCb_; + std::function)> onDeleteCb_; +}; + +class Server { public: - Server(int port, std::function)> onAcceptCb, - std::function, std::string &&)> onReadCb, - boost::asio::io_context &service, - std::function)> = {}); + Server(int port, boost::asio::io_context &service, ServerCallbacks &&callbacks); void runServer(); @@ -23,9 +26,9 @@ class Server : public std::enable_shared_from_this { boost::asio::ip::tcp::acceptor acceptor_; int port_; - std::function)> onAcceptCb_; - std::function, std::string &&)> onReadCb_; - std::function)> onDeleteCb_; + + ServerCallbacks callbacks_; + char readBuf_[BUFFER_LENGTH]; char sendBuf_[BUFFER_LENGTH]; }; \ No newline at end of file diff --git a/project/backend/src/Connection.cpp b/project/backend/src/Connection.cpp index af7b001..59ba1fc 100644 --- a/project/backend/src/Connection.cpp +++ b/project/backend/src/Connection.cpp @@ -63,6 +63,9 @@ void Connection::writeHandler(const boost::system::error_code &err, std::size_t if (onDeleteCb_) { onDeleteCb_(shared_from_this()); } + if (onWriteCb) { + onWriteCb(nullptr); + } return; } std::cerr << "we are on Connection::writeHandler" << std::endl; @@ -79,3 +82,4 @@ void Connection::stop() { boost::asio::ip::tcp::socket &Connection::getSock() { return sock_; } + diff --git a/project/backend/src/IManageCommand.cpp b/project/backend/src/IManageCommand.cpp index 87ac90a..0023f4d 100644 --- a/project/backend/src/IManageCommand.cpp +++ b/project/backend/src/IManageCommand.cpp @@ -30,11 +30,43 @@ IManageCommand::~IManageCommand() { bool GetDocument::do_command(std::string &command, std::shared_ptr author) { std::cerr << "we are in get document" << std::endl; + // TODO: здесь сейчас вместо реального парсинга команды заглушки. реальная команда будет приходить в json'е, поэтому поменять + // потом на него + if (command == "get document") { + clientsToGetDocument_.push_back(author); + getDocumentFromClient(); + } else if (command == "document received") { + sendDocumentToNewClients(std::move(command)); + } + return true; } +void GetDocument::getDocumentFromClient() { + std::string give_me_document = "give me document"; + (*(connections_->begin()))->write(give_me_document, + [this](std::shared_ptr connection) { this->handleGetDocumentFromClient(connection); }); +} + +void GetDocument::handleGetDocumentFromClient(std::shared_ptr &connection) { + if (connection == nullptr) { + getDocumentFromClient(); + } +} + +void GetDocument::sendDocumentToNewClients(std::string &&document) { + for (auto &client : clientsToGetDocument_) { + client->write(document); + } +} + bool SharingCommand::do_command(std::string &command, std::shared_ptr author) { std::cerr << "we are in sharing command" << std::endl; + for (auto &connection: *connections_) { + if (author != connection) { + connection->write(command); + } + } return true; } @@ -45,7 +77,7 @@ bool CreateNewDocumentCommand::do_command(std::string &command, std::shared_ptr< std::string response = "nu chto tebe skazatt pro sahalin\r\n"; author->write(response); - std::shared_ptr shared_document( + std::shared_ptr shared_document( new SharedDocumentServer(static_cast(author->getSock().get_executor().context()))); sharedDocuments_.push_back(shared_document); shared_document->startShared(); diff --git a/project/backend/src/MainServer.cpp b/project/backend/src/MainServer.cpp index c6b1192..8444228 100644 --- a/project/backend/src/MainServer.cpp +++ b/project/backend/src/MainServer.cpp @@ -4,15 +4,17 @@ #include #include -MainServer::MainServer(int port, int countThreads) : service_(), server_(port, - [this](std::shared_ptr connection) { - this->handleAcceptConnection(std::move(connection)); - }, - [this](std::shared_ptr connection, - std::string &&command) { - this->onReadCb(std::move(connection), std::move(command)); - }, - service_), +MainServer::MainServer(int port, int countThreads) : service_(), server_(port, service_, + ServerCallbacks{ + [this](std::shared_ptr connection) { + this->handleAcceptConnection(std::move(connection)); + }, + [this](std::shared_ptr connection, + std::string &&command) { + this->onReadCb(std::move(connection), + std::move(command)); + }, {}} +), countThreads_(countThreads) { createNewDocumentCommand_ = new IManageCommand(CREATE_DOCUMENT); } diff --git a/project/backend/src/Server.cpp b/project/backend/src/Server.cpp index 24dd4a9..b41cd34 100644 --- a/project/backend/src/Server.cpp +++ b/project/backend/src/Server.cpp @@ -6,16 +6,9 @@ #include "Server.h" -Server::Server(int port, std::function)> onAcceptCb, - std::function, std::string &&)> onReadCb, - boost::asio::io_context &service, - std::function)> onDeleteCb) : acceptor_(service), - port_(port), - onAcceptCb_(std::move( - onAcceptCb)), - onReadCb_(std::move( - onReadCb)), - onDeleteCb_(std::move(onDeleteCb)) { +Server::Server(int port, boost::asio::io_context &service, ServerCallbacks &&callbacks) : acceptor_(service), + port_(port), + callbacks_(std::move(callbacks)) { } @@ -36,7 +29,7 @@ int Server::getPort() { void Server::startAcceptConnections() { std::shared_ptr connection( - new Connection(static_cast(acceptor_.get_executor().context()), onReadCb_)); + new Connection(static_cast(acceptor_.get_executor().context()), callbacks_.onReadCb_)); acceptor_.async_accept(connection->getSock(), boost::bind(&Server::handleAcceptConnection, this, connection, boost::asio::placeholders::error)); std::cerr << "start accept connections" << std::endl; @@ -47,7 +40,9 @@ void Server::handleAcceptConnection(std::shared_ptr connection, cons startAcceptConnections(); } - onAcceptCb_(connection); + callbacks_.onAcceptCb_(connection); startAcceptConnections(); } + + diff --git a/project/backend/src/SharedDocumentServer.cpp b/project/backend/src/SharedDocumentServer.cpp index 88dfabd..05b6f03 100644 --- a/project/backend/src/SharedDocumentServer.cpp +++ b/project/backend/src/SharedDocumentServer.cpp @@ -6,14 +6,21 @@ #include "IManageCommand.h" #include -SharedDocumentServer::SharedDocumentServer(boost::asio::io_context &service) : server_(start_since_port++, [this](std::shared_ptr connection) { - this->handleAcceptConnection(std::move(connection)); - }, [this](std::shared_ptr author, std::string &&command) - { this->onReadCb(std::move(author), std::move(command)); }, - service, - [this](std::shared_ptr connection) { - this->onDeleteConnection(std::move(connection)); - }) { +SharedDocumentServer::SharedDocumentServer(boost::asio::io_context &service) : server_(start_since_port++, service, + ServerCallbacks{ + [this](std::shared_ptr connection) { + this->handleAcceptConnection( + std::move(connection)); + }, + [this](std::shared_ptr author, + std::string &&command) { + this->onReadCb(std::move(author), + std::move(command)); + }, + [this](std::shared_ptr connection) { + this->onDeleteConnection( + std::move(connection)); + }}) { generateAuthToken(); sharingCommand_ = new IManageCommand(SHARING_COMMAND, &connections_); @@ -37,7 +44,12 @@ bool SharedDocumentServer::checkAuthToken(std::string &token) { void SharedDocumentServer::onReadCb(std::shared_ptr author, std::string &&command) { std::cout << "We are in onReadCb" << std::endl; - // TODO: возможно переделать логику обработки команд на CommandBus + // TODO: тоже стоят заглушки вместо парсинга команд. Переделать на парсинг json'а + if (command == "sharind command") { + sharingCommand_->do_command(command, author); + } else if (command == "get document" || command == "document received") { + getDocument_->do_command(command, author); + } } From 17d418f959fa6244c696865d52128efb7591af9b Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Sat, 4 Dec 2021 12:38:57 +0300 Subject: [PATCH 06/15] refactor file struct --- CMakeLists.txt | 6 +++--- project/{backend => }/include/Connection.h | 0 project/{backend => }/include/IManageCommand.h | 1 - project/{backend => }/include/MainServer.h | 0 project/{backend => }/include/Server.h | 0 project/{backend => }/include/Settings.h | 0 project/{backend => }/include/SharedDocumentServer.h | 0 project/{backend => }/src/Connection.cpp | 0 project/{backend => }/src/IManageCommand.cpp | 0 project/{backend => }/src/MainServer.cpp | 0 project/{backend => }/src/Server.cpp | 0 project/{backend => }/src/SharedDocumentServer.cpp | 0 project/{backend => }/src/main.cpp | 0 project/{backend => }/unit_tests/main.cpp | 0 14 files changed, 3 insertions(+), 4 deletions(-) rename project/{backend => }/include/Connection.h (100%) rename project/{backend => }/include/IManageCommand.h (99%) rename project/{backend => }/include/MainServer.h (100%) rename project/{backend => }/include/Server.h (100%) rename project/{backend => }/include/Settings.h (100%) rename project/{backend => }/include/SharedDocumentServer.h (100%) rename project/{backend => }/src/Connection.cpp (100%) rename project/{backend => }/src/IManageCommand.cpp (100%) rename project/{backend => }/src/MainServer.cpp (100%) rename project/{backend => }/src/Server.cpp (100%) rename project/{backend => }/src/SharedDocumentServer.cpp (100%) rename project/{backend => }/src/main.cpp (100%) rename project/{backend => }/unit_tests/main.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5722c9..046b1d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ find_package(Boost 1.40.0 REQUIRED system) find_package(Boost COMPONENTS log log_setup REQUIRED) link_directories(${Boost_LIBRARY_DIR}) -include_directories(project/backend/include ${Boost_INCLUDE_DIR}) -aux_source_directory(project/backend/src SRC) -add_executable(boost_asio_async_server ${SRC} project/backend/src/IManageCommand.cpp) +include_directories(project/include ${Boost_INCLUDE_DIR}) +aux_source_directory(project/src SRC) +add_executable(boost_asio_async_server ${SRC}) target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES}) diff --git a/project/backend/include/Connection.h b/project/include/Connection.h similarity index 100% rename from project/backend/include/Connection.h rename to project/include/Connection.h diff --git a/project/backend/include/IManageCommand.h b/project/include/IManageCommand.h similarity index 99% rename from project/backend/include/IManageCommand.h rename to project/include/IManageCommand.h index 34020ff..4906926 100644 --- a/project/backend/include/IManageCommand.h +++ b/project/include/IManageCommand.h @@ -48,7 +48,6 @@ class GetDocument : public IManageCommand { GetDocument() = default; - void getDocumentFromClient(); void handleGetDocumentFromClient(std::shared_ptr &connection); diff --git a/project/backend/include/MainServer.h b/project/include/MainServer.h similarity index 100% rename from project/backend/include/MainServer.h rename to project/include/MainServer.h diff --git a/project/backend/include/Server.h b/project/include/Server.h similarity index 100% rename from project/backend/include/Server.h rename to project/include/Server.h diff --git a/project/backend/include/Settings.h b/project/include/Settings.h similarity index 100% rename from project/backend/include/Settings.h rename to project/include/Settings.h diff --git a/project/backend/include/SharedDocumentServer.h b/project/include/SharedDocumentServer.h similarity index 100% rename from project/backend/include/SharedDocumentServer.h rename to project/include/SharedDocumentServer.h diff --git a/project/backend/src/Connection.cpp b/project/src/Connection.cpp similarity index 100% rename from project/backend/src/Connection.cpp rename to project/src/Connection.cpp diff --git a/project/backend/src/IManageCommand.cpp b/project/src/IManageCommand.cpp similarity index 100% rename from project/backend/src/IManageCommand.cpp rename to project/src/IManageCommand.cpp diff --git a/project/backend/src/MainServer.cpp b/project/src/MainServer.cpp similarity index 100% rename from project/backend/src/MainServer.cpp rename to project/src/MainServer.cpp diff --git a/project/backend/src/Server.cpp b/project/src/Server.cpp similarity index 100% rename from project/backend/src/Server.cpp rename to project/src/Server.cpp diff --git a/project/backend/src/SharedDocumentServer.cpp b/project/src/SharedDocumentServer.cpp similarity index 100% rename from project/backend/src/SharedDocumentServer.cpp rename to project/src/SharedDocumentServer.cpp diff --git a/project/backend/src/main.cpp b/project/src/main.cpp similarity index 100% rename from project/backend/src/main.cpp rename to project/src/main.cpp diff --git a/project/backend/unit_tests/main.cpp b/project/unit_tests/main.cpp similarity index 100% rename from project/backend/unit_tests/main.cpp rename to project/unit_tests/main.cpp From 45293858adf3707c1ac92d504205a953f1653660 Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Sun, 5 Dec 2021 15:12:11 +0300 Subject: [PATCH 07/15] added ServerConnection class to interact with the server from the application side --- CMakeLists.txt | 2 +- .../include/ServerConnection.h | 65 +++++++++++++++ .../ServerConnection/src/ServerConnection.cpp | 80 +++++++++++++++++++ project/include/Connection.h | 7 ++ project/src/Connection.cpp | 8 ++ project/src/SharedDocumentServer.cpp | 2 +- 6 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 project/ServerConnection/include/ServerConnection.h create mode 100644 project/ServerConnection/src/ServerConnection.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 046b1d9..960b3ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,6 @@ link_directories(${Boost_LIBRARY_DIR}) include_directories(project/include ${Boost_INCLUDE_DIR}) aux_source_directory(project/src SRC) -add_executable(boost_asio_async_server ${SRC}) +add_executable(boost_asio_async_server ${SRC} project/ServerConnection/include/ServerConnection.h project/ServerConnection/src/ServerConnection.cpp) target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES}) diff --git a/project/ServerConnection/include/ServerConnection.h b/project/ServerConnection/include/ServerConnection.h new file mode 100644 index 0000000..6b0da1d --- /dev/null +++ b/project/ServerConnection/include/ServerConnection.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#define BUFFER_LENGTH 1024 +#define END_STR "\r\n" + + +/* + * Структура с колбеками, которые будут вызываться после успешного чтения и записи соответственно. + */ +struct ServerConnectionCallbacks { + std::function onReadCb; + std::function onWriteCb; +}; + +class ServerConnection { +public: + ServerConnection(std::string &&url, int port, ServerConnectionCallbacks &&callbacks); + + /* + * Выполняет подключение к серверу и начинает бесконечный цикл чтения сообщений с сервера. + * После того как прочитали сообщение, вызовется onReadCb из ServerConnectionCallbacks. + */ + void start(); + + /** + * Пишет серверу какое-либо сообщение. После записи вызовет onWriteCb, переданный в структуре ServerConnectionCallbacks + * @param message само сообщение + */ + void write(std::string &&message); + +private: + void connectionToServer(); + + void read(); + + void readHandler(boost::system::error_code &err, size_t bytes_transferred); + + std::size_t checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred); + + void writeHandler(boost::system::error_code &err); + + void run_ioc(); + + std::string serverUrl_; + int serverPort_; + + boost::asio::io_context service_; + boost::asio::ip::tcp::socket socket_; + ServerConnectionCallbacks callbacks_; + + std::mutex writeMutex_; + std::condition_variable writeCv_; + std::atomic canWrite_ = true; + + char readBuf_[BUFFER_LENGTH]; + char sendBuf_[BUFFER_LENGTH]; +}; + diff --git a/project/ServerConnection/src/ServerConnection.cpp b/project/ServerConnection/src/ServerConnection.cpp new file mode 100644 index 0000000..9caa738 --- /dev/null +++ b/project/ServerConnection/src/ServerConnection.cpp @@ -0,0 +1,80 @@ +#include + +#include "../include/ServerConnection.h" + +ServerConnection::ServerConnection(std::string &&url, int port, ServerConnectionCallbacks &&callbacks) : socket_(service_), + serverUrl_(std::move(url)), + serverPort_(port), + callbacks_(std::move(callbacks)) { +} + +void ServerConnection::connectionToServer() { + boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string(serverUrl_), serverPort_); + socket_.connect(ep); + read(); +} + +void ServerConnection::read() { + boost::asio::async_read(socket_, boost::asio::buffer(readBuf_), + [this](boost::system::error_code err, std::size_t bytes_transferred) -> size_t { + return this->checkEndOfRead(err, bytes_transferred); + }, [this](boost::system::error_code err, std::size_t bytes_transferred) { + this->readHandler(err, bytes_transferred); + }); +} + +void ServerConnection::readHandler(boost::system::error_code &err, size_t bytes_transferred) { + if (err) { + return; + } + + if (callbacks_.onReadCb) { + callbacks_.onReadCb(std::string(readBuf_, readBuf_ + bytes_transferred)); + } + + read(); +} + +void ServerConnection::run_ioc() { + service_.run(); +} + +void ServerConnection::start() { + connectionToServer(); + run_ioc(); +} + +void ServerConnection::write(std::string &&message) { + std::unique_lock ulock(writeMutex_); + writeCv_.wait(ulock, [this]() { return bool(canWrite_); }); + canWrite_ = false; + + for (int i = 0; i < message.length(); ++i) { + sendBuf_[i] = message[i]; + } + + boost::asio::async_write(socket_, boost::asio::buffer(sendBuf_, message.length()), [this](boost::system::error_code err) { + this->writeHandler(err); + }); +} + +void ServerConnection::writeHandler(boost::system::error_code &err) { + if (err) { + return; + } + + if (callbacks_.onWriteCb) { + callbacks_.onWriteCb(err); + } + + canWrite_ = true; + writeCv_.notify_one(); +} + +std::size_t ServerConnection::checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred) { + if (bytes_transferred > 0 && + std::string(readBuf_ + bytes_transferred - 1 - std::strlen(END_STR), readBuf_ + bytes_transferred - 1) == std::string(END_STR)) { + return 0; + } + return 1; +} diff --git a/project/include/Connection.h b/project/include/Connection.h index 37f5758..6898b1c 100644 --- a/project/include/Connection.h +++ b/project/include/Connection.h @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include #include "Settings.h" @@ -33,4 +36,8 @@ class Connection : public std::enable_shared_from_this { std::function)> onDeleteCb_; char readBuf_[BUFFER_LENGTH]; char sendBuf_[BUFFER_LENGTH]; + + std::mutex writeMutex_; + std::condition_variable writeCv_; + std::atomic canWrite_ = true; }; \ No newline at end of file diff --git a/project/src/Connection.cpp b/project/src/Connection.cpp index 59ba1fc..b43c4d8 100644 --- a/project/src/Connection.cpp +++ b/project/src/Connection.cpp @@ -26,6 +26,11 @@ void Connection::read() { } void Connection::write(std::string &command, std::function)> onWriteCb) { + // функция write может быть вызвана из разных потоков, поэтому блокируем ее до тех пор, пока другой поток не закончит запись + std::unique_lock ulock(writeMutex_); + writeCv_.wait(ulock, [this](){ return bool(canWrite_);}); + canWrite_ = false; + for (int i = 0; i < command.length(); ++i) { sendBuf_[i] = command[i]; } @@ -73,6 +78,9 @@ void Connection::writeHandler(const boost::system::error_code &err, std::size_t if (onWriteCb) { onWriteCb(shared_from_this()); } + + canWrite_ = true; + writeCv_.notify_one(); } void Connection::stop() { diff --git a/project/src/SharedDocumentServer.cpp b/project/src/SharedDocumentServer.cpp index 05b6f03..7053d85 100644 --- a/project/src/SharedDocumentServer.cpp +++ b/project/src/SharedDocumentServer.cpp @@ -62,7 +62,7 @@ void SharedDocumentServer::onDeleteConnection(std::shared_ptr connec pos++; } try { - std::cerr << "delete client" << std::endl; + std::cerr << "delete ServerConnection" << std::endl; (*pos)->stop(); connections_.erase(pos); } catch (...) { From 8353e749a6835dd16fecd9056ab918a0da86d502 Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Thu, 9 Dec 2021 01:34:46 +0300 Subject: [PATCH 08/15] some client-server --- CMakeLists.txt | 7 +- about_json_api.md | 91 ++++++++++++++++++++++++++ project/include/CommandConstructor.h | 22 +++++++ project/include/Connection.h | 8 +++ project/include/IManageCommand.h | 21 ++++-- project/include/SharedDocumentServer.h | 5 +- project/src/CommandConstructor.cpp | 51 +++++++++++++++ project/src/Connection.cpp | 27 ++++++-- project/src/IManageCommand.cpp | 75 +++++++++++++++------ project/src/MainServer.cpp | 9 ++- project/src/SharedDocumentServer.cpp | 28 +++++--- 11 files changed, 299 insertions(+), 45 deletions(-) create mode 100644 about_json_api.md create mode 100644 project/include/CommandConstructor.h create mode 100644 project/src/CommandConstructor.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 960b3ab..7f348e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,11 @@ set(CMAKE_CXX_STANDARD 20) find_package(Boost 1.40.0 REQUIRED system) find_package(Boost COMPONENTS log log_setup REQUIRED) +find_package(nlohmann_json 3.2.0 REQUIRED) link_directories(${Boost_LIBRARY_DIR}) include_directories(project/include ${Boost_INCLUDE_DIR}) -aux_source_directory(project/src SRC) -add_executable(boost_asio_async_server ${SRC} project/ServerConnection/include/ServerConnection.h project/ServerConnection/src/ServerConnection.cpp) +aux_source_directory(project/src SRCR) +add_executable(boost_asio_async_server ${SRCR}) -target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES}) +target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES} nlohmann_json::nlohmann_json) diff --git a/about_json_api.md b/about_json_api.md new file mode 100644 index 0000000..44e37f0 --- /dev/null +++ b/about_json_api.md @@ -0,0 +1,91 @@ +# Всевозможные сценарии комманд + +Клиент, чтобы расшарить документ: +```json +{ + "target": "sharing_document" +} +``` + +Сервер в ответ: +```json +{ + "status": "OK", // или "FAIL" + "target": "sharing_document" // для указания цели, на которую пришел ответ + "auth_token": "dummy_aboba", + "address": "127.0.0.1", + "port": 5555 +} +``` + +
+ +Клиент, чтобы подключиться к документу: +```json +{ + "target": "auth", + "auth_token": "dummy_aboba" +} +``` + +Сервер в ответ: +```json +{ + "status": "OK" // или FAIL + "target": "auth" +} +``` + +
+ +Клиент, чтобы запросить после подключения копию документа +```json +{ + "target": "get_document" +} +``` +Сервер клиенту, у которого есть копия документа: +```json +{ + "target": "get_document" +} +``` +Клиент в ответ на запрос сервера на документ: +```json +{ + "status": "OK", // или FAIL, тогда поле document не обязательно + "target": "get_document", + "document": "some document code" +} +``` + +Сервер изначальному клиенту, который запрашивал документ: +```json +{ + "status": "OK", // или FAIL, тогда поле document не обязательно + "target": "get_document", + "document": "some document code" +} +``` + +
+ +Клиент, чтобы расшарить команду: +```json +{ + "target": "sharing_command", + "command": "some command code" +} +``` + +Сервер в ответ: решительное ничего + +Сервер всем остальным клиентам, подключенным к документу: +```json +{ + "target": "sharing_command", + "command": "some command code" +} +``` + +Клиенты в ответ после получения команды: решительное ничего \ No newline at end of file diff --git a/project/include/CommandConstructor.h b/project/include/CommandConstructor.h new file mode 100644 index 0000000..22c4264 --- /dev/null +++ b/project/include/CommandConstructor.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +using json = nlohmann::json; + +class CommandConstructor { +public: + static json sharingDocumentClient(); + + static json sharingDocumentServer(std::string &&status, std::string &&auth_token, std::string &&address, int port); + + static json authClient(std::string &&auth_token); + + static json authServer(std::string &&status); + + static json getDocumentClient(); + + static json getDocumentServer(std::string &&status, std::string &&document); + + static json sharingCommandClient(std::string &&command_); +}; \ No newline at end of file diff --git a/project/include/Connection.h b/project/include/Connection.h index 6898b1c..74c5834 100644 --- a/project/include/Connection.h +++ b/project/include/Connection.h @@ -21,6 +21,12 @@ class Connection : public std::enable_shared_from_this { void stop(); + void setAuth(bool value); + + bool getAuth(); + + ~Connection(); + private: void read(); @@ -40,4 +46,6 @@ class Connection : public std::enable_shared_from_this { std::mutex writeMutex_; std::condition_variable writeCv_; std::atomic canWrite_ = true; + + bool isAuth_ = false; }; \ No newline at end of file diff --git a/project/include/IManageCommand.h b/project/include/IManageCommand.h index 4906926..d4c8e2d 100644 --- a/project/include/IManageCommand.h +++ b/project/include/IManageCommand.h @@ -1,9 +1,13 @@ #pragma once +#include + #include "Settings.h" #include "SharedDocumentServer.h" #include "Connection.h" +using json = nlohmann::json; + typedef enum { SHARING_COMMAND = 0x01, GET_DOCUMENT = 0x02, @@ -20,7 +24,7 @@ class IManageCommand { IManageCommand &operator=(IManageCommand &) = delete; - virtual bool do_command(std::string &command, std::shared_ptr author); + virtual bool do_command(json &command, std::shared_ptr author); ~IManageCommand(); @@ -35,7 +39,7 @@ class IManageCommand { class GetDocument : public IManageCommand { public: - virtual bool do_command(std::string &command, std::shared_ptr author) override; + virtual bool do_command(json &command, std::shared_ptr author) override; GetDocument(const GetDocument &) = delete; @@ -59,7 +63,7 @@ class GetDocument : public IManageCommand { class SharingCommand : public IManageCommand { public: - virtual bool do_command(std::string &command, std::shared_ptr author) override; + virtual bool do_command(json &command, std::shared_ptr author) override; SharingCommand(const SharingCommand &) = delete; @@ -75,7 +79,7 @@ class SharingCommand : public IManageCommand { class CreateNewDocumentCommand : public IManageCommand { public: - virtual bool do_command(std::string &command, std::shared_ptr author) override; + virtual bool do_command(json &command, std::shared_ptr author) override; ~CreateNewDocumentCommand(); @@ -85,4 +89,13 @@ class CreateNewDocumentCommand : public IManageCommand { CreateNewDocumentCommand() = default; std::vector> sharedDocuments_; +}; + +class DocumentCommandBus { +public: + explicit DocumentCommandBus(std::vector> *connection); + bool do_command(std::string &&command, std::shared_ptr author); +private: + IManageCommand sharingCommand_; + IManageCommand getDocumentCommand_; }; \ No newline at end of file diff --git a/project/include/SharedDocumentServer.h b/project/include/SharedDocumentServer.h index 7283933..9f5c657 100644 --- a/project/include/SharedDocumentServer.h +++ b/project/include/SharedDocumentServer.h @@ -8,7 +8,7 @@ #include "Connection.h" #include "Settings.h" -class IManageCommand; +class DocumentCommandBus; class SharedDocumentServer { public: @@ -40,6 +40,5 @@ class SharedDocumentServer { std::string authToken_; std::vector> connections_; - IManageCommand *sharingCommand_; - IManageCommand *getDocument_; + DocumentCommandBus *documentCommandBus_; }; diff --git a/project/src/CommandConstructor.cpp b/project/src/CommandConstructor.cpp new file mode 100644 index 0000000..62a1ba4 --- /dev/null +++ b/project/src/CommandConstructor.cpp @@ -0,0 +1,51 @@ +#include "CommandConstructor.h" + +json CommandConstructor::sharingDocumentClient() { + static json command = {{"target", "sharing_document"}}; + return command; +} + +json CommandConstructor::sharingDocumentServer(std::string &&status, std::string &&auth_token, std::string &&address, int port) { + json command = {{"status", status}, + {"target", "sharing_document"}, + {"auth_token", auth_token}, + {"address", address}, + {"port", port}}; + + return command; +} + +json CommandConstructor::authClient(std::string &&auth_token) { + json command = {{"target", "auth"}, + {"auth_token", auth_token}}; + + return command; +} + +json CommandConstructor::authServer(std::string &&status) { + json command = {{"status", status}, + {"target", "auth"}}; + + return command; +} + +json CommandConstructor::getDocumentClient() { + static json command = {{"target", "get_document"}}; + + return command; +} + +json CommandConstructor::getDocumentServer(std::string &&status, std::string &&document) { + json command = {{"status", status}, + {"target", "get_document"}, + {"document", document}}; + + return command; +} + +json CommandConstructor::sharingCommandClient(std::string &&command_) { + json command = {{"target", "sharing_command"}, + {"command", command_}}; + + return command; +} diff --git a/project/src/Connection.cpp b/project/src/Connection.cpp index b43c4d8..80273a1 100644 --- a/project/src/Connection.cpp +++ b/project/src/Connection.cpp @@ -11,6 +11,9 @@ Connection::Connection(boost::asio::io_context &service, std::function)> onWriteCb) { // функция write может быть вызвана из разных потоков, поэтому блокируем ее до тех пор, пока другой поток не закончит запись std::unique_lock ulock(writeMutex_); - writeCv_.wait(ulock, [this](){ return bool(canWrite_);}); + writeCv_.wait(ulock, [this]() { return bool(canWrite_); }); canWrite_ = false; for (int i = 0; i < command.length(); ++i) { sendBuf_[i] = command[i]; } - sock_.async_write_some(boost::asio::buffer(sendBuf_, command.length()), + std::string end_str(END_STR); + for (int i = command.length(); i < command.length() + end_str.length(); ++i) { + sendBuf_[i] = end_str[i - command.length()]; + } + + sock_.async_write_some(boost::asio::buffer(sendBuf_, command.length() + end_str.length()), boost::bind(&Connection::writeHandler, shared_from_this(), _1, _2, onWriteCb)); } void Connection::readHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { if (err) { + std::cerr << "Connection::readHandler error" << std::endl; if (onDeleteCb_) { onDeleteCb_(shared_from_this()); } @@ -54,8 +63,10 @@ void Connection::readHandler(const boost::system::error_code &err, std::size_t b std::size_t Connection::checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred) { - if (bytes_transferred > 0 && - std::string(readBuf_ + bytes_transferred - 1 - std::strlen(END_STR), readBuf_ + bytes_transferred - 1) == std::string(END_STR)) { + if (bytes_transferred > 2 && + readBuf_[bytes_transferred - 1] == '\n' && readBuf_[bytes_transferred - 2] == '\r') + //std::string(readBuf_ + bytes_transferred - 1 - std::strlen(END_STR), readBuf_ + bytes_transferred - 1) == std::string(END_STR)) + { return 0; } return 1; @@ -91,3 +102,11 @@ boost::asio::ip::tcp::socket &Connection::getSock() { return sock_; } +void Connection::setAuth(bool) { + isAuth_ = true; +} + +bool Connection::getAuth() { + return isAuth_; +} + diff --git a/project/src/IManageCommand.cpp b/project/src/IManageCommand.cpp index 0023f4d..9135e41 100644 --- a/project/src/IManageCommand.cpp +++ b/project/src/IManageCommand.cpp @@ -1,6 +1,10 @@ #include +#include #include "IManageCommand.h" +#include "CommandConstructor.h" + +using json = nlohmann::json; IManageCommand::IManageCommand(command_t type_command) { switch (type_command) { @@ -18,7 +22,7 @@ IManageCommand::IManageCommand(command_t type_command, std::vector author) { +bool IManageCommand::do_command(json &command, std::shared_ptr author) { letter_->do_command(command, author); return true; @@ -28,23 +32,25 @@ IManageCommand::~IManageCommand() { delete letter_; } -bool GetDocument::do_command(std::string &command, std::shared_ptr author) { +bool GetDocument::do_command(json &command, std::shared_ptr author) { std::cerr << "we are in get document" << std::endl; - // TODO: здесь сейчас вместо реального парсинга команды заглушки. реальная команда будет приходить в json'е, поэтому поменять - // потом на него - if (command == "get document") { - clientsToGetDocument_.push_back(author); - getDocumentFromClient(); - } else if (command == "document received") { - sendDocumentToNewClients(std::move(command)); + if (command["target"] == "get_document" && !command.contains("status")) { + if (command.contains("status") && command["status"] == "OK") { + sendDocumentToNewClients(std::move(command["document"])); + return true; + } else if (!command.contains("status")) { + clientsToGetDocument_.push_back(author); + getDocumentFromClient(); + return true; + } } - return true; + return false; } void GetDocument::getDocumentFromClient() { - std::string give_me_document = "give me document"; - (*(connections_->begin()))->write(give_me_document, + std::string command_dump = CommandConstructor::getDocumentClient().dump(); + (*(connections_->begin()))->write(command_dump, [this](std::shared_ptr connection) { this->handleGetDocumentFromClient(connection); }); } @@ -55,36 +61,63 @@ void GetDocument::handleGetDocumentFromClient(std::shared_ptr &conne } void GetDocument::sendDocumentToNewClients(std::string &&document) { - for (auto &client : clientsToGetDocument_) { - client->write(document); + std::string command_dump = CommandConstructor::getDocumentServer("OK", std::move(document)).dump(); + for (auto &client: clientsToGetDocument_) { + client->write(command_dump); } } -bool SharingCommand::do_command(std::string &command, std::shared_ptr author) { +bool SharingCommand::do_command(json &command, std::shared_ptr author) { std::cerr << "we are in sharing command" << std::endl; for (auto &connection: *connections_) { if (author != connection) { - connection->write(command); + std::string command_dump = command.dump(); + connection->write(command_dump); } } return true; } -bool CreateNewDocumentCommand::do_command(std::string &command, std::shared_ptr author) { +bool CreateNewDocumentCommand::do_command(json &command, std::shared_ptr author) { std::cerr << "we are in create new document" << std::endl; - std::string response = "nu chto tebe skazatt pro sahalin\r\n"; - author->write(response); - std::shared_ptr shared_document( new SharedDocumentServer(static_cast(author->getSock().get_executor().context()))); sharedDocuments_.push_back(shared_document); shared_document->startShared(); + std::string command_dump = CommandConstructor::sharingDocumentServer("OK", shared_document->getAuthToken(), "127.0.0.1", + shared_document->getPort()).dump(); + author->write(command_dump); + return true; } CreateNewDocumentCommand::~CreateNewDocumentCommand() { std::cerr << "~CreateNewDocumentCommand()" << std::endl; -} \ No newline at end of file +} + +DocumentCommandBus::DocumentCommandBus(std::vector> *connection) : getDocumentCommand_(CREATE_DOCUMENT, + connection), + sharingCommand_(SHARING_COMMAND, + connection) { + +} + +bool DocumentCommandBus::do_command(std::string &&command, std::shared_ptr author) { + try { + auto command_json = json::parse(command); + if (command_json.contains("target")) { + if (command_json["target"] == "sharing_command" && command_json.contains("command")) { + return sharingCommand_.do_command(command_json, author); + } else if (command_json["target"] == "get_document") { + return getDocumentCommand_.do_command(command_json, author); + } + } + return false; + } catch (...) { + return false; + } + +} diff --git a/project/src/MainServer.cpp b/project/src/MainServer.cpp index 8444228..a051c0a 100644 --- a/project/src/MainServer.cpp +++ b/project/src/MainServer.cpp @@ -1,8 +1,12 @@ #include "MainServer.h" #include "IManageCommand.h" +#include #include #include +#include + +using json = nlohmann::json; MainServer::MainServer(int port, int countThreads) : service_(), server_(port, service_, ServerCallbacks{ @@ -40,5 +44,8 @@ void MainServer::handleAcceptConnection(std::shared_ptr connection) } void MainServer::onReadCb(std::shared_ptr connection, std::string &&command) { - createNewDocumentCommand_->do_command(command, std::move(connection)); + auto command_parse = json::parse(command); + if (command_parse["target"] == "sharing_document") { + createNewDocumentCommand_->do_command(command_parse, std::move(connection)); + } } diff --git a/project/src/SharedDocumentServer.cpp b/project/src/SharedDocumentServer.cpp index 7053d85..e1f1cf7 100644 --- a/project/src/SharedDocumentServer.cpp +++ b/project/src/SharedDocumentServer.cpp @@ -4,6 +4,7 @@ #include "SharedDocumentServer.h" #include "IManageCommand.h" +#include "CommandConstructor.h" #include SharedDocumentServer::SharedDocumentServer(boost::asio::io_context &service) : server_(start_since_port++, service, @@ -23,8 +24,7 @@ SharedDocumentServer::SharedDocumentServer(boost::asio::io_context &service) : s }}) { generateAuthToken(); - sharingCommand_ = new IManageCommand(SHARING_COMMAND, &connections_); - getDocument_ = new IManageCommand(GET_DOCUMENT, &connections_); + documentCommandBus_ = new DocumentCommandBus(&connections_); } void SharedDocumentServer::generateAuthToken() { @@ -44,11 +44,22 @@ bool SharedDocumentServer::checkAuthToken(std::string &token) { void SharedDocumentServer::onReadCb(std::shared_ptr author, std::string &&command) { std::cout << "We are in onReadCb" << std::endl; - // TODO: тоже стоят заглушки вместо парсинга команд. Переделать на парсинг json'а - if (command == "sharind command") { - sharingCommand_->do_command(command, author); - } else if (command == "get document" || command == "document received") { - getDocument_->do_command(command, author); + std::cout << command << std::endl; + documentCommandBus_->do_command(std::move(command), author); + auto command_parse = json::parse(command); + if (command_parse["target"] == "auth") { + if (command_parse["auth_token"] == getAuthToken()) { + std::string response_dump = CommandConstructor::authServer("OK").dump(); + author->setAuth(true); + author->write(response_dump); + } else { + std::string response_dump = CommandConstructor::authServer("FAIL").dump(); + author->setAuth(false); + // если пользователь послал не верный аутентификационный токен - удаляем его + author->write(response_dump, [](std::shared_ptr connection) { connection->stop(); }); + } + } else { + documentCommandBus_->do_command(std::move(command), author); } } @@ -79,8 +90,7 @@ std::string SharedDocumentServer::getAuthToken() { } SharedDocumentServer::~SharedDocumentServer() { - delete getDocument_; - delete sharingCommand_; + delete documentCommandBus_; } void SharedDocumentServer::handleAcceptConnection(std::shared_ptr connection) { From 08a455ba539e0a2652b3e0b5f8ed03b3eb079dc8 Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Thu, 9 Dec 2021 16:17:10 +0300 Subject: [PATCH 09/15] some fix --- project/src/Connection.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/project/src/Connection.cpp b/project/src/Connection.cpp index 80273a1..5c7daaf 100644 --- a/project/src/Connection.cpp +++ b/project/src/Connection.cpp @@ -42,6 +42,7 @@ void Connection::write(std::string &command, std::function Date: Thu, 16 Dec 2021 12:57:33 +0300 Subject: [PATCH 11/15] command logic --- project/include/CommandConstructor.h | 2 +- project/include/Settings.h | 2 +- project/src/CommandConstructor.cpp | 7 +++++-- project/src/Connection.cpp | 3 +-- project/src/IManageCommand.cpp | 4 ++++ project/src/MainServer.cpp | 1 + project/src/SharedDocumentServer.cpp | 9 +++++---- 7 files changed, 18 insertions(+), 10 deletions(-) diff --git a/project/include/CommandConstructor.h b/project/include/CommandConstructor.h index 22c4264..fd2f7b2 100644 --- a/project/include/CommandConstructor.h +++ b/project/include/CommandConstructor.h @@ -12,7 +12,7 @@ class CommandConstructor { static json authClient(std::string &&auth_token); - static json authServer(std::string &&status); + static json authServer(std::string &&status, std::string &&token, std::string &&address, int port); static json getDocumentClient(); diff --git a/project/include/Settings.h b/project/include/Settings.h index 1b48218..bf458b4 100644 --- a/project/include/Settings.h +++ b/project/include/Settings.h @@ -1,6 +1,6 @@ #pragma once -#define BUFFER_LENGTH 1024 +#define BUFFER_LENGTH 10000 #define END_STR "\r\n" #define MAX_DOCUMENT_LENGTH 2048 diff --git a/project/src/CommandConstructor.cpp b/project/src/CommandConstructor.cpp index 62a1ba4..ae38d02 100644 --- a/project/src/CommandConstructor.cpp +++ b/project/src/CommandConstructor.cpp @@ -22,9 +22,12 @@ json CommandConstructor::authClient(std::string &&auth_token) { return command; } -json CommandConstructor::authServer(std::string &&status) { +json CommandConstructor::authServer(std::string &&status, std::string &&token, std::string &&address, int port) { json command = {{"status", status}, - {"target", "auth"}}; + {"target", "auth"}, + {"auth_token", token}, + {"port", port}, + {"address", address}}; return command; } diff --git a/project/src/Connection.cpp b/project/src/Connection.cpp index 5c7daaf..b948270 100644 --- a/project/src/Connection.cpp +++ b/project/src/Connection.cpp @@ -42,7 +42,6 @@ void Connection::write(std::string &command, std::functionwrite(command_dump); } @@ -81,6 +82,9 @@ bool SharingCommand::do_command(json &command, std::shared_ptr autho bool CreateNewDocumentCommand::do_command(json &command, std::shared_ptr author) { std::cerr << "we are in create new document" << std::endl; + if (SharedDocumentServer::start_since_port > 6070) { + return false; + } std::shared_ptr shared_document( new SharedDocumentServer(static_cast(author->getSock().get_executor().context()))); diff --git a/project/src/MainServer.cpp b/project/src/MainServer.cpp index a051c0a..582fd4f 100644 --- a/project/src/MainServer.cpp +++ b/project/src/MainServer.cpp @@ -45,6 +45,7 @@ void MainServer::handleAcceptConnection(std::shared_ptr connection) void MainServer::onReadCb(std::shared_ptr connection, std::string &&command) { auto command_parse = json::parse(command); + std::cout << "MainServer::onReadCb, command = " << command << std::endl; if (command_parse["target"] == "sharing_document") { createNewDocumentCommand_->do_command(command_parse, std::move(connection)); } diff --git a/project/src/SharedDocumentServer.cpp b/project/src/SharedDocumentServer.cpp index e1f1cf7..c1b2bbb 100644 --- a/project/src/SharedDocumentServer.cpp +++ b/project/src/SharedDocumentServer.cpp @@ -45,15 +45,16 @@ bool SharedDocumentServer::checkAuthToken(std::string &token) { void SharedDocumentServer::onReadCb(std::shared_ptr author, std::string &&command) { std::cout << "We are in onReadCb" << std::endl; std::cout << command << std::endl; - documentCommandBus_->do_command(std::move(command), author); + //std::string command_cpy = command; + //documentCommandBus_->do_command(std::move(command_cpy), author); auto command_parse = json::parse(command); - if (command_parse["target"] == "auth") { + if (command_parse["target"] == "auth" && !author->getAuth()) { if (command_parse["auth_token"] == getAuthToken()) { - std::string response_dump = CommandConstructor::authServer("OK").dump(); + std::string response_dump = CommandConstructor::authServer("OK", getAuthToken(), std::string("127.0.0.1"), getPort()).dump(); author->setAuth(true); author->write(response_dump); } else { - std::string response_dump = CommandConstructor::authServer("FAIL").dump(); + std::string response_dump = CommandConstructor::authServer("FAIL", getAuthToken(), std::string("127.0.0.1"), getPort()).dump(); author->setAuth(false); // если пользователь послал не верный аутентификационный токен - удаляем его author->write(response_dump, [](std::shared_ptr connection) { connection->stop(); }); From a1a3f87c41c9a40cce1546f0510d5d7d2bb4cb4d Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Thu, 16 Dec 2021 20:15:34 +0300 Subject: [PATCH 12/15] changed boost.asio to boost.beast. add boost.log. fix bugs with sharing command --- CMakeLists.txt | 5 +-- project/include/Connection.h | 9 +++-- project/include/IManageCommand.h | 16 ++++----- project/src/Connection.cpp | 54 +++++++++++++--------------- project/src/IManageCommand.cpp | 30 +++++++++------- project/src/MainServer.cpp | 3 +- project/src/Server.cpp | 2 +- project/src/SharedDocumentServer.cpp | 18 ++++++---- project/src/main.cpp | 1 + 9 files changed, 75 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f348e7..edc1d3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,13 @@ project(boost_asio_async_server) set(CMAKE_CXX_STANDARD 20) find_package(Boost 1.40.0 REQUIRED system) +add_definitions(-DBOOST_LOG_DYN_LINK) find_package(Boost COMPONENTS log log_setup REQUIRED) find_package(nlohmann_json 3.2.0 REQUIRED) link_directories(${Boost_LIBRARY_DIR}) -include_directories(project/include ${Boost_INCLUDE_DIR}) +include_directories(project/include ${Boost_INCLUDE_DIRS}) aux_source_directory(project/src SRCR) add_executable(boost_asio_async_server ${SRCR}) -target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES} nlohmann_json::nlohmann_json) +target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES} nlohmann_json::nlohmann_json Boost::log Boost::log_setup) diff --git a/project/include/Connection.h b/project/include/Connection.h index 74c5834..9c04301 100644 --- a/project/include/Connection.h +++ b/project/include/Connection.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -38,10 +39,14 @@ class Connection : public std::enable_shared_from_this { std::function)> onWriteCb); boost::asio::ip::tcp::socket sock_; + std::function, std::string &&)> onReadCb_; std::function)> onDeleteCb_; - char readBuf_[BUFFER_LENGTH]; - char sendBuf_[BUFFER_LENGTH]; + + boost::beast::flat_buffer buffer_{BUFFER_LENGTH}; + + boost::beast::http::request request_; + boost::beast::http::response response_; std::mutex writeMutex_; std::condition_variable writeCv_; diff --git a/project/include/IManageCommand.h b/project/include/IManageCommand.h index d4c8e2d..a792a41 100644 --- a/project/include/IManageCommand.h +++ b/project/include/IManageCommand.h @@ -16,9 +16,7 @@ typedef enum { class IManageCommand { public: - IManageCommand(command_t type_command); - - IManageCommand(command_t type_command, std::vector> *connection); + IManageCommand(command_t type_command, std::vector> *connection = nullptr); IManageCommand(const IManageCommand &) = delete; @@ -29,9 +27,7 @@ class IManageCommand { ~IManageCommand(); protected: - IManageCommand() : letter_(NULL) {} - - std::vector> *connections_ = nullptr; + IManageCommand() : letter_(nullptr) {} private: IManageCommand *letter_; @@ -50,7 +46,7 @@ class GetDocument : public IManageCommand { private: friend class IManageCommand; - GetDocument() = default; + explicit GetDocument(std::vector> *connections); void getDocumentFromClient(); @@ -59,6 +55,8 @@ class GetDocument : public IManageCommand { void sendDocumentToNewClients(std::string &&document); std::vector> clientsToGetDocument_; + + std::vector> *connections_ = nullptr; }; class SharingCommand : public IManageCommand { @@ -74,7 +72,9 @@ class SharingCommand : public IManageCommand { private: friend class IManageCommand; - SharingCommand() = default; + explicit SharingCommand(std::vector> *connections); + + std::vector> *connections_ = nullptr; }; class CreateNewDocumentCommand : public IManageCommand { diff --git a/project/src/Connection.cpp b/project/src/Connection.cpp index b948270..a09dfc4 100644 --- a/project/src/Connection.cpp +++ b/project/src/Connection.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "Connection.h" @@ -12,7 +13,7 @@ Connection::Connection(boost::asio::io_context &service, std::functionreadHandler(err, bytes_transferred); + }); } void Connection::write(std::string &command, std::function)> onWriteCb) { @@ -34,42 +33,38 @@ void Connection::write(std::string &command, std::functionwriteHandler(err, bytes_transferred, onWriteCb); + }); } void Connection::readHandler(const boost::system::error_code &err, std::size_t bytes_transferred) { if (err) { - std::cerr << "Connection::readHandler error" << std::endl; + std::cout << request_ << std::endl; + BOOST_LOG_TRIVIAL(error) << "Error while read from client"; if (onDeleteCb_) { onDeleteCb_(shared_from_this()); } return; } - onReadCb_(shared_from_this(), std::string(readBuf_, readBuf_ + bytes_transferred)); - memset(readBuf_, 0, bytes_transferred); - read(); -} + onReadCb_(shared_from_this(), request_.body().data()); + request_.clear(); + request_.body().clear(); -std::size_t Connection::checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred) { - if (bytes_transferred > 2 && - readBuf_[bytes_transferred - 1] == '\n' && readBuf_[bytes_transferred - 2] == '\r') - //std::string(readBuf_ + bytes_transferred - 1 - std::strlen(END_STR), readBuf_ + bytes_transferred - 1) == std::string(END_STR)) - { - return 0; - } - return 1; + read(); } @@ -84,7 +79,6 @@ void Connection::writeHandler(const boost::system::error_code &err, std::size_t } return; } - std::cerr << "we are on Connection::writeHandler" << std::endl; if (onWriteCb) { onWriteCb(shared_from_this()); diff --git a/project/src/IManageCommand.cpp b/project/src/IManageCommand.cpp index a4f6f01..0afb7d9 100644 --- a/project/src/IManageCommand.cpp +++ b/project/src/IManageCommand.cpp @@ -1,27 +1,26 @@ #include #include +#include #include "IManageCommand.h" #include "CommandConstructor.h" using json = nlohmann::json; -IManageCommand::IManageCommand(command_t type_command) { +IManageCommand::IManageCommand(command_t type_command, std::vector> *connections) { switch (type_command) { case GET_DOCUMENT: - letter_ = new GetDocument(); + letter_ = new GetDocument(connections); + break; case SHARING_COMMAND: - letter_ = new SharingCommand(); + letter_ = new SharingCommand(connections); + break; case CREATE_DOCUMENT: letter_ = new CreateNewDocumentCommand(); + break; } } -IManageCommand::IManageCommand(command_t type_command, std::vector> *connection) : IManageCommand( - type_command) { - connections_ = connection; -} - bool IManageCommand::do_command(json &command, std::shared_ptr author) { letter_->do_command(command, author); @@ -33,7 +32,6 @@ IManageCommand::~IManageCommand() { } bool GetDocument::do_command(json &command, std::shared_ptr author) { - std::cerr << "we are in get document" << std::endl; if (command["target"] == "get_document" && !command.contains("status")) { if (command.contains("status") && command["status"] == "OK") { sendDocumentToNewClients(std::move(command["document"])); @@ -67,8 +65,15 @@ void GetDocument::sendDocumentToNewClients(std::string &&document) { } } +GetDocument::GetDocument(std::vector> *connections) { + connections_ = connections; +} + +SharingCommand::SharingCommand(std::vector> *connections) { + connections_ = connections; +} + bool SharingCommand::do_command(json &command, std::shared_ptr author) { - std::cerr << "we are in sharing command" << std::endl; for (auto &connection: *connections_) { if (author != connection) { std::cerr << "SharingCommand::do_command()" << std::endl; @@ -81,7 +86,7 @@ bool SharingCommand::do_command(json &command, std::shared_ptr autho } bool CreateNewDocumentCommand::do_command(json &command, std::shared_ptr author) { - std::cerr << "we are in create new document" << std::endl; + BOOST_LOG_TRIVIAL(info) << "Create new document"; if (SharedDocumentServer::start_since_port > 6070) { return false; } @@ -99,10 +104,11 @@ bool CreateNewDocumentCommand::do_command(json &command, std::shared_ptr> *connection) : getDocumentCommand_(CREATE_DOCUMENT, +DocumentCommandBus::DocumentCommandBus(std::vector> *connection) : getDocumentCommand_(GET_DOCUMENT, connection), sharingCommand_(SHARING_COMMAND, connection) { diff --git a/project/src/MainServer.cpp b/project/src/MainServer.cpp index 582fd4f..0108040 100644 --- a/project/src/MainServer.cpp +++ b/project/src/MainServer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using json = nlohmann::json; @@ -40,12 +41,12 @@ void MainServer::runServer() { } void MainServer::handleAcceptConnection(std::shared_ptr connection) { + BOOST_LOG_TRIVIAL(info) << "Accept new client to MainServer"; connection->afterConnect(); } void MainServer::onReadCb(std::shared_ptr connection, std::string &&command) { auto command_parse = json::parse(command); - std::cout << "MainServer::onReadCb, command = " << command << std::endl; if (command_parse["target"] == "sharing_document") { createNewDocumentCommand_->do_command(command_parse, std::move(connection)); } diff --git a/project/src/Server.cpp b/project/src/Server.cpp index b41cd34..0a1ac20 100644 --- a/project/src/Server.cpp +++ b/project/src/Server.cpp @@ -29,7 +29,7 @@ int Server::getPort() { void Server::startAcceptConnections() { std::shared_ptr connection( - new Connection(static_cast(acceptor_.get_executor().context()), callbacks_.onReadCb_)); + new Connection(static_cast(acceptor_.get_executor().context()), callbacks_.onReadCb_, callbacks_.onDeleteCb_)); acceptor_.async_accept(connection->getSock(), boost::bind(&Server::handleAcceptConnection, this, connection, boost::asio::placeholders::error)); std::cerr << "start accept connections" << std::endl; diff --git a/project/src/SharedDocumentServer.cpp b/project/src/SharedDocumentServer.cpp index c1b2bbb..e9adb6b 100644 --- a/project/src/SharedDocumentServer.cpp +++ b/project/src/SharedDocumentServer.cpp @@ -5,7 +5,7 @@ #include "SharedDocumentServer.h" #include "IManageCommand.h" #include "CommandConstructor.h" -#include +#include SharedDocumentServer::SharedDocumentServer(boost::asio::io_context &service) : server_(start_since_port++, service, ServerCallbacks{ @@ -28,11 +28,15 @@ SharedDocumentServer::SharedDocumentServer(boost::asio::io_context &service) : s } void SharedDocumentServer::generateAuthToken() { - authToken_ = "dummy_aboba"; + static std::vector syms = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', '_', '-', '$', '@'}; + static int token_length = 20; + for (int i = 0; i < token_length; ++i) { + authToken_ += syms[rand() % syms.size()]; + } } void SharedDocumentServer::startShared() { - std::cerr << "startShared()" << std::endl; server_.runServer(); } @@ -43,8 +47,7 @@ bool SharedDocumentServer::checkAuthToken(std::string &token) { void SharedDocumentServer::onReadCb(std::shared_ptr author, std::string &&command) { - std::cout << "We are in onReadCb" << std::endl; - std::cout << command << std::endl; + BOOST_LOG_TRIVIAL(info) << "command from user: " << command; //std::string command_cpy = command; //documentCommandBus_->do_command(std::move(command_cpy), author); auto command_parse = json::parse(command); @@ -53,6 +56,7 @@ void SharedDocumentServer::onReadCb(std::shared_ptr author, std::str std::string response_dump = CommandConstructor::authServer("OK", getAuthToken(), std::string("127.0.0.1"), getPort()).dump(); author->setAuth(true); author->write(response_dump); + BOOST_LOG_TRIVIAL(info) << "Connect new client to document"; } else { std::string response_dump = CommandConstructor::authServer("FAIL", getAuthToken(), std::string("127.0.0.1"), getPort()).dump(); author->setAuth(false); @@ -74,7 +78,7 @@ void SharedDocumentServer::onDeleteConnection(std::shared_ptr connec pos++; } try { - std::cerr << "delete ServerConnection" << std::endl; + BOOST_LOG_TRIVIAL(info) << "Delete client connection"; (*pos)->stop(); connections_.erase(pos); } catch (...) { @@ -95,7 +99,7 @@ SharedDocumentServer::~SharedDocumentServer() { } void SharedDocumentServer::handleAcceptConnection(std::shared_ptr connection) { - std::cerr << "we are in SharedDocumentServer::handleAcceptConnection" << std::endl; + BOOST_LOG_TRIVIAL(info) << "Accept new client to document"; connections_.push_back(connection); connection->afterConnect(); } diff --git a/project/src/main.cpp b/project/src/main.cpp index 3d32f49..91e8e73 100644 --- a/project/src/main.cpp +++ b/project/src/main.cpp @@ -6,6 +6,7 @@ int SharedDocumentServer::start_since_port = 6070; int main() { + srand(time(NULL)); MainServer server(8080, 4); server.runServer(); } \ No newline at end of file From 86e25e0efe3ac13498ecc293009807c57827b8cb Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Thu, 16 Dec 2021 21:35:40 +0300 Subject: [PATCH 13/15] some refactor --- CMakeLists.txt | 4 +-- .../include/{IManageCommand.h => Command.h} | 30 +++++++++---------- project/include/Connection.h | 2 -- project/include/MainServer.h | 4 +-- project/include/Settings.h | 6 +--- project/include/SharedDocumentServer.h | 2 +- .../src/{IManageCommand.cpp => Command.cpp} | 10 +++---- project/src/Connection.cpp | 1 - project/src/MainServer.cpp | 4 +-- project/src/Server.cpp | 5 ++-- project/src/SharedDocumentServer.cpp | 10 +++---- 11 files changed, 35 insertions(+), 43 deletions(-) rename project/include/{IManageCommand.h => Command.h} (74%) rename project/src/{IManageCommand.cpp => Command.cpp} (92%) diff --git a/CMakeLists.txt b/CMakeLists.txt index edc1d3f..dd14aa6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ find_package(nlohmann_json 3.2.0 REQUIRED) link_directories(${Boost_LIBRARY_DIR}) include_directories(project/include ${Boost_INCLUDE_DIRS}) -aux_source_directory(project/src SRCR) -add_executable(boost_asio_async_server ${SRCR}) +aux_source_directory(project/src SRC) +add_executable(boost_asio_async_server ${SRC}) target_link_libraries(boost_asio_async_server boost_thread pthread ${BOOST_LIBRARIES} nlohmann_json::nlohmann_json Boost::log Boost::log_setup) diff --git a/project/include/IManageCommand.h b/project/include/Command.h similarity index 74% rename from project/include/IManageCommand.h rename to project/include/Command.h index a792a41..e6235fa 100644 --- a/project/include/IManageCommand.h +++ b/project/include/Command.h @@ -14,26 +14,26 @@ typedef enum { CREATE_DOCUMENT = 0x04 } command_t; -class IManageCommand { +class Command { public: - IManageCommand(command_t type_command, std::vector> *connection = nullptr); + Command(command_t type_command, std::vector> *connection = nullptr); - IManageCommand(const IManageCommand &) = delete; + Command(const Command &) = delete; - IManageCommand &operator=(IManageCommand &) = delete; + Command &operator=(Command &) = delete; virtual bool do_command(json &command, std::shared_ptr author); - ~IManageCommand(); + ~Command(); protected: - IManageCommand() : letter_(nullptr) {} + Command() : letter_(nullptr) {} private: - IManageCommand *letter_; + Command *letter_; }; -class GetDocument : public IManageCommand { +class GetDocument : public Command { public: virtual bool do_command(json &command, std::shared_ptr author) override; @@ -44,7 +44,7 @@ class GetDocument : public IManageCommand { ~GetDocument() = default; private: - friend class IManageCommand; + friend class Command; explicit GetDocument(std::vector> *connections); @@ -59,7 +59,7 @@ class GetDocument : public IManageCommand { std::vector> *connections_ = nullptr; }; -class SharingCommand : public IManageCommand { +class SharingCommand : public Command { public: virtual bool do_command(json &command, std::shared_ptr author) override; @@ -70,21 +70,21 @@ class SharingCommand : public IManageCommand { ~SharingCommand() = default; private: - friend class IManageCommand; + friend class Command; explicit SharingCommand(std::vector> *connections); std::vector> *connections_ = nullptr; }; -class CreateNewDocumentCommand : public IManageCommand { +class CreateNewDocumentCommand : public Command { public: virtual bool do_command(json &command, std::shared_ptr author) override; ~CreateNewDocumentCommand(); private: - friend class IManageCommand; + friend class Command; CreateNewDocumentCommand() = default; @@ -96,6 +96,6 @@ class DocumentCommandBus { explicit DocumentCommandBus(std::vector> *connection); bool do_command(std::string &&command, std::shared_ptr author); private: - IManageCommand sharingCommand_; - IManageCommand getDocumentCommand_; + Command sharingCommand_; + Command getDocumentCommand_; }; \ No newline at end of file diff --git a/project/include/Connection.h b/project/include/Connection.h index 9c04301..f57e153 100644 --- a/project/include/Connection.h +++ b/project/include/Connection.h @@ -33,8 +33,6 @@ class Connection : public std::enable_shared_from_this { void readHandler(const boost::system::error_code &err, std::size_t bytes_transferred); - std::size_t checkEndOfRead(const boost::system::error_code &err, std::size_t bytes_transferred); - void writeHandler(const boost::system::error_code &err, std::size_t bytes_transferred, std::function)> onWriteCb); diff --git a/project/include/MainServer.h b/project/include/MainServer.h index 806452e..ed9f8a1 100644 --- a/project/include/MainServer.h +++ b/project/include/MainServer.h @@ -2,7 +2,7 @@ #include "Server.h" #include "Connection.h" -#include "IManageCommand.h" +#include "Command.h" class MainServer { public: @@ -16,6 +16,6 @@ class MainServer { boost::asio::io_context service_; Server server_; - IManageCommand *createNewDocumentCommand_; + Command *createNewDocumentCommand_; int countThreads_; }; \ No newline at end of file diff --git a/project/include/Settings.h b/project/include/Settings.h index bf458b4..cb8d6d3 100644 --- a/project/include/Settings.h +++ b/project/include/Settings.h @@ -1,7 +1,3 @@ #pragma once -#define BUFFER_LENGTH 10000 -#define END_STR "\r\n" -#define MAX_DOCUMENT_LENGTH 2048 - -#define AUTH_SUCCESS_COMMAND "auth success" \ No newline at end of file +constexpr int BUFFER_LENGTH = 1024; \ No newline at end of file diff --git a/project/include/SharedDocumentServer.h b/project/include/SharedDocumentServer.h index 9f5c657..86981e0 100644 --- a/project/include/SharedDocumentServer.h +++ b/project/include/SharedDocumentServer.h @@ -31,7 +31,7 @@ class SharedDocumentServer { void onDeleteConnection(std::shared_ptr connection); - bool checkAuthToken(std::string &token); + bool checkAuthToken(std::string &&token); void onReadCb(std::shared_ptr author, std::string &&command); diff --git a/project/src/IManageCommand.cpp b/project/src/Command.cpp similarity index 92% rename from project/src/IManageCommand.cpp rename to project/src/Command.cpp index 0afb7d9..083ad34 100644 --- a/project/src/IManageCommand.cpp +++ b/project/src/Command.cpp @@ -2,12 +2,12 @@ #include #include -#include "IManageCommand.h" +#include "Command.h" #include "CommandConstructor.h" using json = nlohmann::json; -IManageCommand::IManageCommand(command_t type_command, std::vector> *connections) { +Command::Command(command_t type_command, std::vector> *connections) { switch (type_command) { case GET_DOCUMENT: letter_ = new GetDocument(connections); @@ -21,13 +21,13 @@ IManageCommand::IManageCommand(command_t type_command, std::vector author) { +bool Command::do_command(json &command, std::shared_ptr author) { letter_->do_command(command, author); return true; } -IManageCommand::~IManageCommand() { +Command::~Command() { delete letter_; } @@ -104,8 +104,6 @@ bool CreateNewDocumentCommand::do_command(json &command, std::shared_ptr> *connection) : getDocumentCommand_(GET_DOCUMENT, diff --git a/project/src/Connection.cpp b/project/src/Connection.cpp index a09dfc4..b5270fd 100644 --- a/project/src/Connection.cpp +++ b/project/src/Connection.cpp @@ -51,7 +51,6 @@ void Connection::write(std::string &command, std::function #include @@ -21,7 +21,7 @@ MainServer::MainServer(int port, int countThreads) : service_(), server_(port, s }, {}} ), countThreads_(countThreads) { - createNewDocumentCommand_ = new IManageCommand(CREATE_DOCUMENT); + createNewDocumentCommand_ = new Command(CREATE_DOCUMENT); } void MainServer::runServer() { diff --git a/project/src/Server.cpp b/project/src/Server.cpp index 0a1ac20..4eb540b 100644 --- a/project/src/Server.cpp +++ b/project/src/Server.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "Server.h" @@ -13,7 +14,7 @@ Server::Server(int port, boost::asio::io_context &service, ServerCallbacks &&cal } void Server::runServer() { - std::cerr << "runServer()" << std::endl; + BOOST_LOG_TRIVIAL(info) << "Server run"; boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port_); acceptor_.open(endpoint.protocol()); acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); @@ -32,7 +33,7 @@ void Server::startAcceptConnections() { new Connection(static_cast(acceptor_.get_executor().context()), callbacks_.onReadCb_, callbacks_.onDeleteCb_)); acceptor_.async_accept(connection->getSock(), boost::bind(&Server::handleAcceptConnection, this, connection, boost::asio::placeholders::error)); - std::cerr << "start accept connections" << std::endl; + BOOST_LOG_TRIVIAL(info) << "Start accept connections"; } void Server::handleAcceptConnection(std::shared_ptr connection, const boost::system::error_code &err) { diff --git a/project/src/SharedDocumentServer.cpp b/project/src/SharedDocumentServer.cpp index e9adb6b..4374e52 100644 --- a/project/src/SharedDocumentServer.cpp +++ b/project/src/SharedDocumentServer.cpp @@ -3,7 +3,7 @@ #include #include "SharedDocumentServer.h" -#include "IManageCommand.h" +#include "Command.h" #include "CommandConstructor.h" #include @@ -41,7 +41,7 @@ void SharedDocumentServer::startShared() { } -bool SharedDocumentServer::checkAuthToken(std::string &token) { +bool SharedDocumentServer::checkAuthToken(std::string &&token) { return token == authToken_; } @@ -52,18 +52,18 @@ void SharedDocumentServer::onReadCb(std::shared_ptr author, std::str //documentCommandBus_->do_command(std::move(command_cpy), author); auto command_parse = json::parse(command); if (command_parse["target"] == "auth" && !author->getAuth()) { - if (command_parse["auth_token"] == getAuthToken()) { + if (checkAuthToken(command_parse["auth_token"])) { std::string response_dump = CommandConstructor::authServer("OK", getAuthToken(), std::string("127.0.0.1"), getPort()).dump(); author->setAuth(true); author->write(response_dump); BOOST_LOG_TRIVIAL(info) << "Connect new client to document"; } else { - std::string response_dump = CommandConstructor::authServer("FAIL", getAuthToken(), std::string("127.0.0.1"), getPort()).dump(); + std::string response_dump = CommandConstructor::authServer("FAIL", "", std::string("127.0.0.1"), getPort()).dump(); author->setAuth(false); // если пользователь послал не верный аутентификационный токен - удаляем его author->write(response_dump, [](std::shared_ptr connection) { connection->stop(); }); } - } else { + } else if (author->getAuth()) { documentCommandBus_->do_command(std::move(command), author); } } From 0e68c2cf298a846e19b9ce9980fb7efcd6ab07f1 Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Sun, 19 Dec 2021 20:23:06 +0300 Subject: [PATCH 14/15] some fix bugs --- project/src/Command.cpp | 16 +++++++--------- project/src/SharedDocumentServer.cpp | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/project/src/Command.cpp b/project/src/Command.cpp index 083ad34..f3a1c94 100644 --- a/project/src/Command.cpp +++ b/project/src/Command.cpp @@ -32,13 +32,13 @@ Command::~Command() { } bool GetDocument::do_command(json &command, std::shared_ptr author) { - if (command["target"] == "get_document" && !command.contains("status")) { - if (command.contains("status") && command["status"] == "OK") { - sendDocumentToNewClients(std::move(command["document"])); + if (command["target"] == "get_document") { + if (command.contains("status") && command["status"] == "OK") { // если пришел документ от одного из пользователей + sendDocumentToNewClients(std::move(command["document"])); // рассылаем его всем нуждающимся return true; - } else if (!command.contains("status")) { - clientsToGetDocument_.push_back(author); - getDocumentFromClient(); + } else if (!command.contains("status")) { // если пришел запрос на получение документа + clientsToGetDocument_.push_back(author); // добавляем автора запроса в вектор тех, кому нужен документ + getDocumentFromClient(); // и запрашиваем документ у одного из участников return true; } } @@ -63,6 +63,7 @@ void GetDocument::sendDocumentToNewClients(std::string &&document) { for (auto &client: clientsToGetDocument_) { client->write(command_dump); } + clientsToGetDocument_.clear(); } GetDocument::GetDocument(std::vector> *connections) { @@ -87,9 +88,6 @@ bool SharingCommand::do_command(json &command, std::shared_ptr autho bool CreateNewDocumentCommand::do_command(json &command, std::shared_ptr author) { BOOST_LOG_TRIVIAL(info) << "Create new document"; - if (SharedDocumentServer::start_since_port > 6070) { - return false; - } std::shared_ptr shared_document( new SharedDocumentServer(static_cast(author->getSock().get_executor().context()))); diff --git a/project/src/SharedDocumentServer.cpp b/project/src/SharedDocumentServer.cpp index 4374e52..4048df4 100644 --- a/project/src/SharedDocumentServer.cpp +++ b/project/src/SharedDocumentServer.cpp @@ -28,7 +28,7 @@ SharedDocumentServer::SharedDocumentServer(boost::asio::io_context &service) : s } void SharedDocumentServer::generateAuthToken() { - static std::vector syms = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + static const std::vector syms = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_', '-', '$', '@'}; static int token_length = 20; for (int i = 0; i < token_length; ++i) { From 45dfd7a03080267dabb6bd67c9fc221dfd01618d Mon Sep 17 00:00:00 2001 From: Dmitriy Ilyin Date: Tue, 21 Dec 2021 16:27:43 +0300 Subject: [PATCH 15/15] some fix --- project/include/Command.h | 4 ++-- project/include/Settings.h | 2 +- project/src/Command.cpp | 22 ++++++++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/project/include/Command.h b/project/include/Command.h index e6235fa..40624e1 100644 --- a/project/include/Command.h +++ b/project/include/Command.h @@ -48,9 +48,9 @@ class GetDocument : public Command { explicit GetDocument(std::vector> *connections); - void getDocumentFromClient(); + void getDocumentFromClient(const std::shared_ptr& author); - void handleGetDocumentFromClient(std::shared_ptr &connection); + void handleGetDocumentFromClient(std::shared_ptr &connection, const std::shared_ptr& author); void sendDocumentToNewClients(std::string &&document); diff --git a/project/include/Settings.h b/project/include/Settings.h index cb8d6d3..b4a14a0 100644 --- a/project/include/Settings.h +++ b/project/include/Settings.h @@ -1,3 +1,3 @@ #pragma once -constexpr int BUFFER_LENGTH = 1024; \ No newline at end of file +constexpr int BUFFER_LENGTH = 10000; \ No newline at end of file diff --git a/project/src/Command.cpp b/project/src/Command.cpp index f3a1c94..880b310 100644 --- a/project/src/Command.cpp +++ b/project/src/Command.cpp @@ -38,7 +38,7 @@ bool GetDocument::do_command(json &command, std::shared_ptr author) return true; } else if (!command.contains("status")) { // если пришел запрос на получение документа clientsToGetDocument_.push_back(author); // добавляем автора запроса в вектор тех, кому нужен документ - getDocumentFromClient(); // и запрашиваем документ у одного из участников + getDocumentFromClient(author); // и запрашиваем документ у одного из участников return true; } } @@ -46,15 +46,25 @@ bool GetDocument::do_command(json &command, std::shared_ptr author) return false; } -void GetDocument::getDocumentFromClient() { +void GetDocument::getDocumentFromClient(const std::shared_ptr& author) { std::string command_dump = CommandConstructor::getDocumentClient().dump(); - (*(connections_->begin()))->write(command_dump, - [this](std::shared_ptr connection) { this->handleGetDocumentFromClient(connection); }); + if (!connections_->empty()) { + auto it = connections_->begin(); + while (*it == author) { + it++; + } + if (it != connections_->end()) { + (*(connections_->begin()))->write(command_dump, + [this, author](std::shared_ptr connection) { + this->handleGetDocumentFromClient(connection, author); + }); + } + } } -void GetDocument::handleGetDocumentFromClient(std::shared_ptr &connection) { +void GetDocument::handleGetDocumentFromClient(std::shared_ptr &connection, const std::shared_ptr& author) { if (connection == nullptr) { - getDocumentFromClient(); + getDocumentFromClient(author); } }