From 3131766c9268408f6d58d8a324d08917e0eb5c39 Mon Sep 17 00:00:00 2001 From: ackimixs Date: Sun, 19 May 2024 10:59:13 +0200 Subject: [PATCH] initial commit --- .gitignore | 127 ++++++++++++++++++ CMakeLists.txt | 39 ++++++ cmake/ModelecConfig.cmake.in | 3 + components/CLParser/CMakeLists.txt | 24 ++++ .../CLParser/include/Modelec/CLParser.h | 33 +++++ components/CLParser/src/CLParser.cpp | 68 ++++++++++ components/TCPClient/CMakeLists.txt | 27 ++++ .../TCPClient/include/Modelec/TCPClient.h | 38 ++++++ components/TCPClient/src/TCPClient.cpp | 89 ++++++++++++ components/Utils/CMakeLists.txt | 24 ++++ components/Utils/include/Modelec/Utils.h | 14 ++ components/Utils/src/Utils.cpp | 35 +++++ example/CMakeLists.txt | 16 +++ example/main.cpp | 26 ++++ 14 files changed, 563 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 cmake/ModelecConfig.cmake.in create mode 100644 components/CLParser/CMakeLists.txt create mode 100644 components/CLParser/include/Modelec/CLParser.h create mode 100644 components/CLParser/src/CLParser.cpp create mode 100644 components/TCPClient/CMakeLists.txt create mode 100644 components/TCPClient/include/Modelec/TCPClient.h create mode 100644 components/TCPClient/src/TCPClient.cpp create mode 100644 components/Utils/CMakeLists.txt create mode 100644 components/Utils/include/Modelec/Utils.h create mode 100644 components/Utils/src/Utils.cpp create mode 100644 example/CMakeLists.txt create mode 100644 example/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d1b3670 --- /dev/null +++ b/.gitignore @@ -0,0 +1,127 @@ +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### CMake template +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +### CLion template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +.idea \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a7b07b3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.25) +project(ModelecProject VERSION 1.0.0 LANGUAGES CXX DESCRIPTION "Modelec Lib") + +# Define default install path if not provided +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "..." FORCE) +endif() + +# Library and executable paths +include(GNUInstallDirs) + +# Automatically add subdirectories found in the components directory +file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/components ${CMAKE_CURRENT_SOURCE_DIR}/components/*) +foreach(child ${children}) + if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/components/${child}) + message(STATUS "Adding component: ${child}") + add_subdirectory(components/${child}) + endif() +endforeach() + +# Configuration for installation and find_package() +include(CMakePackageConfigHelpers) +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ModelecConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/ModelecConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Modelec +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/ModelecConfig.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Modelec +) + +# Install the export set for later use by find_package() +install(EXPORT ModelecTargets + FILE ModelecTargets.cmake + NAMESPACE Modelec:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Modelec +) diff --git a/cmake/ModelecConfig.cmake.in b/cmake/ModelecConfig.cmake.in new file mode 100644 index 0000000..b15edbc --- /dev/null +++ b/cmake/ModelecConfig.cmake.in @@ -0,0 +1,3 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/ModelecTargets.cmake") \ No newline at end of file diff --git a/components/CLParser/CMakeLists.txt b/components/CLParser/CMakeLists.txt new file mode 100644 index 0000000..bfd6a10 --- /dev/null +++ b/components/CLParser/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.25) +project(CLParser) + +# Define the library +add_library(CLParser SHARED + src/CLParser.cpp +) + +# Specify include directories +target_include_directories(CLParser PUBLIC + $ + $ +) + +# Export target +install(TARGETS CLParser + EXPORT ModelecTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) \ No newline at end of file diff --git a/components/CLParser/include/Modelec/CLParser.h b/components/CLParser/include/Modelec/CLParser.h new file mode 100644 index 0000000..4cee155 --- /dev/null +++ b/components/CLParser/include/Modelec/CLParser.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +class CLParser { + +public: + CLParser(int argc, char** argv); + + CLParser(const CLParser& other); + + [[nodiscard]] bool hasOption(const std::string& option) const; + + [[nodiscard]] std::optional getOption(const std::string& option) const; + + [[nodiscard]] std::string getOption(const std::string& option, const std::string& defaultValue) const; + + [[nodiscard]] bool hasPositionalArgument(int index) const; + + [[nodiscard]] std::string getPositionalArgument(int index) const; + + [[nodiscard]] int positionalArgumentsCount() const; + + ~CLParser(); + +private: + std::string* _argv; + int _argc; + + std::map _options; +}; diff --git a/components/CLParser/src/CLParser.cpp b/components/CLParser/src/CLParser.cpp new file mode 100644 index 0000000..31665ab --- /dev/null +++ b/components/CLParser/src/CLParser.cpp @@ -0,0 +1,68 @@ +#include + +CLParser::CLParser(int argc, char **argv) : _argc(argc) { + this->_argv = new std::string[argc]; + for (int i = 0; i < argc; i++) { + this->_argv[i] = argv[i]; + } + + for (int i = 1; i < argc; i++) { + if (this->_argv[i].rfind("--", 0) == 0) { + std::string option = this->_argv[i].substr(2); + if (i + 1 < argc && this->_argv[i + 1].rfind("--", 0) != 0) { + this->_options[option] = this->_argv[i + 1]; + } else { + this->_options[option] = ""; + } + } + } +} + +std::optional CLParser::getOption(const std::string &option) const { + if (!this->hasOption(option)) { + return std::nullopt; + } + + return this->_options.at(option); +} + +bool CLParser::hasOption(const std::string &option) const { + return this->_options.find(option) != this->_options.end(); +} + +std::string CLParser::getOption(const std::string &option, const std::string &defaultValue) const { + if (!this->hasOption(option)) { + return defaultValue; + } + + return this->_options.at(option); +} + +bool CLParser::hasPositionalArgument(int index) const { + return index < this->_argc; +} + +std::string CLParser::getPositionalArgument(int index) const { + if (!this->hasPositionalArgument(index)) { + return ""; + } + + return this->_argv[index]; +} + +int CLParser::positionalArgumentsCount() const { + return this->_argc; +} + +CLParser::~CLParser() { + delete[] this->_argv; +} + +CLParser::CLParser(const CLParser &other) : _argc(other._argc) { + this->_argv = new std::string[other._argc]; + for (int i = 0; i < other._argc; i++) { + this->_argv[i] = other._argv[i]; + } + + this->_options = other._options; +} \ No newline at end of file diff --git a/components/TCPClient/CMakeLists.txt b/components/TCPClient/CMakeLists.txt new file mode 100644 index 0000000..39b079d --- /dev/null +++ b/components/TCPClient/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.25) +project(TCPClient) + +# Define the library +add_library(TCPClient SHARED + src/TCPClient.cpp +) + +# Specify include directories +target_include_directories(TCPClient PUBLIC + $ + $ +) + +# Link against Utils +target_link_libraries(TCPClient PUBLIC Utils) + +# Export target +install(TARGETS TCPClient + EXPORT ModelecTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) \ No newline at end of file diff --git a/components/TCPClient/include/Modelec/TCPClient.h b/components/TCPClient/include/Modelec/TCPClient.h new file mode 100644 index 0000000..c49f862 --- /dev/null +++ b/components/TCPClient/include/Modelec/TCPClient.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class TCPClient { +private: + int clientSocket; + sockaddr_in serverAddress{}; +protected: + bool running; + + bool _stoped; + +public: + explicit TCPClient(const char* serverIP = "127.0.0.1", int port = 8080); + + void sendMessage(const char* message) const; + + void sendMessage(const std::string& message) const; + + void receiveMessages(); + + virtual void start(); + + virtual void stop(); + + virtual ~TCPClient(); + + virtual void handleMessage(const std::string& message); + + bool shouldStop() const; +}; \ No newline at end of file diff --git a/components/TCPClient/src/TCPClient.cpp b/components/TCPClient/src/TCPClient.cpp new file mode 100644 index 0000000..82074b2 --- /dev/null +++ b/components/TCPClient/src/TCPClient.cpp @@ -0,0 +1,89 @@ +#include + +#include + +TCPClient::TCPClient(const char* serverIP, int port) : running(false), _stoped(false) { + clientSocket = socket(AF_INET, SOCK_STREAM, 0); + if (clientSocket == -1) { + std::cerr << "Socket creation failed" << std::endl; + exit(EXIT_FAILURE); + } + + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(port); + + if (inet_pton(AF_INET, serverIP, &serverAddress.sin_addr) <= 0) { + std::cerr << "Invalid address or address not supported" << std::endl; + exit(EXIT_FAILURE); + } + + if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) { + std::cerr << "Connection failed" << std::endl; + exit(EXIT_FAILURE); + } +} + +void TCPClient::sendMessage(const char* message) const { + std::string temp = message; + if (!Modelec::endsWith(temp, "\n")) { + temp += "\n"; + } + + send(clientSocket, temp.c_str(), temp.size(), 0); +} + +void TCPClient::sendMessage(const std::string& message) const { + std::string temp = message; + if (!Modelec::endsWith(temp, "\n")) { + temp += "\n"; + } + + send(clientSocket, temp.c_str(), temp.size(), 0); +} + +void TCPClient::receiveMessages() { + char buffer[1024] = {0}; + while (running) { + ssize_t valread = recv(clientSocket, buffer, sizeof(buffer), 0); + if (valread > 0) { + std::vector messages = Modelec::split(buffer, "\n"); + for (const std::string& message : messages) { + handleMessage(message); + } + memset(buffer, 0, sizeof(buffer)); // Clear buffer + } else if (valread == 0) { + std::cerr << "Connection closed by server" << std::endl; + break; + } else { + std::cerr << "Error in receiving message" << std::endl; + break; + } + } + running = false; +} + +void TCPClient::handleMessage(const std::string& message) { + std::cout << message << std::endl; +} + +TCPClient::~TCPClient() { + stop(); +} + +void TCPClient::start() { + running = true; + std::thread receiveThread(&TCPClient::receiveMessages, this); + receiveThread.detach(); +} + +void TCPClient::stop() { + if (!_stoped) { + running = false; + close(clientSocket); + _stoped = true; + } +} + +bool TCPClient::shouldStop() const { + return !running; +} \ No newline at end of file diff --git a/components/Utils/CMakeLists.txt b/components/Utils/CMakeLists.txt new file mode 100644 index 0000000..5e587c3 --- /dev/null +++ b/components/Utils/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.25) +project(Utils) + +# Define the library +add_library(Utils SHARED + src/Utils.cpp +) + +# Specify include directories +target_include_directories(Utils PUBLIC + $ + $ +) + +# Export target +install(TARGETS Utils + EXPORT ModelecTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) \ No newline at end of file diff --git a/components/Utils/include/Modelec/Utils.h b/components/Utils/include/Modelec/Utils.h new file mode 100644 index 0000000..87a12be --- /dev/null +++ b/components/Utils/include/Modelec/Utils.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +namespace Modelec +{ + bool startWith(const std::string& str, const std::string& start); + + bool endsWith(const std::string& str, const std::string& end); + + bool contains(const std::string& str, const std::string& sub); + + std::vector split(const std::string& str, const std::string& delimiter); +} \ No newline at end of file diff --git a/components/Utils/src/Utils.cpp b/components/Utils/src/Utils.cpp new file mode 100644 index 0000000..9b94338 --- /dev/null +++ b/components/Utils/src/Utils.cpp @@ -0,0 +1,35 @@ +#include + +bool Modelec::startWith(const std::string& str, const std::string& start) +{ + return str.rfind(start, 0) == 0; +} + +bool Modelec::endsWith(const std::string& str, const std::string& end) +{ + if (str.length() >= end.length()) + { + return (0 == str.compare(str.length() - end.length(), end.length(), end)); + } + return false; +} + +bool Modelec::contains(const std::string& str, const std::string& sub) +{ + return str.find(sub) != std::string::npos; +} + +std::vector Modelec::split(const std::string& str, const std::string& delimiter) +{ + std::vector tokens; + size_t prev = 0, pos = 0; + do + { + pos = str.find(delimiter, prev); + if (pos == std::string::npos) pos = str.length(); + std::string token = str.substr(prev, pos - prev); + if (!token.empty()) tokens.push_back(token); + prev = pos + delimiter.length(); + } while (pos < str.length() && prev < str.length()); + return tokens; +} \ No newline at end of file diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..0aeb481 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.10) + +project(MySecondProject) + +# Find the shared library package +find_package(Modelec COMPONENTS + CLParser + REQUIRED) + +# Define the executable +add_executable(MyExecutable main.cpp) + +# Link the shared library to the executable +target_link_libraries(MyExecutable + Modelec::CLParser +) \ No newline at end of file diff --git a/example/main.cpp b/example/main.cpp new file mode 100644 index 0000000..42b207c --- /dev/null +++ b/example/main.cpp @@ -0,0 +1,26 @@ +#include + +#include + +int main(int argc, char* argv[]) { + + CLParser parser(argc, argv); + + if (parser.hasOption("help")) { + std::cout << "Usage: " << parser.getPositionalArgument(0) << " [options]" << std::endl; + std::cout << "Options:" << std::endl; + std::cout << " --help: Display this help message" << std::endl; + std::cout << " --port : Set the port to listen to" << std::endl; + return 0; + } + + std::optional port = parser.getOption("port"); + + if (port.has_value()) { + std::cout << port.value() << std::endl; + } else { + std::cout << "No port specified" << std::endl; + } + + return 0; +} \ No newline at end of file