From a543568e1d0a16436cc6ec205f9cb592c6ad53d0 Mon Sep 17 00:00:00 2001 From: IlushaShurupov Date: Wed, 19 Jul 2023 23:52:07 +0300 Subject: [PATCH] Restructure --- CommandLine/private/CommandLine.cpp | 2 +- Storage/CMakeLists.txt | 3 + Storage/applications/CMakeLists.txt | 12 +- Storage/applications/Client.cpp | 119 +++++++--------- Storage/applications/Server.cpp | 134 ++++++------------ Storage/private/LocalStorage.cpp | 2 +- Storage/private/RemoteStorage.cpp | 0 .../{SystemHandle.cpp => SystemAPIFile.cpp} | 2 +- Storage/private/SystemAPINet.cpp | 130 +++++++++++++++++ Storage/private/SystemHandle.hpp | 19 --- Storage/public/RemoteStorage.hpp | 5 +- Storage/public/SystemAPI.hpp | 51 +++++++ 12 files changed, 289 insertions(+), 190 deletions(-) create mode 100644 Storage/private/RemoteStorage.cpp rename Storage/private/{SystemHandle.cpp => SystemAPIFile.cpp} (97%) create mode 100644 Storage/private/SystemAPINet.cpp delete mode 100644 Storage/private/SystemHandle.hpp create mode 100644 Storage/public/SystemAPI.hpp diff --git a/CommandLine/private/CommandLine.cpp b/CommandLine/private/CommandLine.cpp index 77bfa2e..24d56cb 100644 --- a/CommandLine/private/CommandLine.cpp +++ b/CommandLine/private/CommandLine.cpp @@ -4,7 +4,7 @@ using namespace tp; static ModuleManifest* sModuleDependencies[] = { &gModuleTokenizer, &gModuleStorage, nullptr }; -ModuleManifest tp::gModuleStorage = ModuleManifest("CommandLine", nullptr, nullptr, sModuleDependencies); +ModuleManifest tp::gModuleCommandLine = ModuleManifest("CommandLine", nullptr, nullptr, sModuleDependencies); const char* regexSpace = "\n|\t| |\r"; const char* regexFalse = "N|n|(False)|(false)"; diff --git a/Storage/CMakeLists.txt b/Storage/CMakeLists.txt index 33f269a..0d982b1 100644 --- a/Storage/CMakeLists.txt +++ b/Storage/CMakeLists.txt @@ -5,11 +5,14 @@ set(CMAKE_CXX_STANDARD 23) project(Storage) +set(ASIO_INCLUDE ./../Externals/asio/asio/include) + ### ---------------------- Static Library --------------------- ### file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") file(GLOB HEADERS "./public/*.hpp") add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) target_include_directories(${PROJECT_NAME} PUBLIC ./public/) +target_include_directories(${PROJECT_NAME} PRIVATE ${ASIO_INCLUDE}) target_link_libraries(${PROJECT_NAME} PUBLIC Strings) diff --git a/Storage/applications/CMakeLists.txt b/Storage/applications/CMakeLists.txt index b8f171f..dd0142d 100644 --- a/Storage/applications/CMakeLists.txt +++ b/Storage/applications/CMakeLists.txt @@ -3,15 +3,11 @@ cmake_minimum_required(VERSION 3.2) project(Applications) -file(GLOB SOURCES_CLIENT ./Client.cpp) -file(GLOB SOURCES_SERVER ./Server.cpp) - -set(ASIO_INCLUDE ./../../Externals/asio/asio/include) +file(GLOB SOURCES_CLIENT ./Client.cpp ./SystemAPI.cpp) +file(GLOB SOURCES_SERVER ./Server.cpp ./SystemAPI.cpp) add_executable(Client ${SOURCES_CLIENT}) -include_directories(Client ${ASIO_INCLUDE}) -#link_libraries(Client Storage CommandLine) +target_link_libraries(Client Storage CommandLine) add_executable(Server ${SOURCES_SERVER}) -include_directories(Server ${ASIO_INCLUDE}) -#link_libraries(Server Storage CommandLine) +target_link_libraries(Server Storage CommandLine) diff --git a/Storage/applications/Client.cpp b/Storage/applications/Client.cpp index 26409c6..35f1c26 100644 --- a/Storage/applications/Client.cpp +++ b/Storage/applications/Client.cpp @@ -1,81 +1,64 @@ -#include "asio.hpp" +#include "SystemAPI.hpp" -#include -#include -#include +#include "Strings.hpp" -// #include -// #include +#include -constexpr int PORT = 3333; -const char* SERVER_IP = "127.0.0.1"; +using namespace tp; -std::mutex mutex; +class CharClient { -void* readServerBroadcast(void* clientSocketPtr) { - auto socket = ((asio::ip::tcp::socket*)clientSocketPtr); + typedef void* (*ThreadFunction)(void *); - while (true) { + Client client; + pthread_mutex_t mutex; - short messageSize; - asio::read(*socket, asio::buffer(&messageSize, 2)); - - mutex.lock(); - - auto message = new char[messageSize + 1]; - message[messageSize] = 0; - - asio::read(*socket, asio::buffer(message, messageSize)); - - std::cerr << "Broadcast : " << message << std::endl; - - delete[] message; - - mutex.unlock(); +public: + CharClient(int port, const char* ip) { + pthread_mutex_unlock(&mutex); + client.connect(ip, port); } - return nullptr; -} + void start() { + // Create a new thread to handle the client + pthread_t threadId; + if (pthread_create(&threadId, nullptr, (ThreadFunction) readServerBroadcast, this)) { + printf("Failed to create thread for client\n"); + return; + } + + // Detach the thread so it can run independently + pthread_detach(threadId); + + while (true) { + const auto length = 1024; + static char message[length]; + + printf(" >> "); + fgets(message, length, stdin); + + if (String::Logic::isEqualLogic(message, "exit")) return; + + pthread_mutex_lock(&mutex); + client.write(message); + pthread_mutex_unlock(&mutex); + } + } + + static void* readServerBroadcast(CharClient* self) { + while (true) { + auto message = self->client.read(); + pthread_mutex_lock(&self->mutex); + printf("Broadcast : %s \n", message); + delete[] message; + pthread_mutex_unlock(&self->mutex); + } + return nullptr; + } +}; int main() { - asio::io_context ioContext; - - // Create a TCP socket - asio::ip::tcp::socket socket(ioContext); - - // Connect to a server - asio::ip::tcp::endpoint endpoint(asio::ip::address::from_string(SERVER_IP), PORT); - socket.connect(endpoint); - - // Create a new thread to handle the client - pthread_t threadId; - if (pthread_create(&threadId, nullptr, readServerBroadcast, (void*) &socket) != 0) { - std::cerr << "Failed to create thread for client" << std::endl; - return 1; - } - - // Detach the thread so it can run independently - pthread_detach(threadId); - - while (true) { - std::string message; - std::cout << " >> "; - std::cin >> message; - - mutex.lock(); - - // Send a message to the server - auto messageSize = (short) message.size(); - asio::write(socket, asio::buffer(&messageSize, 2)); - - // Send a message to the server - asio::write(socket, asio::buffer(message + "\n")); - - mutex.unlock(); - } - - // Close socket - // close(clientSocket); - + CharClient client(5555, "127.0.0.1"); + client.start(); return 0; } diff --git a/Storage/applications/Server.cpp b/Storage/applications/Server.cpp index 99d9fd3..eea79f1 100644 --- a/Storage/applications/Server.cpp +++ b/Storage/applications/Server.cpp @@ -1,140 +1,92 @@ -#include -#include -#include -#include -#include +#include "SystemAPI.hpp" +#include "Strings.hpp" +#include "List.hpp" + #include -class Server { +using namespace tp; + +class ChatServer { struct SharedData { - std::list clients; - std::mutex mutex; + List clients; + pthread_mutex_t mutex; }; SharedData mSharedData; - - //int serverSocket; - int port; + Server server; public: - Server(int port) : port(port) {} - ~Server() { assert(0); } + explicit ChatServer(int port) { + server.start(port); + } + + ~ChatServer() { + DEBUG_ASSERT(false) + } bool start() { - // Create socket - asio::io_context io_context; - asio::ip::tcp::acceptor serverSocket(io_context); - - // Bind socket to port - serverSocket.open(asio::ip::tcp::v4()); - // serverSocket.set_option(asio::ip::tcp::acceptor::reuse_address(true)); - serverSocket.bind(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)); - - // Listen for connections - serverSocket.listen(); - - std::cout << "Server listening on port " << port << std::endl; - - // Start accepting clients while (true) { - // Accept client connection - auto clientSocket = new asio::ip::tcp::socket(io_context); - serverSocket.accept(*clientSocket); + auto clientSocket = server.accept(); // add client - mSharedData.mutex.lock(); - mSharedData.clients.push_back(clientSocket); - mSharedData.mutex.unlock(); + pthread_mutex_lock(&mSharedData.mutex); + mSharedData.clients.pushBack(clientSocket); + pthread_mutex_unlock(&mSharedData.mutex); // Create a new thread to handle the client pthread_t threadId; - if (pthread_create(&threadId, nullptr, handleClient, this) != 0) { - std::cerr << "Failed to create thread for client" << std::endl; + if (pthread_create(&threadId, nullptr, (void* (*)(void*)) handleClient, this)) { + printf("Failed to create thread for client\n"); return false; } // Detach the thread so it can run independently pthread_detach(threadId); } - - // Close server socket - serverSocket.close(); - return true; } - static void* handleClient(void* in) { - auto self = (Server*) in; - + static void* handleClient(ChatServer* self) { // read shared data - current client id - self->mSharedData.mutex.lock(); - auto clientSocket = self->mSharedData.clients.back(); - self->mSharedData.mutex.unlock(); + pthread_mutex_lock(&self->mSharedData.mutex); + auto clientSocket = self->mSharedData.clients.last(); + pthread_mutex_unlock(&self->mSharedData.mutex); MESSAGE: - // wait for a message request1 - short messageSize; - { - auto bytesRead = asio::read(*clientSocket, asio::buffer(&messageSize, 2)); - if (bytesRead == -1) { - std::cerr << "Failed to read from socket" << std::endl; - (*clientSocket).close(); - return nullptr; - } - } - - self->mSharedData.mutex.lock(); - - // Receive client message - auto message = new char[messageSize + 1]; - message[messageSize] = '\0'; - { - auto bytesRead = asio::read(*clientSocket, asio::buffer(message, messageSize)); - if (bytesRead == -1) { - std::cerr << "Failed to read from socket" << std::endl; - memcpy(message, "Cant wanna say something but i cant read", 100); - } - } + // wait for a message request + auto message = Server::read(clientSocket); // Broadcast to all clients - for (auto client: self->mSharedData.clients) { - auto bytesWritten = asio::write(*client, asio::buffer(&messageSize, 2)); - if (bytesWritten == -1) { - std::cerr << "Failed to write to socket" << std::endl; - } - - bytesWritten = write(*client, asio::buffer(message, messageSize)); - if (bytesWritten == -1) { - std::cerr << "Failed to write to socket" << std::endl; - } + for (auto client : self->mSharedData.clients) { + Server::write(client.data(), message); } - auto exit = memcmp(message, "exit", strlen("exit")) == 0; + auto exit = memCompare(message, "exit", 5) == 0; - // Close socket delete[] message; - if (exit) { - (*clientSocket).close(); - self->mSharedData.clients.remove(clientSocket); + // TODO : disconnect + for (auto iter : self->mSharedData.clients) { + if (clientSocket == iter.data()) { + self->mSharedData.clients.removeNode(iter.node()); + break; + } + } } - self->mSharedData.mutex.unlock(); + pthread_mutex_unlock(&self->mSharedData.mutex); - if (exit) { - return nullptr; - } + if (exit) return nullptr; goto MESSAGE; } }; int main() { - Server server(3333); + ChatServer server(5555); server.start(); - return 0; -} \ No newline at end of file +} diff --git a/Storage/private/LocalStorage.cpp b/Storage/private/LocalStorage.cpp index 3410854..b3cfb8b 100644 --- a/Storage/private/LocalStorage.cpp +++ b/Storage/private/LocalStorage.cpp @@ -1,6 +1,6 @@ #include "LocalStorage.hpp" -#include "SystemHandle.hpp" +#include "SystemAPI.hpp" #include diff --git a/Storage/private/RemoteStorage.cpp b/Storage/private/RemoteStorage.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Storage/private/SystemHandle.cpp b/Storage/private/SystemAPIFile.cpp similarity index 97% rename from Storage/private/SystemHandle.cpp rename to Storage/private/SystemAPIFile.cpp index 0c0b664..5278d2f 100644 --- a/Storage/private/SystemHandle.cpp +++ b/Storage/private/SystemAPIFile.cpp @@ -1,4 +1,4 @@ -#include "SystemHandle.hpp" +#include "SystemAPI.hpp" #include diff --git a/Storage/private/SystemAPINet.cpp b/Storage/private/SystemAPINet.cpp new file mode 100644 index 0000000..3106571 --- /dev/null +++ b/Storage/private/SystemAPINet.cpp @@ -0,0 +1,130 @@ +#include "SystemAPI.hpp" + +#include "asio.hpp" + +#include + +using namespace tp; + +class tp::ServerContext { + friend class Server; + + asio::io_context context; + asio::ip::tcp::acceptor socket; + typedef asio::ip::tcp::socket Socket; + + ServerContext() : socket(context) {} + + ~ServerContext() { + context.stop(); + socket.close(); + } +}; + +class tp::ClientContext { + friend Client; + + asio::io_context context; + asio::ip::tcp::socket socket; + +public: + ClientContext() : socket(context) {} + + ~ClientContext() { + context.stop(); + socket.close(); + } +}; + +// --------------------------------------------------------------------------------------- // + +Server::Server() { + mContext = new ServerContext(); +} + +Server::~Server() { + delete mContext; + assert(0); +} + +void Server::start(ualni port) { + mContext->socket.open(asio::ip::tcp::v4()); + mContext->socket.bind(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)); + mContext->socket.listen(); + std::cout << "Server listening on port " << port << std::endl; +} + +Server::Socket Server::accept() { + auto clientSocket = new asio::ip::tcp::socket(mContext->context); + mContext->socket.accept(*clientSocket); + std::cout << "New client accepted "<< std::endl; + return clientSocket; +} + +int1* Server::read(Socket client) { + short messageSize; + if (asio::read(*(ServerContext::Socket*)client, asio::buffer(&messageSize, 2)) == -1) { + std::cerr << "Failed to read from socket" << std::endl; + ((ServerContext::Socket*)client)->close(); + return nullptr; + } + auto message = new char[messageSize + 1]; + message[messageSize] = '\0'; + if (asio::read(*(ServerContext::Socket*)client, asio::buffer(message, messageSize)) == -1) { + std::cerr << "Failed to read from socket" << std::endl; + memcpy(message, "Client wanna say something but i cant read", 100); + } + return message; +} + +void Server::write(Socket client, const char* message) { + auto messageSize = (short) strlen(message); + if (asio::write(*(ServerContext::Socket*)client, asio::buffer(&messageSize, 2)) == -1) { + std::cerr << "Failed to write to socket" << std::endl; + } + if (asio::write(*(ServerContext::Socket*)client, asio::buffer(message, messageSize)) == -1) { + std::cerr << "Failed to write to socket" << std::endl; + } +} + +// --------------------------------------------------------------------------------------- // + +Client::Client() { + mContext = new ClientContext(); +} + +Client::~Client() { + delete mContext; + assert(0); +} + +void Client::connect(const char* IP, ualni PORT) { + asio::ip::tcp::endpoint endpoint(asio::ip::address::from_string(IP), PORT); + mContext->socket.connect(endpoint); +} + +char* Client::read() { + short messageSize; + if (asio::read(mContext->socket, asio::buffer(&messageSize, 2)) == -1) { + std::cerr << "Failed to read from socket" << std::endl; + return nullptr; + } + auto message = new char[messageSize + 1]; + message[messageSize] = '\0'; + if (asio::read(mContext->socket, asio::buffer(message, messageSize)) == -1) { + std::cerr << "Failed to read from socket" << std::endl; + memcpy(message, "Cant wanna say something but i cant read", 100); + } + return message; +} + +void Client::write( const char* message ) { + auto messageSize = (short) strlen(message); + if (asio::write(mContext->socket, asio::buffer(&messageSize, 2)) == -1) { + std::cerr << "Failed to write to socket" << std::endl; + } + if (asio::write(mContext->socket, asio::buffer(message, messageSize)) == -1) { + std::cerr << "Failed to write to socket" << std::endl; + } +} + diff --git a/Storage/private/SystemHandle.hpp b/Storage/private/SystemHandle.hpp deleted file mode 100644 index 17d85c7..0000000 --- a/Storage/private/SystemHandle.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "Common.hpp" - -namespace tp { - class FileSystemHandle { - void* stream; - public: - FileSystemHandle(); - ~FileSystemHandle(); - void open(const char*, bool); - bool isOpen(); - void close(); - void seekp(ualni); - void read(int1*, ualni); - void write(const int1*, ualni); - ualni size(); - }; -} \ No newline at end of file diff --git a/Storage/public/RemoteStorage.hpp b/Storage/public/RemoteStorage.hpp index 7f525be..4a1d13c 100644 --- a/Storage/public/RemoteStorage.hpp +++ b/Storage/public/RemoteStorage.hpp @@ -1,8 +1,10 @@ #pragma once -#include "Storage.hpp" +#include "SystemAPI.hpp" namespace tp { + + /* class Client : public Storage { // same as local storage file but transfers all commands to server }; @@ -11,4 +13,5 @@ namespace tp { // opens local storage and transfers all client command to it // manages multiple clients }; + */ } \ No newline at end of file diff --git a/Storage/public/SystemAPI.hpp b/Storage/public/SystemAPI.hpp new file mode 100644 index 0000000..ff1e681 --- /dev/null +++ b/Storage/public/SystemAPI.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "Common.hpp" + +namespace tp { + class FileSystemHandle { + void* stream; + public: + FileSystemHandle(); + ~FileSystemHandle(); + void open(const char*, bool); + bool isOpen(); + void close(); + void seekp(ualni); + void read(int1*, ualni); + void write(const int1*, ualni); + ualni size(); + }; + + + class ServerContext; + class ClientContext; + + class Server { + ServerContext* mContext; + + public: + typedef void* Socket; + + public: + Server(); + ~Server(); + + void start(ualni port); + Socket accept(); + static int1* read(Socket client); + static void write(Socket client, const int1* message); + }; + + class Client { + ClientContext* mContext; + + public: + Client(); + ~Client(); + + void connect(const int1* IP, ualni PORT); + int1* read(); + void write(const int1* message); + }; +} \ No newline at end of file