From df3767df29368798ed45643c8f3861dfaaf8703a Mon Sep 17 00:00:00 2001 From: IlushaShurupov Date: Tue, 18 Jul 2023 23:36:51 +0300 Subject: [PATCH 1/5] Storage initial --- CMakeLists.txt | 3 +- Storage/CMakeLists.txt | 28 +++++++++ Storage/applications/Client.cpp | 45 ++++++++++++++ Storage/applications/Server.cpp | 97 +++++++++++++++++++++++++++++ Storage/private/LocalStorage.cpp | 76 +++++++++++++++++++++++ Storage/private/Storage.cpp | 9 +++ Storage/private/SystemHandle.cpp | 57 +++++++++++++++++ Storage/private/SystemHandle.hpp | 19 ++++++ Storage/public/LocalStorage.hpp | 98 ++++++++++++++++++++++++++++++ Storage/public/RemoteStorage.hpp | 14 +++++ Storage/public/Storage.hpp | 53 ++++++++++++++++ Storage/tests/TestLocalStorage.cpp | 33 ++++++++++ Storage/tests/Tests.cpp | 19 ++++++ Strings/public/Strings.hpp | 2 +- 14 files changed, 551 insertions(+), 2 deletions(-) create mode 100644 Storage/CMakeLists.txt create mode 100644 Storage/applications/Client.cpp create mode 100644 Storage/applications/Server.cpp create mode 100644 Storage/private/LocalStorage.cpp create mode 100644 Storage/private/Storage.cpp create mode 100644 Storage/private/SystemHandle.cpp create mode 100644 Storage/private/SystemHandle.hpp create mode 100644 Storage/public/LocalStorage.hpp create mode 100644 Storage/public/RemoteStorage.hpp create mode 100644 Storage/public/Storage.hpp create mode 100644 Storage/tests/TestLocalStorage.cpp create mode 100644 Storage/tests/Tests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fd8d46..d731dda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,4 +17,5 @@ add_subdirectory(Math) add_subdirectory(Allocators) add_subdirectory(Strings) add_subdirectory(Tokenizer) -add_subdirectory(CommandLine) \ No newline at end of file +add_subdirectory(CommandLine) +add_subdirectory(Storage) diff --git a/Storage/CMakeLists.txt b/Storage/CMakeLists.txt new file mode 100644 index 0000000..28e593f --- /dev/null +++ b/Storage/CMakeLists.txt @@ -0,0 +1,28 @@ + +cmake_minimum_required(VERSION 3.2) + +set(CMAKE_CXX_STANDARD 23) + +project(Storage) + +### ---------------------- 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_link_libraries(${PROJECT_NAME} PUBLIC Strings) + +### ---------------------- Applications --------------------- ### +add_executable(Server ./applications/Server.cpp) +add_executable(Client ./applications/Client.cpp) +target_link_libraries(Server PUBLIC ${PROJECT_NAME}) +target_link_libraries(Client PUBLIC ${PROJECT_NAME}) + +### -------------------------- Tests -------------------------- ### +enable_testing() +file(GLOB TEST_SOURCES "./tests/*.cpp") +add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) +target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) +add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) + +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib) \ No newline at end of file diff --git a/Storage/applications/Client.cpp b/Storage/applications/Client.cpp new file mode 100644 index 0000000..3f7a622 --- /dev/null +++ b/Storage/applications/Client.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include + +constexpr int PORT = 8080; +constexpr int BUFFER_SIZE = 1024; +const char* SERVER_IP = "127.0.0.1"; + +int main() { + // Create socket + int clientSocket = socket(AF_INET, SOCK_STREAM, 0); + if (clientSocket == -1) { + std::cerr << "Failed to create socket" << std::endl; + return 1; + } + + // Connect to server + sockaddr_in serverAddress{}; + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(PORT); + if (inet_pton(AF_INET, SERVER_IP, &serverAddress.sin_addr) <= 0) { + std::cerr << "Invalid address or address not supported" << std::endl; + return 1; + } + + if (connect(clientSocket, reinterpret_cast(&serverAddress), sizeof(serverAddress)) == -1) { + std::cerr << "Failed to connect to server" << std::endl; + return 1; + } + + // Send message to server + const char* message = "Hello, server!"; + if (write(clientSocket, message, strlen(message)) == -1) { + std::cerr << "Failed to write to socket" << std::endl; + return 1; + } + + // Close socket + close(clientSocket); + + return 0; +} diff --git a/Storage/applications/Server.cpp b/Storage/applications/Server.cpp new file mode 100644 index 0000000..7f508be --- /dev/null +++ b/Storage/applications/Server.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + + +class Server { +public: + Server(int port) : serverSocket(-1), port(port) {} + + bool start() { + // Create socket + serverSocket = socket(AF_INET, SOCK_STREAM, 0); + if (serverSocket == -1) { + std::cerr << "Failed to create socket" << std::endl; + return false; + } + + // Bind socket to port + sockaddr_in serverAddress{}; + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(port); + serverAddress.sin_addr.s_addr = INADDR_ANY; + if (bind(serverSocket, reinterpret_cast(&serverAddress), sizeof(serverAddress)) == -1) { + std::cerr << "Failed to bind socket" << std::endl; + return false; + } + + // Listen for connections + if (listen(serverSocket, 5) == -1) { + std::cerr << "Failed to listen on socket" << std::endl; + return false; + } + + std::cout << "Server listening on port " << port << std::endl; + + // Start accepting clients + while (true) { + // Accept client connection + sockaddr_in clientAddress{}; + socklen_t clientAddressSize = sizeof(clientAddress); + int clientSocket = accept(serverSocket, reinterpret_cast(&clientAddress), &clientAddressSize); + if (clientSocket == -1) { + std::cerr << "Failed to accept client connection" << std::endl; + return false; + } + + // Create a new thread to handle the client + pthread_t threadId; + if (pthread_create(&threadId, nullptr, handleClient, &clientSocket) != 0) { + std::cerr << "Failed to create thread for client" << std::endl; + return false; + } + + // Detach the thread so it can run independently + pthread_detach(threadId); + } + + // Close server socket + close(serverSocket); + + return true; + } + +private: + int serverSocket; + int port; + + static void* handleClient(void* clientSocketPtr) { + int clientSocket = *(reinterpret_cast(clientSocketPtr)); + constexpr int BUFFER_SIZE = 1024; + + // Receive and print client message + char buffer[BUFFER_SIZE]; + ssize_t bytesRead = read(clientSocket, buffer, BUFFER_SIZE - 1); + if (bytesRead == -1) { + std::cerr << "Failed to read from socket" << std::endl; + return nullptr; + } + + buffer[bytesRead] = '\0'; + std::cout << "Received message from client: " << buffer << std::endl; + + // Close socket + close(clientSocket); + + return nullptr; + } +}; + +int main() { + Server server(8080); + server.start(); + + return 0; +} diff --git a/Storage/private/LocalStorage.cpp b/Storage/private/LocalStorage.cpp new file mode 100644 index 0000000..9e33fe5 --- /dev/null +++ b/Storage/private/LocalStorage.cpp @@ -0,0 +1,76 @@ +#include "LocalStorage.hpp" + +#include "SystemHandle.hpp" + +using namespace tp; + +bool File::connect(const FileLocation& location, const FileConnectionType& connectionInfo) { + DEBUG_ASSERT(!mStatus.isOpened()); + if (mStatus.isOpened()) return false; + + auto handle = new FileSystemHandle(); + + switch (connectionInfo.getType()) { + case FileConnectionType::READ: + handle->open(location.getLocation().read(), true); + break; + + case FileConnectionType::WRITE: + handle->open(location.getLocation().read(), false); + break; + + default: + break; + }; + + if (!handle->isOpen()) { + mStatus.setStatus(FileConnectionStatus::DENIED); + delete handle; + return false; + } + + mStatus.setStatus(FileConnectionStatus::OPENED); + mHandle = handle; + return true; +} + +bool File::disconnect() { + DEBUG_ASSERT(mStatus.isOpened()); + if (!mStatus.isOpened() || !mHandle) return false; + mHandle->close(); + delete mHandle; + mStatus.setStatus(FileConnectionStatus::CLOSED); + return true; +} + +bool File::setPointer(BytePointer pointer) { + DEBUG_ASSERT(mStatus.isOpened()); + if (!mStatus.isOpened()) return false; + return true; +} + +bool File::readBytes(Byte* bytes, SizeBytes size) { + DEBUG_ASSERT(mStatus.isOpened() && mConnectionType.isWrite()); + if (!mStatus.isOpened() || !mConnectionType.isWrite()) return false; + + mHandle->seekp(mPointer); + mHandle->read(bytes, size); + mPointer += size; + return true; +} + +bool File::writeBytes(const Byte* bytes, SizeBytes size) { + DEBUG_ASSERT(mStatus.isOpened() && mConnectionType.isRead()); + if (!mStatus.isOpened() || !mConnectionType.isRead()) return false; + + mHandle->seekp(mPointer); + mHandle->write(bytes, size); + mPointer += size; + return true; +} + +File::SizeBytes File::size() { + DEBUG_ASSERT(mStatus.isOpened()); + if (!mStatus.isOpened() || !mHandle) return 0; + return mHandle->size(); +} \ No newline at end of file diff --git a/Storage/private/Storage.cpp b/Storage/private/Storage.cpp new file mode 100644 index 0000000..197a710 --- /dev/null +++ b/Storage/private/Storage.cpp @@ -0,0 +1,9 @@ + +#include "Storage.hpp" + +static tp::ModuleManifest* sModuleDependencies[] = { + &tp::gModuleStrings, + nullptr +}; + +tp::ModuleManifest tp::gModuleStorage = ModuleManifest("Storage", nullptr, nullptr, sModuleDependencies); \ No newline at end of file diff --git a/Storage/private/SystemHandle.cpp b/Storage/private/SystemHandle.cpp new file mode 100644 index 0000000..1386b2a --- /dev/null +++ b/Storage/private/SystemHandle.cpp @@ -0,0 +1,57 @@ +#include "SystemHandle.hpp" + +#include + +using namespace tp; + +ualni tp::FileSystemHandle::size() { + auto strm = (std::fstream*) stream; + ualni out = 0; + strm->seekg(0, std::ios::beg); + out = strm->tellg(); + strm->seekg(0, std::ios::end); + out = (ualni) strm->tellg() - out; + return out; +} + +FileSystemHandle::FileSystemHandle() { + stream = new std::fstream(); +} + +FileSystemHandle::~FileSystemHandle() { + auto strm = (std::fstream*) stream; + delete strm; +} + +bool FileSystemHandle::isOpen() { + auto strm = (std::fstream*) stream; + return strm->is_open(); +} + +void FileSystemHandle::close() { + auto strm = (std::fstream*) stream; + strm->close(); +} + +void FileSystemHandle::seekp(ualni in) { + auto strm = (std::fstream*) stream; + strm->seekp(in); +} + +void FileSystemHandle::read(int1* in, ualni size) { + auto strm = (std::fstream*) stream; + strm->write(in, size); +} + +void FileSystemHandle::write(const int1* in, ualni size) { + auto strm = (std::fstream*) stream; + strm->write(in, size); +} + +void FileSystemHandle::open(const char* path, bool read) { + auto strm = (std::fstream*) stream; + if (read) + strm->open(path, std::ios::in | std::ios::binary | std::ios::app); + else + strm->open(path, std::ios::out | std::ios::binary | std::ios::trunc); +} diff --git a/Storage/private/SystemHandle.hpp b/Storage/private/SystemHandle.hpp new file mode 100644 index 0000000..17d85c7 --- /dev/null +++ b/Storage/private/SystemHandle.hpp @@ -0,0 +1,19 @@ +#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/LocalStorage.hpp b/Storage/public/LocalStorage.hpp new file mode 100644 index 0000000..e832db0 --- /dev/null +++ b/Storage/public/LocalStorage.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include "Storage.hpp" + +namespace tp { + + class FileSystemHandle; + + class FileLocation { + String mLocation; + public: + FileLocation() : mLocation("tmp") {}; + explicit FileLocation(const String& location) : mLocation(location) {} + void setLocation(const String& location) { mLocation = location; } + [[nodiscard]] const String& getLocation() const { return mLocation; } + }; + + class FileConnectionType { + public: + enum HandleType { + READ, + WRITE, + NONE, + }; + + private: + HandleType mHandleType; + + public: + FileConnectionType() : mHandleType(NONE) {} + explicit FileConnectionType(bool read) : mHandleType((HandleType) read) {} + explicit FileConnectionType(HandleType handleType) : mHandleType(handleType) {} + [[nodiscard]] HandleType getType() const { return mHandleType; } + [[nodiscard]] bool isRead() const { return mHandleType == READ; } + [[nodiscard]] bool isWrite() const { return mHandleType == WRITE; } + }; + + class FileConnectionStatus { + public: + enum Status { + NONE, + OPENED, + CLOSED, + DENIED, + INVALID, + }; + + private: + Status mStatus = NONE; + + public: + FileConnectionStatus() = default; + [[nodiscard]] Status getStatus() const { return mStatus; } + void setStatus(Status status) { mStatus = status; } + [[nodiscard]] bool isOpened() const { return mStatus == OPENED; } + }; + + class File { + typedef ualni SizeBytes; + typedef ualni BytePointer; + typedef int1 Byte; + + private: + FileSystemHandle* mHandle = nullptr; + + FileLocation mLocation; + FileConnectionType mConnectionType; + FileConnectionStatus mStatus; + + BytePointer mPointer = 0; + + public: + File() { + MODULE_SANITY_CHECK(gModuleStorage) + }; + + virtual ~File() { + File::disconnect(); + } + + public: + virtual bool connect(const FileLocation& location, const FileConnectionType& connectionInfo); + virtual bool disconnect(); + + public: + virtual const FileConnectionStatus& getConnectionStatus() { return mStatus; } + virtual const FileConnectionType& getConnectionType() { return mConnectionType; } + virtual const FileLocation& getLocation() { return mLocation; } + + public: + virtual bool setPointer(BytePointer pointer); + virtual bool readBytes(Byte* bytes, SizeBytes size); + virtual bool writeBytes(const Byte* bytes, SizeBytes size); + + public: + virtual SizeBytes size(); + }; +} \ No newline at end of file diff --git a/Storage/public/RemoteStorage.hpp b/Storage/public/RemoteStorage.hpp new file mode 100644 index 0000000..7f525be --- /dev/null +++ b/Storage/public/RemoteStorage.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "Storage.hpp" + +namespace tp { + class Client : public Storage { + // same as local storage file but transfers all commands to server + }; + + class Server { + // opens local storage and transfers all client command to it + // manages multiple clients + }; +} \ No newline at end of file diff --git a/Storage/public/Storage.hpp b/Storage/public/Storage.hpp new file mode 100644 index 0000000..b2f2b87 --- /dev/null +++ b/Storage/public/Storage.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "Strings.hpp" + +namespace tp { + + extern ModuleManifest gModuleStorage; + + class StorageLocation { + public: + StorageLocation() = default; + virtual ~StorageLocation() = default; + }; + + class ConnectionType { + public: + ConnectionType() = default; + virtual ~ConnectionType() = default; + }; + + class ConnectionStatus { + public: + ConnectionStatus() = default; + virtual ~ConnectionStatus() = default; + }; + + class Storage { + typedef ualni SizeBytes; + typedef ualni BytePointer; + typedef int1 Byte; + + private: + StorageLocation mLocation; + ConnectionType mConnectionType; + ConnectionStatus mStatus; + + public: + Storage() = default; + virtual ~Storage() = default; + + public: + virtual bool connect(const StorageLocation& location, const ConnectionType& connectionInfo) = 0; + virtual bool disconnect() = 0; + virtual const ConnectionStatus& getConnectionStatus() = 0; + + public: + virtual bool readBytes(BytePointer pointer, Byte* bytes, SizeBytes size) = 0; + virtual bool writeBytes(BytePointer pointer, const Byte* bytes, SizeBytes size) = 0; + + public: + virtual SizeBytes size() = 0; + }; +}; \ No newline at end of file diff --git a/Storage/tests/TestLocalStorage.cpp b/Storage/tests/TestLocalStorage.cpp new file mode 100644 index 0000000..996782a --- /dev/null +++ b/Storage/tests/TestLocalStorage.cpp @@ -0,0 +1,33 @@ + +#include "Testing.hpp" +#include "LocalStorage.hpp" + +using namespace tp; + +TEST_DEF_STATIC(Simple) { + + int1 data[] = { 0, 1, 2, 3, 4 }; + int1 dataRead[]{}; + + { + File file; + file.connect(FileLocation(String("tmp2")), FileConnectionType(false)); + file.writeBytes(data, 5); + file.disconnect(); + } + + { + File file; + file.connect(FileLocation(String("tmp2")), FileConnectionType(true)); + file.readBytes(dataRead, 5); + file.disconnect(); + } + + for (auto i = 0; i < 5; i++) { + TEST(data[i] == dataRead[i]); + } +} + +TEST_DEF(LocalStorage) { + testSimple(); +} \ No newline at end of file diff --git a/Storage/tests/Tests.cpp b/Storage/tests/Tests.cpp new file mode 100644 index 0000000..3dec993 --- /dev/null +++ b/Storage/tests/Tests.cpp @@ -0,0 +1,19 @@ + +#include "Testing.hpp" +#include "Utils.hpp" + +void testLocalStorage(); + +int main() { + + tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr }; + tp::ModuleManifest testModule("StorageTest", nullptr, nullptr, deps); + + if (!testModule.initialize()) { + return 1; + } + + testLocalStorage(); + + testModule.deinitialize(); +} \ No newline at end of file diff --git a/Strings/public/Strings.hpp b/Strings/public/Strings.hpp index 46d124b..c3b6472 100644 --- a/Strings/public/Strings.hpp +++ b/Strings/public/Strings.hpp @@ -1,6 +1,6 @@ #pragma once -#include "PoolAllocator.hpp" +#include "Allocators.hpp" #include "StringLogic.hpp" namespace tp { From 8e00882bb3df7684c31af57a33c2e6bb8fdb1bf7 Mon Sep 17 00:00:00 2001 From: IlushaShurupov Date: Sun, 16 Jul 2023 20:03:14 +0300 Subject: [PATCH 2/5] Networking Initial --- .gitmodules | 3 + Externals/asio | 1 + Storage/CMakeLists.txt | 12 +-- Storage/applications/CMakeLists.txt | 11 +++ Storage/applications/Client.cpp | 96 +++++++++++++------ Storage/applications/Server.cpp | 141 ++++++++++++++++++---------- 6 files changed, 178 insertions(+), 86 deletions(-) create mode 100644 .gitmodules create mode 160000 Externals/asio create mode 100644 Storage/applications/CMakeLists.txt diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3f056fd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Externals/asio"] + path = Externals/asio + url = https://github.com/IlyaShurupov/asio.git diff --git a/Externals/asio b/Externals/asio new file mode 160000 index 0000000..d6b95c0 --- /dev/null +++ b/Externals/asio @@ -0,0 +1 @@ +Subproject commit d6b95c0188e0359a8cdbdb6571f0cbacf11a538c diff --git a/Storage/CMakeLists.txt b/Storage/CMakeLists.txt index 28e593f..d18d496 100644 --- a/Storage/CMakeLists.txt +++ b/Storage/CMakeLists.txt @@ -12,12 +12,6 @@ add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) target_include_directories(${PROJECT_NAME} PUBLIC ./public/) target_link_libraries(${PROJECT_NAME} PUBLIC Strings) -### ---------------------- Applications --------------------- ### -add_executable(Server ./applications/Server.cpp) -add_executable(Client ./applications/Client.cpp) -target_link_libraries(Server PUBLIC ${PROJECT_NAME}) -target_link_libraries(Client PUBLIC ${PROJECT_NAME}) - ### -------------------------- Tests -------------------------- ### enable_testing() file(GLOB TEST_SOURCES "./tests/*.cpp") @@ -25,4 +19,8 @@ add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) -install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib) \ No newline at end of file +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib) + + +# todo :remove +add_subdirectory(applications) \ No newline at end of file diff --git a/Storage/applications/CMakeLists.txt b/Storage/applications/CMakeLists.txt new file mode 100644 index 0000000..8e1e2df --- /dev/null +++ b/Storage/applications/CMakeLists.txt @@ -0,0 +1,11 @@ + +cmake_minimum_required(VERSION 3.2) + +project(Applications) + +### ---------------------- Applications --------------------- ### +add_executable(Server ./Server.cpp) +add_executable(Client ./Client.cpp) + +include_directories(Client ./../../Externals/asio/asio/include) +include_directories(Server ./../../Externals/asio/asio/include) \ No newline at end of file diff --git a/Storage/applications/Client.cpp b/Storage/applications/Client.cpp index 3f7a622..26409c6 100644 --- a/Storage/applications/Client.cpp +++ b/Storage/applications/Client.cpp @@ -1,45 +1,81 @@ -#include -#include -#include -#include -#include -#include +#include "asio.hpp" -constexpr int PORT = 8080; -constexpr int BUFFER_SIZE = 1024; +#include +#include +#include + +// #include +// #include + +constexpr int PORT = 3333; const char* SERVER_IP = "127.0.0.1"; +std::mutex mutex; + +void* readServerBroadcast(void* clientSocketPtr) { + auto socket = ((asio::ip::tcp::socket*)clientSocketPtr); + + while (true) { + + 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(); + } + + return nullptr; +} + int main() { - // Create socket - int clientSocket = socket(AF_INET, SOCK_STREAM, 0); - if (clientSocket == -1) { - std::cerr << "Failed to create socket" << std::endl; + 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; } - // Connect to server - sockaddr_in serverAddress{}; - serverAddress.sin_family = AF_INET; - serverAddress.sin_port = htons(PORT); - if (inet_pton(AF_INET, SERVER_IP, &serverAddress.sin_addr) <= 0) { - std::cerr << "Invalid address or address not supported" << std::endl; - return 1; - } + // Detach the thread so it can run independently + pthread_detach(threadId); - if (connect(clientSocket, reinterpret_cast(&serverAddress), sizeof(serverAddress)) == -1) { - std::cerr << "Failed to connect to server" << std::endl; - return 1; - } + while (true) { + std::string message; + std::cout << " >> "; + std::cin >> message; - // Send message to server - const char* message = "Hello, server!"; - if (write(clientSocket, message, strlen(message)) == -1) { - std::cerr << "Failed to write to socket" << std::endl; - return 1; + 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); + // close(clientSocket); return 0; } diff --git a/Storage/applications/Server.cpp b/Storage/applications/Server.cpp index 7f508be..99d9fd3 100644 --- a/Storage/applications/Server.cpp +++ b/Storage/applications/Server.cpp @@ -1,54 +1,56 @@ +#include + +#include #include -#include -#include -#include +#include +#include #include - class Server { + + struct SharedData { + std::list clients; + std::mutex mutex; + }; + + SharedData mSharedData; + + //int serverSocket; + int port; + public: - Server(int port) : serverSocket(-1), port(port) {} + Server(int port) : port(port) {} + ~Server() { assert(0); } bool start() { // Create socket - serverSocket = socket(AF_INET, SOCK_STREAM, 0); - if (serverSocket == -1) { - std::cerr << "Failed to create socket" << std::endl; - return false; - } + asio::io_context io_context; + asio::ip::tcp::acceptor serverSocket(io_context); // Bind socket to port - sockaddr_in serverAddress{}; - serverAddress.sin_family = AF_INET; - serverAddress.sin_port = htons(port); - serverAddress.sin_addr.s_addr = INADDR_ANY; - if (bind(serverSocket, reinterpret_cast(&serverAddress), sizeof(serverAddress)) == -1) { - std::cerr << "Failed to bind socket" << std::endl; - return false; - } + 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 - if (listen(serverSocket, 5) == -1) { - std::cerr << "Failed to listen on socket" << std::endl; - return false; - } + serverSocket.listen(); std::cout << "Server listening on port " << port << std::endl; // Start accepting clients while (true) { // Accept client connection - sockaddr_in clientAddress{}; - socklen_t clientAddressSize = sizeof(clientAddress); - int clientSocket = accept(serverSocket, reinterpret_cast(&clientAddress), &clientAddressSize); - if (clientSocket == -1) { - std::cerr << "Failed to accept client connection" << std::endl; - return false; - } + auto clientSocket = new asio::ip::tcp::socket(io_context); + serverSocket.accept(*clientSocket); + + // add client + mSharedData.mutex.lock(); + mSharedData.clients.push_back(clientSocket); + mSharedData.mutex.unlock(); // Create a new thread to handle the client pthread_t threadId; - if (pthread_create(&threadId, nullptr, handleClient, &clientSocket) != 0) { + if (pthread_create(&threadId, nullptr, handleClient, this) != 0) { std::cerr << "Failed to create thread for client" << std::endl; return false; } @@ -58,40 +60,81 @@ public: } // Close server socket - close(serverSocket); + serverSocket.close(); return true; } -private: - int serverSocket; - int port; - static void* handleClient(void* clientSocketPtr) { - int clientSocket = *(reinterpret_cast(clientSocketPtr)); - constexpr int BUFFER_SIZE = 1024; + static void* handleClient(void* in) { + auto self = (Server*) in; - // Receive and print client message - char buffer[BUFFER_SIZE]; - ssize_t bytesRead = read(clientSocket, buffer, BUFFER_SIZE - 1); - if (bytesRead == -1) { - std::cerr << "Failed to read from socket" << std::endl; - return nullptr; + // read shared data - current client id + self->mSharedData.mutex.lock(); + auto clientSocket = self->mSharedData.clients.back(); + self->mSharedData.mutex.unlock(); + + 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; + } } - buffer[bytesRead] = '\0'; - std::cout << "Received message from client: " << buffer << std::endl; + 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); + } + } + + // 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; + } + } + + auto exit = memcmp(message, "exit", strlen("exit")) == 0; // Close socket - close(clientSocket); + delete[] message; - return nullptr; + + if (exit) { + (*clientSocket).close(); + self->mSharedData.clients.remove(clientSocket); + } + + self->mSharedData.mutex.unlock(); + + if (exit) { + return nullptr; + } + goto MESSAGE; } }; int main() { - Server server(8080); + Server server(3333); server.start(); return 0; -} +} \ No newline at end of file From 62cb2bb8b764638d49198c13d5d70a898e1d1a06 Mon Sep 17 00:00:00 2001 From: IlushaShurupov Date: Tue, 18 Jul 2023 23:48:54 +0300 Subject: [PATCH 3/5] Fix File test --- Storage/private/LocalStorage.cpp | 5 +++-- Storage/private/SystemHandle.cpp | 2 +- Storage/public/LocalStorage.hpp | 2 +- Storage/tests/TestLocalStorage.cpp | 12 ++++++------ Storage/tests/Tests.cpp | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Storage/private/LocalStorage.cpp b/Storage/private/LocalStorage.cpp index 9e33fe5..fccaad7 100644 --- a/Storage/private/LocalStorage.cpp +++ b/Storage/private/LocalStorage.cpp @@ -12,11 +12,11 @@ bool File::connect(const FileLocation& location, const FileConnectionType& conne switch (connectionInfo.getType()) { case FileConnectionType::READ: - handle->open(location.getLocation().read(), true); + handle->open(location.getLocation().read(), false); break; case FileConnectionType::WRITE: - handle->open(location.getLocation().read(), false); + handle->open(location.getLocation().read(), true); break; default: @@ -31,6 +31,7 @@ bool File::connect(const FileLocation& location, const FileConnectionType& conne mStatus.setStatus(FileConnectionStatus::OPENED); mHandle = handle; + mConnectionType = connectionInfo; return true; } diff --git a/Storage/private/SystemHandle.cpp b/Storage/private/SystemHandle.cpp index 1386b2a..0c0b664 100644 --- a/Storage/private/SystemHandle.cpp +++ b/Storage/private/SystemHandle.cpp @@ -40,7 +40,7 @@ void FileSystemHandle::seekp(ualni in) { void FileSystemHandle::read(int1* in, ualni size) { auto strm = (std::fstream*) stream; - strm->write(in, size); + strm->read(in, size); } void FileSystemHandle::write(const int1* in, ualni size) { diff --git a/Storage/public/LocalStorage.hpp b/Storage/public/LocalStorage.hpp index e832db0..33e2f36 100644 --- a/Storage/public/LocalStorage.hpp +++ b/Storage/public/LocalStorage.hpp @@ -75,7 +75,7 @@ namespace tp { }; virtual ~File() { - File::disconnect(); + if (mStatus.isOpened()) File::disconnect(); } public: diff --git a/Storage/tests/TestLocalStorage.cpp b/Storage/tests/TestLocalStorage.cpp index 996782a..b4c765d 100644 --- a/Storage/tests/TestLocalStorage.cpp +++ b/Storage/tests/TestLocalStorage.cpp @@ -6,20 +6,20 @@ using namespace tp; TEST_DEF_STATIC(Simple) { - int1 data[] = { 0, 1, 2, 3, 4 }; - int1 dataRead[]{}; + const int1* data = "abcde\0"; + int1 dataRead[6]{}; { File file; - file.connect(FileLocation(String("tmp2")), FileConnectionType(false)); - file.writeBytes(data, 5); + file.connect(FileLocation(String("tmp2.txt")), FileConnectionType(false)); + file.writeBytes(data, 6); file.disconnect(); } { File file; - file.connect(FileLocation(String("tmp2")), FileConnectionType(true)); - file.readBytes(dataRead, 5); + file.connect(FileLocation(String("tmp2.txt")), FileConnectionType(true)); + file.readBytes(dataRead, 6); file.disconnect(); } diff --git a/Storage/tests/Tests.cpp b/Storage/tests/Tests.cpp index 3dec993..36f7fd5 100644 --- a/Storage/tests/Tests.cpp +++ b/Storage/tests/Tests.cpp @@ -1,12 +1,12 @@ #include "Testing.hpp" -#include "Utils.hpp" +#include "Storage.hpp" void testLocalStorage(); int main() { - tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr }; + tp::ModuleManifest* deps[] = { &tp::gModuleStorage, nullptr }; tp::ModuleManifest testModule("StorageTest", nullptr, nullptr, deps); if (!testModule.initialize()) { From 576a3565f7e578838bc961092825013bffb2bc0e Mon Sep 17 00:00:00 2001 From: IlushaShurupov Date: Wed, 19 Jul 2023 21:29:57 +0300 Subject: [PATCH 4/5] Command Line INterpreter with fixes --- CommandLine/CMakeLists.txt | 2 +- CommandLine/private/CmdLineInterpreter.cpp | 120 +++++++++++++ CommandLine/private/CommandLine.cpp | 191 ++++++++++++++------- CommandLine/public/CmdLineInterpreter.hpp | 36 ++++ CommandLine/public/CommandLine.hpp | 41 +++-- CommandLine/tests/TestInterpreter.cpp | 34 ++++ CommandLine/tests/Tests.cpp | 3 +- CommandLine/tests/Tests.hpp | 1 + Storage/CMakeLists.txt | 10 +- Storage/applications/CMakeLists.txt | 16 +- Storage/private/LocalStorage.cpp | 13 ++ Storage/public/LocalStorage.hpp | 1 + Strings/public/Strings.hpp | 9 +- Tokenizer/public/Tokenizer.hpp | 2 +- 14 files changed, 384 insertions(+), 95 deletions(-) create mode 100644 CommandLine/private/CmdLineInterpreter.cpp create mode 100644 CommandLine/public/CmdLineInterpreter.hpp create mode 100644 CommandLine/tests/TestInterpreter.cpp diff --git a/CommandLine/CMakeLists.txt b/CommandLine/CMakeLists.txt index 7e8c179..33cea0b 100644 --- a/CommandLine/CMakeLists.txt +++ b/CommandLine/CMakeLists.txt @@ -10,7 +10,7 @@ file(GLOB SOURCES "./private/*.cpp") file(GLOB HEADERS "./public/*.hpp") add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) target_include_directories(${PROJECT_NAME} PUBLIC ./public/) -target_link_libraries(${PROJECT_NAME} PUBLIC Tokenizer) +target_link_libraries(${PROJECT_NAME} PUBLIC Tokenizer Storage) ### -------------------------- Tests -------------------------- ### enable_testing() diff --git a/CommandLine/private/CmdLineInterpreter.cpp b/CommandLine/private/CmdLineInterpreter.cpp new file mode 100644 index 0000000..d3b0e40 --- /dev/null +++ b/CommandLine/private/CmdLineInterpreter.cpp @@ -0,0 +1,120 @@ +#include "CmdLineInterpreter.hpp" + +#define MAX_LINE_LENGTH 1024 + +#include +#include + +using namespace tp; + +static bool helpFunction(CmdLineInterpreter* self, const CommandLine& args) { + self->help(args); + return true; +} + +void CmdLineInterpreter::help(const CommandLine& args) const { + auto commandName = args.getString("CommandName"); + auto allCommands = commandName == "_none_"; + + if (allCommands) { + printf("Commands:\n"); + for (auto command : mCommands) { + printf(" %s\n", command->key.read()); + } + return; + } + + auto idx = mCommands.presents(commandName); + if (!idx) { + printf("Command '%s' not found\n", commandName.read()); + return; + } + + printf("Command '%s'\n", commandName.read()); + auto command = &mCommands.getSlotVal(idx); + command->args->help(); +} + +CmdLineInterpreter::CmdLineInterpreter() { + auto helpArgs = new CommandLine{ + { "CommandName", "_none_" } + }; + + addCommand("help", helpArgs, (CommandFunction) helpFunction, this); +} + + +void CmdLineInterpreter::addCommand(const String& id, CommandLine* args, CommandFunction function, void* customData) { + ASSERT(!mCommands.presents(id)) + mCommands.put(id, { args, function, customData }); +} + +void CmdLineInterpreter::run() { + char buffer[MAX_LINE_LENGTH]; + printf("Command Line Interpreter (or type 'exit' to quit):\n"); + + while (true) { + printf("%s >> ", mName.read()); + + // Read input from the user + if (fgets(buffer, MAX_LINE_LENGTH, stdin) == nullptr) { + printf("Error reading input.\n"); + return; + } + + // Remove the trailing newline character if it exists + auto length = strlen(buffer); + if (length > 0 && buffer[length - 1] == '\n') { + buffer[length - 1] = '\0'; + } + + // Check if the user wants to exit + if (strcmp(buffer, "exit") == 0) { + return; + } + + // Process the input here + processCommand(buffer); + } +} + +bool CmdLineInterpreter::processCommand(int1* commandString) { + ualni commandLen = 0; + for (auto i = commandString; *i != 0; i++) { + if (*i == ' ') break; + commandLen++; + } + + commandString[commandLen] = 0; + auto args = commandString + commandLen + 1; + + auto idx = mCommands.presents(commandString); + if (!idx) { + printf("ERROR: Command '%s' is not found\n", commandString); + printf("Please execute 'help' for more information\n\n"); + return true; + } + + auto command = &mCommands.getSlotVal(idx); + + command->args->parse(args); + + if (command->args->mError) { + printf("ERROR: Command call '%s' has invalid arguments\n", commandString); + command->args->resetError(); + return true; + } + + if (!command->function(command->customData, *command->args)) { + printf("ERROR: Command call '%s' failed\n", commandString); + return true; + } + + return true; +} + +CmdLineInterpreter::~CmdLineInterpreter() { + for (auto cmd : mCommands) { + delete cmd->val.args; + } +} \ No newline at end of file diff --git a/CommandLine/private/CommandLine.cpp b/CommandLine/private/CommandLine.cpp index 39cea49..77bfa2e 100644 --- a/CommandLine/private/CommandLine.cpp +++ b/CommandLine/private/CommandLine.cpp @@ -3,6 +3,9 @@ using namespace tp; +static ModuleManifest* sModuleDependencies[] = { &gModuleTokenizer, &gModuleStorage, nullptr }; +ModuleManifest tp::gModuleStorage = ModuleManifest("CommandLine", nullptr, nullptr, sModuleDependencies); + const char* regexSpace = "\n|\t| |\r"; const char* regexFalse = "N|n|(False)|(false)"; const char* regexTrue = "Y|y|(True)|(true)"; @@ -13,11 +16,13 @@ const char* regexString = "'{'-'}*'"; CommandLine::Arg::Arg(const Arg& arg) { mId = arg.mId; switch (arg.mType) { - case CommandLine::Arg::INT: mType = INT; mInt = arg.mInt; break; - case CommandLine::Arg::FLOAT: mType = FLOAT; mFloat = arg.mFloat; break; - case CommandLine::Arg::BOOL: mType = BOOL; mBool = arg.mBool; break; - case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); mStr = arg.mStr; break; - case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); mFile = arg.mFile; break; + case CommandLine::Arg::INT: mType = INT; mInt = arg.mInt; break; + case CommandLine::Arg::FLOAT: mType = FLOAT; mFloat = arg.mFloat; break; + case CommandLine::Arg::BOOL: mType = BOOL; mBool = arg.mBool; break; + case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); mStr = arg.mStr; break; + case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); mFile = arg.mFile; break; + default: + ASSERT(false) } mOptional = arg.mOptional; } @@ -30,6 +35,7 @@ CommandLine::Arg::Arg(const String& id, Type type) { case CommandLine::Arg::BOOL: mType = BOOL; new (&mBool) BoolArg(); break; case CommandLine::Arg::STR: mType = STR; new (&mStr) StringArg(); break; case CommandLine::Arg::FILE_IN: mType = FILE_IN; new (&mFile) FileInputArg(); break; + default: ASSERT(false) } mOptional = false; } @@ -119,6 +125,13 @@ CommandLine::CommandLine(const init_list& args) { }); ASSERT(mTokenizer.isBuild() && "Internal Error") + + mArgumentTokenizer.build({ + { regexSpace, ArgTokType::SPACE }, + { "{ - }*", ArgTokType::ARG } + }); + + ASSERT(mTokenizer.isBuild() && "Internal Error") } CommandLine::~CommandLine() { @@ -153,17 +166,60 @@ bool CommandLine::parse(char argc, const char* argv[], bool logError, ualni skip } idx++; } - return true; - - //set_working_dir(); } -alni CommandLine::getInt(const String& id) { auto& arg = getArg(id, Arg::INT); return arg.mInt.mVal; } -alnf CommandLine::getFloat(const String& id) { auto& arg = getArg(id, Arg::FLOAT); return arg.mFloat.mVal; } -bool CommandLine::getBool(const String& id) { auto& arg = getArg(id, Arg::BOOL); return arg.mBool.mFlag; } -const String& CommandLine::getString(const String& id) { auto& arg = getArg(id, Arg::STR); return arg.mStr.mStr; } -File& CommandLine::getFile(const String& id) { auto& arg = getArg(id, Arg::FILE_IN); return arg.mFile.mFile; } +bool CommandLine::parse(const char* args, bool logError) { + mArgumentTokenizer.bindSource(args); + mArgumentTokenizer.reset(); + + ualni argc = 0; + auto tok = mArgumentTokenizer.readTok(); + auto argument = mArgsOrder.first(); + + while (tok != ArgTokType::FAILURE && tok != ArgTokType::END) { + if (tok != ArgTokType::ARG) { + tok = mArgumentTokenizer.readTok(); + continue; + } + + if (!argument) { + ErrInvalidArgCount(); + if (logError) ErrLog(); + return false; + } + + parseArg(*argument->data, mArgumentTokenizer.extractVal().read()); + + if (mError && logError) { + ErrLog(); + return false; + } + + argc++; + argument = argument->next; + tok = mArgumentTokenizer.readTok(); + } + + ualni idx = 0; + for (auto arg : mArgsOrder) { + if (idx >= argc) { + initDefault(*arg.data()); + } + if (mError) { + if (logError) ErrLog(); + return false; + } + idx++; + } + return true; +} + +alni CommandLine::getInt(const String& id) const { auto& arg = getArg(id, Arg::INT); return arg.mInt.mVal; } +alnf CommandLine::getFloat(const String& id) const { auto& arg = getArg(id, Arg::FLOAT); return arg.mFloat.mVal; } +bool CommandLine::getBool(const String& id) const { auto& arg = getArg(id, Arg::BOOL); return arg.mBool.mFlag; } +const String& CommandLine::getString(const String& id) const { auto& arg = getArg(id, Arg::STR); return arg.mStr.mStr; } +const FileLocation& CommandLine::getFile(const String& id) const { auto& arg = getArg(id, Arg::FILE_IN); return arg.mFile.mFileLocation; } CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) { @@ -174,6 +230,14 @@ CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) { return *arg; } +const CommandLine::Arg& CommandLine::getArg(const String& id, Arg::Type type) const { + auto idx = mArgs.presents(id); + ASSERT(idx && "Invalid Id") + auto& arg = mArgs.getSlotVal(idx); + ASSERT(arg->mType == type && "Invalid Type Requested") + return *arg; +} + void CommandLine::ErrInvalidArgCount() { mError = { "Invalid Number Of Arguments Passed", nullptr }; } void CommandLine::ErrInvalidArgSyntax(Arg* arg) { mError = { "Invalid Syntax Of Argument", arg }; } void CommandLine::ErrInvalidArgType(Arg* arg) { mError = { "Invalid Type Of Argument", arg }; } @@ -192,7 +256,7 @@ void CommandLine::ErrLog() { } printf("\nArgument: %lli\n", idx); - ArgLog(*mError.mArg); + logArg(*mError.mArg); } printf("Error Description: %s. \n", mError.mDescr); @@ -201,7 +265,7 @@ void CommandLine::ErrLog() { ualni idx = 0; for (auto arg : mArgsOrder) { printf(" -- %lli -- \n", idx); - ArgLog(*arg.data()); + logArg(*arg.data()); idx++; } @@ -214,42 +278,43 @@ void CommandLine::ErrLog() { printf(" File - else\n"); } -void CommandLine::ArgLog(Arg& arg) { +void CommandLine::logArg(const Arg& arg) { switch (arg.mType) { - case Arg::INT: { - printf("Type : Int\n"); - printf("Range : %lli - %lli\n", arg.mInt.mAcceptingRange.mBegin, arg.mInt.mAcceptingRange.mEnd); - if (arg.mOptional) { - printf("Default : %lli\n", arg.mInt.mDefault); - } - printf("Given : %lli\n", arg.mInt.mVal); - } break; - case Arg::FLOAT: { - printf("Type : Float\n"); - printf("Range : %f - %f\n", (halnf) arg.mFloat.mAcceptingRange.mBegin, (halnf) arg.mFloat.mAcceptingRange.mEnd); - if (arg.mOptional) { - printf("Default : %f\n", arg.mFloat.mDefault); - } - printf("Given : %f\n", arg.mFloat.mVal); - } break; - case Arg::BOOL: { - printf("Type : Bool\n"); - if (arg.mOptional) { - printf("Default : %s\n", arg.mBool.mDefault ? "True" : "False"); - } - printf("Given : %s\n", arg.mBool.mFlag ? "True" : "False"); - } break; - case Arg::STR: { - printf("Type : String\n"); - if (arg.mOptional) { - printf("Default : %s\n", arg.mStr.mDefault.read()); - } - printf("Given : %s\n", arg.mStr.mStr.read()); - } break; - case Arg::FILE_IN: { - printf("Type : File Input\n"); - printf("Given Path : %s\n", arg.mFile.mFilepath.read()); - } break; + case Arg::INT: { + printf("Type : Int\n"); + printf("Range : %lli - %lli\n", arg.mInt.mAcceptingRange.mBegin, arg.mInt.mAcceptingRange.mEnd); + if (arg.mOptional) { + printf("Default : %lli\n", arg.mInt.mDefault); + } + printf("Value : %lli\n", arg.mInt.mVal); + } break; + case Arg::FLOAT: { + printf("Type : Float\n"); + printf("Range : %f - %f\n", (halnf) arg.mFloat.mAcceptingRange.mBegin, (halnf) arg.mFloat.mAcceptingRange.mEnd); + if (arg.mOptional) { + printf("Default : %f\n", arg.mFloat.mDefault); + } + printf("Value : %f\n", arg.mFloat.mVal); + } break; + case Arg::BOOL: { + printf("Type : Bool\n"); + if (arg.mOptional) { + printf("Default : %s\n", arg.mBool.mDefault ? "True" : "False"); + } + printf("Value : %s\n", arg.mBool.mFlag ? "True" : "False"); + } break; + case Arg::STR: { + printf("Type : String\n"); + if (arg.mOptional) { + printf("Default : %s\n", arg.mStr.mDefault.read()); + } + printf("Value : %s\n", arg.mStr.mStr.read()); + } break; + case Arg::FILE_IN: { + printf("Type : File Input\n"); + printf("Value Path : %s\n", arg.mFile.mFileLocation.getLocation().read()); + } break; + default: ASSERT(false) } } @@ -305,7 +370,8 @@ void CommandLine::parseArg(Arg& arg, const char* src) { ErrInvalidArgType(&arg); return; } - arg.mStr.mStr = val; + arg.mStr.mStr.resize(val.size() - 2); + memCopy(arg.mStr.mStr.write(), val.read() + 1, val.size() - 2); } break; case Arg::BOOL: { @@ -313,7 +379,7 @@ void CommandLine::parseArg(Arg& arg, const char* src) { ErrInvalidArgType(&arg); return; } - arg.mBool.mFlag = bool(val); + arg.mBool.mFlag = tok == TokType::BOOL_TRUE; } break; case Arg::FILE_IN: { @@ -322,24 +388,23 @@ void CommandLine::parseArg(Arg& arg, const char* src) { return; } - arg.mFile.mFilepath = val; + arg.mFile.mFileLocation.setLocation(val); - /* - // TODO : replace - if (!File::exists(arg.mFile.mFilepath.cstr())) { + if (!arg.mFile.mFileLocation.exists()) { ErrFileNotExists(&arg); return; } - arg.mFile.mFile.open(arg.mFile.mFilepath.cstr(), osfile_openflags::LOAD); - if (!arg.mFile.mFile.opened) { - ErrFileCouldNotOpen(&arg); - return; - } - */ - } break; + default: ASSERT(false) } arg.mIsPassed = true; } + +void CommandLine::help() const { + printf("Arguments:\n"); + for (auto arg : mArgsOrder) { + logArg(*arg.data()); + } +} \ No newline at end of file diff --git a/CommandLine/public/CmdLineInterpreter.hpp b/CommandLine/public/CmdLineInterpreter.hpp new file mode 100644 index 0000000..5839544 --- /dev/null +++ b/CommandLine/public/CmdLineInterpreter.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "CommandLine.hpp" +#include "Map.hpp" + +namespace tp { + + class CmdLineInterpreter { + public: + + typedef bool (*CommandFunction)(void* customData, const CommandLine& args); + + private: + + struct Command { + CommandLine* args; + CommandFunction function; + void* customData = nullptr; + }; + + Map mCommands; + String mName = "InterpName"; + + public: + CmdLineInterpreter(); + ~CmdLineInterpreter(); + + void setName(const String& name) { mName = name; } + [[nodiscard]] const String& getName() const { return mName; } + + void help(const CommandLine& args) const; + void addCommand(const String& id, CommandLine* args, CommandFunction function, void* customData = nullptr); + void run(); + bool processCommand(int1* command); + }; +} \ No newline at end of file diff --git a/CommandLine/public/CommandLine.hpp b/CommandLine/public/CommandLine.hpp index 9e406e1..51c98b6 100644 --- a/CommandLine/public/CommandLine.hpp +++ b/CommandLine/public/CommandLine.hpp @@ -2,13 +2,11 @@ #include "Tokenizer.hpp" #include "Map.hpp" +#include "LocalStorage.hpp" namespace tp { - // TODO : replace - class File { - - }; + extern ModuleManifest gModuleCommandLine; struct CommandLine { @@ -35,13 +33,12 @@ namespace tp { }; struct FileInputArg { - String mFilepath; - File mFile; + FileLocation mFileLocation; }; struct Arg { String mId; - enum Type { INT, FLOAT, BOOL, STR, FILE_IN } mType; + enum Type { INT, FLOAT, BOOL, STR, FILE_IN, NONE } mType = NONE; union { IntArg mInt; FloatArg mFloat; @@ -73,16 +70,23 @@ namespace tp { CommandLine(const init_list& args); ~CommandLine(); - bool parse(char argc, const char* argv[], bool logError = true, ualni skipArgs = 1); + void resetError() { mError.mDescr = nullptr; } - alni getInt(const String& id); - alnf getFloat(const String& id); - bool getBool(const String& id); - const String& getString(const String& id); - File& getFile(const String& id); + bool parse(char argc, const char* argv[], bool logError = true, ualni skipArgs = 1); + bool parse(const char* args, bool logError = true); + + void help() const; + + [[nodiscard]] alni getInt(const String& id) const; + [[nodiscard]] alnf getFloat(const String& id) const; + [[nodiscard]] bool getBool(const String& id) const; + [[nodiscard]] const String& getString(const String& id) const; + [[nodiscard]] const FileLocation& getFile(const String& id) const; + + const CommandLine& operator=(const CommandLine&) = delete; private: - enum class TokType { SPACE, INT, FLOAT, BOOL_FALSE, BOOL_TRUE, STR, NONE, FAILURE, END, } mType; + enum class TokType { SPACE, INT, FLOAT, BOOL_FALSE, BOOL_TRUE, STR, NONE, FAILURE, END, }; typedef SimpleTokenizer Tokenizer; Tokenizer mTokenizer; @@ -90,7 +94,12 @@ namespace tp { List mArgsOrder; ualni mOptionals = 0; + enum class ArgTokType { SPACE, ARG, NONE, FAILURE, END, }; + SimpleTokenizer mArgumentTokenizer; + Arg& getArg(const String& id, Arg::Type type); + [[nodiscard]] const Arg& getArg(const String& id, Arg::Type type) const; + void ErrInvalidArgCount(); void ErrInvalidArgSyntax(Arg* arg); void ErrInvalidArgType(Arg* arg); @@ -98,8 +107,8 @@ namespace tp { void ErrFileCouldNotOpen(Arg* arg); void ErrValNotinRange(Arg* arg); void ErrLog(); - static void ArgLog(Arg& arg); + static void logArg(const Arg& arg); static void initDefault(Arg& arg); void parseArg(Arg& arg, const char* src); }; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/CommandLine/tests/TestInterpreter.cpp b/CommandLine/tests/TestInterpreter.cpp new file mode 100644 index 0000000..eb00474 --- /dev/null +++ b/CommandLine/tests/TestInterpreter.cpp @@ -0,0 +1,34 @@ +#include "Tests.hpp" +#include "CmdLineInterpreter.hpp" + +using namespace tp; + +TEST_DEF_STATIC(Simple) { + + struct TestStruct { + int val = 0; + + static bool print(TestStruct* self, const CommandLine& args) { + printf("Test Val - %i\n", (int) args.getBool("bool")); + return false; + } + + }; + + TestStruct self; + + CmdLineInterpreter interp; + + interp.addCommand("test", new CommandLine{ { "bool", CommandLine::Arg::BOOL } }, (CmdLineInterpreter::CommandFunction) TestStruct::print); + + printf("test false\n", stdin); + printf("help\n", stdin); + printf("help test\n", stdin); + printf("exit\n", stdin); + + interp.run(); +} + +TEST_DEF(Interpreter) { + //testSimple(); +} diff --git a/CommandLine/tests/Tests.cpp b/CommandLine/tests/Tests.cpp index c1d284f..89e1d0f 100644 --- a/CommandLine/tests/Tests.cpp +++ b/CommandLine/tests/Tests.cpp @@ -12,7 +12,8 @@ int main() { return 1; } - testCommandLine(); + // testCommandLine(); + testInterpreter(); testModule.deinitialize(); } diff --git a/CommandLine/tests/Tests.hpp b/CommandLine/tests/Tests.hpp index 13f4290..eaac059 100644 --- a/CommandLine/tests/Tests.hpp +++ b/CommandLine/tests/Tests.hpp @@ -5,3 +5,4 @@ #include "CommandLine.hpp" void testCommandLine(); +void testInterpreter(); diff --git a/Storage/CMakeLists.txt b/Storage/CMakeLists.txt index d18d496..33f269a 100644 --- a/Storage/CMakeLists.txt +++ b/Storage/CMakeLists.txt @@ -12,6 +12,10 @@ add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) target_include_directories(${PROJECT_NAME} PUBLIC ./public/) target_link_libraries(${PROJECT_NAME} PUBLIC Strings) + +### -------------------------- Applications -------------------------- ### +add_subdirectory(applications) + ### -------------------------- Tests -------------------------- ### enable_testing() file(GLOB TEST_SOURCES "./tests/*.cpp") @@ -19,8 +23,4 @@ add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) -install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib) - - -# todo :remove -add_subdirectory(applications) \ No newline at end of file +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib) \ No newline at end of file diff --git a/Storage/applications/CMakeLists.txt b/Storage/applications/CMakeLists.txt index 8e1e2df..b8f171f 100644 --- a/Storage/applications/CMakeLists.txt +++ b/Storage/applications/CMakeLists.txt @@ -3,9 +3,15 @@ cmake_minimum_required(VERSION 3.2) project(Applications) -### ---------------------- Applications --------------------- ### -add_executable(Server ./Server.cpp) -add_executable(Client ./Client.cpp) +file(GLOB SOURCES_CLIENT ./Client.cpp) +file(GLOB SOURCES_SERVER ./Server.cpp) -include_directories(Client ./../../Externals/asio/asio/include) -include_directories(Server ./../../Externals/asio/asio/include) \ No newline at end of file +set(ASIO_INCLUDE ./../../Externals/asio/asio/include) + +add_executable(Client ${SOURCES_CLIENT}) +include_directories(Client ${ASIO_INCLUDE}) +#link_libraries(Client Storage CommandLine) + +add_executable(Server ${SOURCES_SERVER}) +include_directories(Server ${ASIO_INCLUDE}) +#link_libraries(Server Storage CommandLine) diff --git a/Storage/private/LocalStorage.cpp b/Storage/private/LocalStorage.cpp index fccaad7..3410854 100644 --- a/Storage/private/LocalStorage.cpp +++ b/Storage/private/LocalStorage.cpp @@ -2,8 +2,21 @@ #include "SystemHandle.hpp" +#include + using namespace tp; + +bool FileLocation::exists() const { + FILE* file = fopen(mLocation.read(), "r"); + if (file) { + // File exists, close it and return 1 + fclose(file); + return true; + } + return false; +} + bool File::connect(const FileLocation& location, const FileConnectionType& connectionInfo) { DEBUG_ASSERT(!mStatus.isOpened()); if (mStatus.isOpened()) return false; diff --git a/Storage/public/LocalStorage.hpp b/Storage/public/LocalStorage.hpp index 33e2f36..f1cf805 100644 --- a/Storage/public/LocalStorage.hpp +++ b/Storage/public/LocalStorage.hpp @@ -13,6 +13,7 @@ namespace tp { explicit FileLocation(const String& location) : mLocation(location) {} void setLocation(const String& location) { mLocation = location; } [[nodiscard]] const String& getLocation() const { return mLocation; } + [[nodiscard]] bool exists() const; }; class FileConnectionType { diff --git a/Strings/public/Strings.hpp b/Strings/public/Strings.hpp index c3b6472..b146d41 100644 --- a/Strings/public/Strings.hpp +++ b/Strings/public/Strings.hpp @@ -188,17 +188,20 @@ namespace tp { explicit operator alni() { alni out; - return Logic::convertStringToValue(read(), out); + Logic::convertStringToValue(read(), out); + return out; } explicit operator alnf() { alnf out; - return Logic::convertStringToValue(read(), out); + Logic::convertStringToValue(read(), out); + return out; } explicit operator bool() { bool out; - return Logic::convertStringToValue(read(), out); + Logic::convertStringToValue(read(), out); + return out; } Index size() const { diff --git a/Tokenizer/public/Tokenizer.hpp b/Tokenizer/public/Tokenizer.hpp index c48552a..3a041c5 100644 --- a/Tokenizer/public/Tokenizer.hpp +++ b/Tokenizer/public/Tokenizer.hpp @@ -168,7 +168,7 @@ namespace tp { String extractVal() { auto crs = getCursorPrev(); String out; - out.resize(mLastTokLen + 1); + out.resize(mLastTokLen); memCopy(out.write(), crs.str(), mLastTokLen); return out; } From a543568e1d0a16436cc6ec205f9cb592c6ad53d0 Mon Sep 17 00:00:00 2001 From: IlushaShurupov Date: Wed, 19 Jul 2023 23:52:07 +0300 Subject: [PATCH 5/5] 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