From 22ce960e278a314cc906c32dfe55434e5aea826d Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Wed, 30 Jul 2025 16:23:40 +0200 Subject: [PATCH 01/15] added aeron classes for initial testing --- CMakeLists.txt | 4 + .../aeron_communication/AeronClient.hpp | 51 ++++++++ .../aeron_communication/AeronDriver.hpp | 51 ++++++++ .../modules/ModuleManagerLibraryHandler.hpp | 4 + include/bringauto/settings/Constants.hpp | 11 ++ .../bringauto/structures/ModuleLibrary.hpp | 4 + main.cpp | 9 ++ .../aeron_communication/AeronClient.cpp | 115 ++++++++++++++++++ .../aeron_communication/AeronDriver.cpp | 56 +++++++++ .../modules/ModuleManagerLibraryHandler.cpp | 29 +++++ source/bringauto/structures/ModuleLibrary.cpp | 6 +- 11 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 include/bringauto/aeron_communication/AeronClient.hpp create mode 100644 include/bringauto/aeron_communication/AeronDriver.hpp create mode 100644 source/bringauto/aeron_communication/AeronClient.cpp create mode 100644 source/bringauto/aeron_communication/AeronDriver.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b4285f2..164ed20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ FIND_PACKAGE(eclipse-paho-mqtt-c REQUIRED) FIND_PACKAGE(libbringauto_logger 2.0.0 REQUIRED) FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) FIND_PACKAGE(ZLIB 1.2.11 REQUIRED) +FIND_PACKAGE(aeron REQUIRED) # Requires local installation FILE(GLOB_RECURSE source_files "source/*") ADD_LIBRARY(module-gateway-lib STATIC "${source_files}") @@ -71,6 +72,9 @@ TARGET_LINK_LIBRARIES(module-gateway-lib PUBLIC eclipse-paho-mqtt-c::paho-mqtt3as PahoMqttCpp::paho-mqttpp3 ZLIB::ZLIB + aeron::aeron + aeron::aeron_client + aeron::aeron_driver ${CMAKE_DL_LIBS} ) diff --git a/include/bringauto/aeron_communication/AeronClient.hpp b/include/bringauto/aeron_communication/AeronClient.hpp new file mode 100644 index 0000000..1906edb --- /dev/null +++ b/include/bringauto/aeron_communication/AeronClient.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include + + + +namespace bringauto::aeron_communication { + +class AeronClient { + +public: + enum ModuleFunctions { + ALLOCATE = 0, + AGGREGATE_ERROR = 1, + AGGREGATE_STATUS = 2, + COMMAND_DATA_VALID = 3, + DEALLOCATE = 4, + GENERATE_COMMAND = 5, + GENERATE_FIRST_COMMAND = 6, + SEND_STATUS_CONDITION = 7, + STATUS_DATA_VALID = 8 + }; + + AeronClient(); + + ~AeronClient() = default; + + void addModule(uint16_t moduleId); + + void callModuleFunction(ModuleFunctions function ,const std::string &message) const; + +private: + bool waitForAeronResponse(); + aeron::fragment_handler_t handleMessage(); + std::string moduleFunctionToCode(ModuleFunctions function) const; + + aeron::Context aeronContext_ {}; + std::shared_ptr aeron_ {nullptr}; + std::shared_ptr aeronPublication_ {nullptr}; + std::shared_ptr aeronSubscription_ {nullptr}; + std::shared_ptr aeronFragmentAssembler_ {nullptr}; + std::shared_ptr aeronHandler_ {nullptr}; + std::shared_ptr aeronIdleStrategy_ {nullptr}; + std::atomic aeronPolling_ {false}; + std::string aeronMessage_ {}; + +}; + +} diff --git a/include/bringauto/aeron_communication/AeronDriver.hpp b/include/bringauto/aeron_communication/AeronDriver.hpp new file mode 100644 index 0000000..210548a --- /dev/null +++ b/include/bringauto/aeron_communication/AeronDriver.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include + + + +namespace bringauto::aeron_communication { + +/** + * This class is meant for aeron testing. It provides a simple interface to start the Aeron media driver. + */ +class AeronDriver { + +public: + /** + * @brief Constructs Aeron Driver. + * Initializes the driver with default settings. + */ + AeronDriver(); + + ~AeronDriver() = default; + + /** + * @brief Starts the Aeron Driver. + * This method will block until the driver is stopped or an error occurs. + */ + void run(); + + /** + * @brief Checks if the Aeron Driver is running. + * @return true if the driver is running, false otherwise. + */ + bool isRunning() const; + + /** + * @brief Stops the Aeron Driver. + * This method will stop the driver and release all resources. + */ + void stop(); + +private: + /// Context for the Aeron driver. Driver settings can be adjusted in this struct. + aeron_driver_context_t *driverContext_; + /// Pointer to the Aeron driver instance. + aeron_driver_t *driver_ {nullptr}; + /// Variable used in aeron macros that returns error codes. + volatile int exitStatus_ {AERON_NULL_VALUE}; + +}; + +} diff --git a/include/bringauto/modules/ModuleManagerLibraryHandler.hpp b/include/bringauto/modules/ModuleManagerLibraryHandler.hpp index fbae895..795570c 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandler.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandler.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -17,6 +18,8 @@ namespace bringauto::modules { class ModuleManagerLibraryHandler { public: ModuleManagerLibraryHandler() = default; + ModuleManagerLibraryHandler(std::shared_ptr &aeronClient): + aeronClient_(aeronClient) {}; ~ModuleManagerLibraryHandler(); @@ -109,6 +112,7 @@ class ModuleManagerLibraryHandler { std::function generateCommand_ {}; std::function allocate_ {}; std::function deallocate_ {}; + std::shared_ptr aeronClient_ {nullptr}; }; } diff --git a/include/bringauto/settings/Constants.hpp b/include/bringauto/settings/Constants.hpp index 306eb9c..9d22d16 100644 --- a/include/bringauto/settings/Constants.hpp +++ b/include/bringauto/settings/Constants.hpp @@ -86,6 +86,16 @@ constexpr unsigned int max_external_commands { 3 }; */ constexpr unsigned int max_external_queue_size { 500 }; +/** + * @brief base stream id for Aeron communication from Module Gateway to module binary + */ +constexpr unsigned int aeron_to_module_stream_id_base { 10000 }; + +/** + * @brief base stream id for Aeron communication from module binary to Module Gateway + */ +constexpr unsigned int aeron_to_gateway_stream_id_base { 20000 }; + /** * @brief Constants for Mqtt communication */ @@ -161,6 +171,7 @@ class Constants { inline static constexpr std::string_view CLIENT_KEY { "client-key" }; inline static constexpr std::string_view MODULES { "modules" }; + inline static constexpr std::string_view AERON_CONNECTION { "aeron:ipc"}; }; } diff --git a/include/bringauto/structures/ModuleLibrary.hpp b/include/bringauto/structures/ModuleLibrary.hpp index 5f37de3..88655b5 100644 --- a/include/bringauto/structures/ModuleLibrary.hpp +++ b/include/bringauto/structures/ModuleLibrary.hpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -13,6 +14,7 @@ namespace bringauto::structures { * @brief Library with library handlers and status aggregators */ struct ModuleLibrary { + ModuleLibrary(); ~ModuleLibrary(); @@ -33,6 +35,8 @@ struct ModuleLibrary { std::unordered_map> moduleLibraryHandlers {}; /// Map of status aggregators, key is module id std::unordered_map> statusAggregators {}; + /// Aeron client used for communication with modules + std::shared_ptr aeronClient {nullptr}; }; } diff --git a/main.cpp b/main.cpp index 00a3883..4c8a32a 100644 --- a/main.cpp +++ b/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -67,7 +68,13 @@ int main(int argc, char **argv) { std::cerr << "[ERROR] Error occurred during reading configuration: " << e.what() << std::endl; return 1; } + + bringauto::aeron_communication::AeronDriver aeronDriver {}; + std::jthread aeronDriverThread([&aeronDriver]() { aeronDriver.run(); }); + baset::Logger::logInfo("Aeron Driver starting..."); + std::this_thread::sleep_for(std::chrono::seconds(2)); //TODO Not sure how much time is needed. bas::ModuleLibrary moduleLibrary {}; + try { moduleLibrary.loadLibraries(context->settings->modulePaths); moduleLibrary.initStatusAggregators(context); @@ -99,10 +106,12 @@ int main(int argc, char **argv) { context->ioContext.stop(); } + aeronDriver.stop(); contextThread2.join(); contextThread1.join(); externalClientThread.join(); moduleHandlerThread.join(); + aeronDriverThread.join(); internalServer.destroy(); moduleHandler.destroy(); diff --git a/source/bringauto/aeron_communication/AeronClient.cpp b/source/bringauto/aeron_communication/AeronClient.cpp new file mode 100644 index 0000000..402f9d2 --- /dev/null +++ b/source/bringauto/aeron_communication/AeronClient.cpp @@ -0,0 +1,115 @@ +#include +#include +#include + + + +namespace bringauto::aeron_communication { + +using log = settings::Logger; + +AeronClient::AeronClient() { + aeronContext_.newPublicationHandler( + [](const std::string &channel, std::int32_t streamId, std::int32_t sessionId, std::int64_t correlationId) { + log::logDebug("AeronClient: New publication on channel: " + channel + + " with correlationId: " + std::to_string(correlationId) + + ", streamId: " + std::to_string(streamId) + + ", sessionId: " + std::to_string(sessionId) + ); + } + ); + + aeronContext_.newSubscriptionHandler( + [](const std::string &channel, std::int32_t streamId, std::int64_t correlationId) { + log::logDebug("AeronClient: New subscription on channel: " + channel + + " with correlationId: " + std::to_string(correlationId) + + ", streamId: " + std::to_string(streamId) + ); + } + ); + + aeronContext_.availableImageHandler( + [](aeron::Image &image) { + log::logDebug("AeronClient: Available image on correlationId: " + std::to_string(image.correlationId()) + + ", sessionId: " + std::to_string(image.sessionId()) + + ", position: " + std::to_string(image.position()) + + ", sourceIdentity: " + image.sourceIdentity() + ); + } + ); + + aeronContext_.unavailableImageHandler( + [](aeron::Image &image) { + log::logDebug("AeronClient: Unavailable image on correlationId: " + std::to_string(image.correlationId()) + + ", sessionId: " + std::to_string(image.sessionId()) + + ", position: " + std::to_string(image.position()) + + ", sourceIdentity: " + image.sourceIdentity() + ); + } + ); + + aeron_ = aeron::Aeron::connect(aeronContext_); + aeronFragmentAssembler_ = std::make_shared(handleMessage()); + aeronHandler_ = std::make_shared(aeronFragmentAssembler_->handler()); + aeronIdleStrategy_ = std::make_shared(); +} + + +void AeronClient::addModule(uint16_t moduleId) { + std::int64_t id = aeron_->addPublication( + std::string(settings::Constants::AERON_CONNECTION), + settings::aeron_to_module_stream_id_base + moduleId + ); + aeronPublication_ = aeron_->findPublication(id); + while (!aeronPublication_) { + std::this_thread::yield(); + aeronPublication_ = aeron_->findPublication(id); + } + + id = aeron_->addSubscription( + std::string(settings::Constants::AERON_CONNECTION), + settings::aeron_to_gateway_stream_id_base + moduleId + ); + aeronSubscription_ = aeron_->findSubscription(id); + while (!aeronSubscription_) { + std::this_thread::yield(); + aeronSubscription_ = aeron_->findSubscription(id); + } +} + + +void AeronClient::callModuleFunction(ModuleFunctions function, const std::string &message) const { + std::string fullMessage = std::string(moduleFunctionToCode(function)) + ":" + message; + + std::array buff; + aeron::concurrent::AtomicBuffer srcBuffer(&buff[0], buff.size()); + char charMessage[256]; + const int messageLen = ::snprintf(charMessage, sizeof(charMessage), "%s", fullMessage.c_str()); + srcBuffer.putBytes(0, reinterpret_cast(charMessage), messageLen); + aeronPublication_->offer(srcBuffer, 0, messageLen); +} + + +bool AeronClient::waitForAeronResponse() { + aeronPolling_ = true; + while (aeronPolling_) { + const int fragmentsRead = aeronSubscription_->poll(*aeronHandler_, 10); + aeronIdleStrategy_->idle(fragmentsRead); + } + return true; +} + + +aeron::fragment_handler_t AeronClient::handleMessage() { + return [&](const aeron::AtomicBuffer &buffer, aeron::util::index_t offset, aeron::util::index_t length, const aeron::Header &header) { + std::string message(reinterpret_cast(buffer.buffer()) + offset, static_cast(length)); + aeronMessage_ = message; + aeronPolling_ = false; + }; +} + +std::string AeronClient::moduleFunctionToCode(ModuleFunctions function) const { + return std::to_string(static_cast(function)); +} + +} diff --git a/source/bringauto/aeron_communication/AeronDriver.cpp b/source/bringauto/aeron_communication/AeronDriver.cpp new file mode 100644 index 0000000..f6a4b13 --- /dev/null +++ b/source/bringauto/aeron_communication/AeronDriver.cpp @@ -0,0 +1,56 @@ +#include + +#include + + + +static bringauto::aeron_communication::AeronDriver* globalDriverInstance = nullptr; + +void terminationHook(void *state) { + if (globalDriverInstance == nullptr) { + globalDriverInstance->stop(); + } +} + +void signalHandler(int signal) { + if (globalDriverInstance != nullptr) { + globalDriverInstance->stop(); + } +} + + +namespace bringauto::aeron_communication { + +AeronDriver::AeronDriver() { + globalDriverInstance = this; + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); + aeron_driver_context_init(&driverContext_); + aeron_driver_context_set_driver_termination_hook(driverContext_, terminationHook, NULL); + driverContext_->agent_on_start_func_delegate = driverContext_->agent_on_start_func; + driverContext_->agent_on_start_state_delegate = driverContext_->agent_on_start_state; + aeron_driver_context_set_agent_on_start_function(driverContext_, aeron_set_thread_affinity_on_start, driverContext_); + aeron_driver_init(&driver_, driverContext_); +} + + +void AeronDriver::run() { + aeron_driver_start(driver_, true); + while (isRunning()) { + aeron_driver_main_idle_strategy(driver_, aeron_driver_main_do_work(driver_)); + } +} + + +bool AeronDriver::isRunning() const { + int result; + AERON_GET_ACQUIRE(result, exitStatus_); + return result == AERON_NULL_VALUE; +} + + +void AeronDriver::stop() { + AERON_SET_RELEASE(exitStatus_, EXIT_SUCCESS); +} + +} diff --git a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp b/source/bringauto/modules/ModuleManagerLibraryHandler.cpp index b075a5e..ebc1d3a 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandler.cpp @@ -54,6 +54,11 @@ void ModuleManagerLibraryHandler::loadLibrary(const std::filesystem::path &path) "allocate")); deallocate_ = reinterpret_cast::fncptr>(checkFunction( "deallocate")); + + if (aeronClient_ != nullptr) { + aeronClient_->addModule(getModuleNumber_()); + } + log::logDebug("Library " + path.string() + " was successfully loaded"); } @@ -115,6 +120,9 @@ int ModuleManagerLibraryHandler::generateCommand(Buffer &generated_command, } else { generated_command = constructBuffer(); } + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::GENERATE_COMMAND, "TODO"); + } return ret; } @@ -138,6 +146,9 @@ int ModuleManagerLibraryHandler::aggregateStatus(Buffer &aggregated_status, } else { aggregated_status = current_status; } + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_STATUS, "TODO"); + } return ret; } @@ -162,6 +173,9 @@ int ModuleManagerLibraryHandler::aggregateError(Buffer &error_message, } else { error_message = constructBuffer(); } + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_ERROR, "TODO"); + } return ret; } @@ -173,6 +187,9 @@ int ModuleManagerLibraryHandler::generateFirstCommand(Buffer &default_command, u } else { default_command = constructBuffer(); } + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::GENERATE_FIRST_COMMAND, "TODO"); + } return ret; } @@ -181,6 +198,9 @@ int ModuleManagerLibraryHandler::statusDataValid(const Buffer &status, unsigned if (status.isAllocated()) { raw_buffer = status.getStructBuffer(); } + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::STATUS_DATA_VALID, "TODO"); + } return statusDataValid_(raw_buffer, device_type); } @@ -189,14 +209,23 @@ int ModuleManagerLibraryHandler::commandDataValid(const Buffer &command, unsigne if (command.isAllocated()) { raw_buffer = command.getStructBuffer(); } + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::COMMAND_DATA_VALID, "TODO"); + } return commandDataValid_(raw_buffer, device_type); } int ModuleManagerLibraryHandler::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::ALLOCATE, "TODO"); + } return allocate_(buffer_pointer, size_in_bytes); } void ModuleManagerLibraryHandler::deallocate(struct buffer *buffer) const { + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::DEALLOCATE, "TODO"); + } deallocate_(buffer); } diff --git a/source/bringauto/structures/ModuleLibrary.cpp b/source/bringauto/structures/ModuleLibrary.cpp index c6d61c8..20f6dfd 100644 --- a/source/bringauto/structures/ModuleLibrary.cpp +++ b/source/bringauto/structures/ModuleLibrary.cpp @@ -6,6 +6,10 @@ namespace bringauto::structures { +ModuleLibrary::ModuleLibrary() { + aeronClient = std::make_shared(); +} + ModuleLibrary::~ModuleLibrary() { std::for_each(statusAggregators.cbegin(), statusAggregators.cend(), [](auto &pair) { pair.second->destroy_status_aggregator(); }); @@ -13,7 +17,7 @@ ModuleLibrary::~ModuleLibrary() { void ModuleLibrary::loadLibraries(const std::unordered_map &libPaths) { for(auto const &[key, path]: libPaths) { - auto handler = std::make_shared(); + auto handler = std::make_shared(aeronClient); handler->loadLibrary(path); if(handler->getModuleNumber() != key) { settings::Logger::logError("Module number from shared library {} does not match the module number from config. Config: {}, binary: {}.", path, key, handler->getModuleNumber()); From be654fec9ca906b4de78f7fd37de3a6c9557034b Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Thu, 31 Jul 2025 10:52:55 +0200 Subject: [PATCH 02/15] check returned messages from aeron client --- .../aeron_communication/AeronClient.hpp | 4 ++- .../aeron_communication/AeronClient.cpp | 8 ++++- .../modules/ModuleManagerLibraryHandler.cpp | 30 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/bringauto/aeron_communication/AeronClient.hpp b/include/bringauto/aeron_communication/AeronClient.hpp index 1906edb..00fff6d 100644 --- a/include/bringauto/aeron_communication/AeronClient.hpp +++ b/include/bringauto/aeron_communication/AeronClient.hpp @@ -29,7 +29,9 @@ class AeronClient { void addModule(uint16_t moduleId); - void callModuleFunction(ModuleFunctions function ,const std::string &message) const; + void callModuleFunction(ModuleFunctions function ,const std::string &message); + + std::string_view getMessage() const; private: bool waitForAeronResponse(); diff --git a/source/bringauto/aeron_communication/AeronClient.cpp b/source/bringauto/aeron_communication/AeronClient.cpp index 402f9d2..dec69df 100644 --- a/source/bringauto/aeron_communication/AeronClient.cpp +++ b/source/bringauto/aeron_communication/AeronClient.cpp @@ -78,7 +78,7 @@ void AeronClient::addModule(uint16_t moduleId) { } -void AeronClient::callModuleFunction(ModuleFunctions function, const std::string &message) const { +void AeronClient::callModuleFunction(ModuleFunctions function, const std::string &message) { std::string fullMessage = std::string(moduleFunctionToCode(function)) + ":" + message; std::array buff; @@ -87,6 +87,12 @@ void AeronClient::callModuleFunction(ModuleFunctions function, const std::string const int messageLen = ::snprintf(charMessage, sizeof(charMessage), "%s", fullMessage.c_str()); srcBuffer.putBytes(0, reinterpret_cast(charMessage), messageLen); aeronPublication_->offer(srcBuffer, 0, messageLen); + waitForAeronResponse(); +} + + +std::string_view AeronClient::getMessage() const { + return aeronMessage_; } diff --git a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp b/source/bringauto/modules/ModuleManagerLibraryHandler.cpp index ebc1d3a..7a027c3 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandler.cpp @@ -91,6 +91,12 @@ int ModuleManagerLibraryHandler::sendStatusCondition(const Buffer ¤t_statu new_status_raw_buffer = new_status.getStructBuffer(); } + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::SEND_STATUS_CONDITION, "TODO"); + if (aeronClient_->getMessage() != "sendStatusCondition") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } + } return sendStatusCondition_(current_status_raw_buffer, new_status_raw_buffer, device_type); } @@ -122,6 +128,9 @@ int ModuleManagerLibraryHandler::generateCommand(Buffer &generated_command, } if (aeronClient_ != nullptr) { aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::GENERATE_COMMAND, "TODO"); + if (aeronClient_->getMessage() != "generateCommand") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } } return ret; } @@ -148,6 +157,9 @@ int ModuleManagerLibraryHandler::aggregateStatus(Buffer &aggregated_status, } if (aeronClient_ != nullptr) { aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_STATUS, "TODO"); + if (aeronClient_->getMessage() != "aggregateStatus") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } } return ret; } @@ -175,6 +187,9 @@ int ModuleManagerLibraryHandler::aggregateError(Buffer &error_message, } if (aeronClient_ != nullptr) { aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_ERROR, "TODO"); + if (aeronClient_->getMessage() != "aggregateError") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } } return ret; } @@ -189,6 +204,9 @@ int ModuleManagerLibraryHandler::generateFirstCommand(Buffer &default_command, u } if (aeronClient_ != nullptr) { aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::GENERATE_FIRST_COMMAND, "TODO"); + if (aeronClient_->getMessage() != "generateFirstCommand") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } } return ret; } @@ -200,6 +218,9 @@ int ModuleManagerLibraryHandler::statusDataValid(const Buffer &status, unsigned } if (aeronClient_ != nullptr) { aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::STATUS_DATA_VALID, "TODO"); + if (aeronClient_->getMessage() != "statusDataValid") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } } return statusDataValid_(raw_buffer, device_type); } @@ -211,6 +232,9 @@ int ModuleManagerLibraryHandler::commandDataValid(const Buffer &command, unsigne } if (aeronClient_ != nullptr) { aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::COMMAND_DATA_VALID, "TODO"); + if (aeronClient_->getMessage() != "commandDataValid") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } } return commandDataValid_(raw_buffer, device_type); } @@ -218,6 +242,9 @@ int ModuleManagerLibraryHandler::commandDataValid(const Buffer &command, unsigne int ModuleManagerLibraryHandler::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { if (aeronClient_ != nullptr) { aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::ALLOCATE, "TODO"); + if (aeronClient_->getMessage() != "allocate") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } } return allocate_(buffer_pointer, size_in_bytes); } @@ -225,6 +252,9 @@ int ModuleManagerLibraryHandler::allocate(struct buffer *buffer_pointer, size_t void ModuleManagerLibraryHandler::deallocate(struct buffer *buffer) const { if (aeronClient_ != nullptr) { aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::DEALLOCATE, "TODO"); + if (aeronClient_->getMessage() != "deallocate") { + throw std::runtime_error("AeronClient did not receive the expected message"); + } } deallocate_(buffer); } From 683237689536ed655679569ecb9839587f9b5430 Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Fri, 1 Aug 2025 16:29:57 +0200 Subject: [PATCH 03/15] functional aeron module communication --- CMakeLists.txt | 4 + cmake/Dependencies.cmake | 4 +- .../modules/ModuleManagerLibraryHandler.hpp | 18 +++ include/bringauto/settings/Constants.hpp | 1 + .../modules/ModuleManagerLibraryHandler.cpp | 144 +++++++++++------- .../modules/memory_management/CMakeLists.txt | 10 ++ .../source/memory_management.cpp | 21 +++ 7 files changed, 146 insertions(+), 56 deletions(-) create mode 100644 source/bringauto/modules/memory_management/CMakeLists.txt create mode 100644 source/bringauto/modules/memory_management/source/memory_management.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 164ed20..70c2285 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,11 +54,13 @@ FIND_PACKAGE(eclipse-paho-mqtt-c REQUIRED) FIND_PACKAGE(libbringauto_logger 2.0.0 REQUIRED) FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) FIND_PACKAGE(ZLIB 1.2.11 REQUIRED) +FIND_PACKAGE(fleet-protocol-cxx-helpers-static 1.1.1 REQUIRED) FIND_PACKAGE(aeron REQUIRED) # Requires local installation FILE(GLOB_RECURSE source_files "source/*") ADD_LIBRARY(module-gateway-lib STATIC "${source_files}") TARGET_INCLUDE_DIRECTORIES(module-gateway-lib PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) +ADD_SUBDIRECTORY(source/bringauto/modules/memory_management) TARGET_LINK_LIBRARIES(module-gateway-lib PUBLIC Boost::headers protobuf::libprotobuf @@ -72,9 +74,11 @@ TARGET_LINK_LIBRARIES(module-gateway-lib PUBLIC eclipse-paho-mqtt-c::paho-mqtt3as PahoMqttCpp::paho-mqttpp3 ZLIB::ZLIB + fleet-protocol-cxx-helpers-static::fleet-protocol-cxx-helpers-static aeron::aeron aeron::aeron_client aeron::aeron_driver + memory_management ${CMAKE_DL_LIBS} ) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index e004024..ba66f51 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -5,11 +5,11 @@ BA_PACKAGE_LIBRARY(fleet-protocol-interface v2.0.0 NO_DEBUG ON) BA_PACKAGE_LIBRARY(nlohmann-json v3.10.5 NO_DEBUG ON) BA_PACKAGE_LIBRARY(cxxopts v3.0.5 NO_DEBUG ON) BA_PACKAGE_LIBRARY(boost v1.86.0) -BA_PACKAGE_LIBRARY(ba-logger v2.0.0 -) +BA_PACKAGE_LIBRARY(ba-logger v2.0.0) BA_PACKAGE_LIBRARY(pahomqttc v1.3.9) BA_PACKAGE_LIBRARY(pahomqttcpp v1.3.2) BA_PACKAGE_LIBRARY(zlib v1.2.11 OUTPUT_PATH_VAR ZLIB_DIR) +BA_PACKAGE_LIBRARY(fleet-protocol-cpp v1.1.1) IF (BRINGAUTO_TESTS) BA_PACKAGE_LIBRARY(gtest v1.12.1) diff --git a/include/bringauto/modules/ModuleManagerLibraryHandler.hpp b/include/bringauto/modules/ModuleManagerLibraryHandler.hpp index 795570c..3346edd 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandler.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandler.hpp @@ -96,6 +96,24 @@ class ModuleManagerLibraryHandler { */ Buffer constructBufferByTakeOwnership(struct ::buffer& buffer); + /** + * @brief Constructs a message for AeronClient to send to the module + * + * @param buffers vector of raw c buffers to be included in the message + * @param deviceType type of the device for which the message is constructed + * @return a string message to be sent + */ + std::string constructAeronMessage(const std::vector &buffers, int deviceType) const; + + /** + * @brief Parses the response from AeronClient + * + * @param raw_buffer raw buffer to be filled with the response data + * @param response response string from AeronClient + * @return status code of the response + */ + int parseAeronResponse(struct ::buffer &raw_buffer, std::string_view response) const; + void *module_ {}; std::function getModuleNumber_ {}; diff --git a/include/bringauto/settings/Constants.hpp b/include/bringauto/settings/Constants.hpp index 9d22d16..5d4e954 100644 --- a/include/bringauto/settings/Constants.hpp +++ b/include/bringauto/settings/Constants.hpp @@ -172,6 +172,7 @@ class Constants { inline static constexpr std::string_view MODULES { "modules" }; inline static constexpr std::string_view AERON_CONNECTION { "aeron:ipc"}; + inline static constexpr std::string_view SEPARATOR { ":::" }; }; } diff --git a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp b/source/bringauto/modules/ModuleManagerLibraryHandler.cpp index 7a027c3..801b04b 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandler.cpp @@ -1,6 +1,8 @@ #include #include +#include +#include #include #include @@ -92,10 +94,11 @@ int ModuleManagerLibraryHandler::sendStatusCondition(const Buffer ¤t_statu } if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::SEND_STATUS_CONDITION, "TODO"); - if (aeronClient_->getMessage() != "sendStatusCondition") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } + aeronClient_->callModuleFunction( + aeron_communication::AeronClient::ModuleFunctions::SEND_STATUS_CONDITION, + constructAeronMessage({¤t_status_raw_buffer, &new_status_raw_buffer}, device_type) + ); + return std::stoi(std::string(aeronClient_->getMessage())); } return sendStatusCondition_(current_status_raw_buffer, new_status_raw_buffer, device_type); } @@ -119,19 +122,22 @@ int ModuleManagerLibraryHandler::generateCommand(Buffer &generated_command, current_command_raw_buffer = current_command.getStructBuffer(); } - int ret = generateCommand_(&raw_buffer, new_status_raw_buffer, - current_status_raw_buffer, current_command_raw_buffer, device_type); + int ret; + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction( + aeron_communication::AeronClient::ModuleFunctions::GENERATE_COMMAND, + constructAeronMessage({&new_status_raw_buffer, ¤t_status_raw_buffer, ¤t_command_raw_buffer}, device_type) + ); + ret = parseAeronResponse(raw_buffer, aeronClient_->getMessage()); + } else { + ret = generateCommand_(&raw_buffer, new_status_raw_buffer, + current_status_raw_buffer, current_command_raw_buffer, device_type); + } if (ret == OK) { generated_command = constructBufferByTakeOwnership(raw_buffer); } else { generated_command = constructBuffer(); } - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::GENERATE_COMMAND, "TODO"); - if (aeronClient_->getMessage() != "generateCommand") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } - } return ret; } @@ -149,18 +155,21 @@ int ModuleManagerLibraryHandler::aggregateStatus(Buffer &aggregated_status, new_status_raw_buffer = new_status.getStructBuffer(); } - const int ret = aggregateStatus_(&raw_buffer, current_status_raw_buffer, new_status_raw_buffer, device_type); + int ret; + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction( + aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_STATUS, + constructAeronMessage({¤t_status_raw_buffer, &new_status_raw_buffer}, device_type) + ); + ret = parseAeronResponse(raw_buffer, aeronClient_->getMessage()); + } else { + ret = aggregateStatus_(&raw_buffer, current_status_raw_buffer, new_status_raw_buffer, device_type); + } if (ret == OK) { aggregated_status = constructBufferByTakeOwnership(raw_buffer); } else { aggregated_status = current_status; } - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_STATUS, "TODO"); - if (aeronClient_->getMessage() != "aggregateStatus") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } - } return ret; } @@ -178,36 +187,41 @@ int ModuleManagerLibraryHandler::aggregateError(Buffer &error_message, if (status.isAllocated()) { status_raw_buffer = status.getStructBuffer(); } - - const int ret = aggregateError_(&raw_buffer, current_error_raw_buffer, status_raw_buffer, device_type); + int ret; + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction( + aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_ERROR, + constructAeronMessage({¤t_error_raw_buffer, &status_raw_buffer}, device_type) + ); + ret = parseAeronResponse(raw_buffer, aeronClient_->getMessage()); + } else { + ret = aggregateError_(&raw_buffer, current_error_raw_buffer, status_raw_buffer, device_type); + } if (ret == OK) { error_message = constructBufferByTakeOwnership(raw_buffer); } else { error_message = constructBuffer(); } - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_ERROR, "TODO"); - if (aeronClient_->getMessage() != "aggregateError") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } - } return ret; } int ModuleManagerLibraryHandler::generateFirstCommand(Buffer &default_command, unsigned int device_type) { struct ::buffer raw_buffer {}; - const int ret = generateFirstCommand_(&raw_buffer, device_type); + int ret; + if (aeronClient_ != nullptr) { + aeronClient_->callModuleFunction( + aeron_communication::AeronClient::ModuleFunctions::GENERATE_FIRST_COMMAND, + constructAeronMessage({}, device_type) + ); + ret = parseAeronResponse(raw_buffer, aeronClient_->getMessage()); + } else { + ret = generateFirstCommand_(&raw_buffer, device_type); + } if (ret == OK) { default_command = constructBufferByTakeOwnership(raw_buffer); } else { default_command = constructBuffer(); } - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::GENERATE_FIRST_COMMAND, "TODO"); - if (aeronClient_->getMessage() != "generateFirstCommand") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } - } return ret; } @@ -217,10 +231,11 @@ int ModuleManagerLibraryHandler::statusDataValid(const Buffer &status, unsigned raw_buffer = status.getStructBuffer(); } if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::STATUS_DATA_VALID, "TODO"); - if (aeronClient_->getMessage() != "statusDataValid") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } + aeronClient_->callModuleFunction( + aeron_communication::AeronClient::ModuleFunctions::STATUS_DATA_VALID, + constructAeronMessage({&raw_buffer}, device_type) + ); + return std::stoi(std::string(aeronClient_->getMessage())); } return statusDataValid_(raw_buffer, device_type); } @@ -231,31 +246,32 @@ int ModuleManagerLibraryHandler::commandDataValid(const Buffer &command, unsigne raw_buffer = command.getStructBuffer(); } if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::COMMAND_DATA_VALID, "TODO"); - if (aeronClient_->getMessage() != "commandDataValid") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } + aeronClient_->callModuleFunction( + aeron_communication::AeronClient::ModuleFunctions::COMMAND_DATA_VALID, + constructAeronMessage({&raw_buffer}, device_type) + ); + return std::stoi(std::string(aeronClient_->getMessage())); } return commandDataValid_(raw_buffer, device_type); } int ModuleManagerLibraryHandler::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::ALLOCATE, "TODO"); - if (aeronClient_->getMessage() != "allocate") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } - } + // if (aeronClient_ != nullptr) { + // aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::ALLOCATE, "TODO"); + // if (aeronClient_->getMessage() != "allocate") { + // throw std::runtime_error("AeronClient did not receive the expected message"); + // } + // } return allocate_(buffer_pointer, size_in_bytes); } void ModuleManagerLibraryHandler::deallocate(struct buffer *buffer) const { - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::DEALLOCATE, "TODO"); - if (aeronClient_->getMessage() != "deallocate") { - throw std::runtime_error("AeronClient did not receive the expected message"); - } - } + // if (aeronClient_ != nullptr) { + // aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::DEALLOCATE, "TODO"); + // if (aeronClient_->getMessage() != "deallocate") { + // throw std::runtime_error("AeronClient did not receive the expected message"); + // } + // } deallocate_(buffer); } @@ -278,4 +294,24 @@ Buffer ModuleManagerLibraryHandler::constructBufferByTakeOwnership(struct ::buff return { buffer, deallocate_ }; } +std::string ModuleManagerLibraryHandler::constructAeronMessage(const std::vector &buffers, int deviceType) const { + std::string message; + for (const auto &buff : buffers) { + message += std::string(static_cast(buff->data), buff->size_in_bytes) + std::string(settings::Constants::SEPARATOR); + } + return message + std::to_string(deviceType); +} + +int ModuleManagerLibraryHandler::parseAeronResponse(struct ::buffer &raw_buffer, std::string_view response) const { + size_t sepPos = response.find(settings::Constants::SEPARATOR); + if (sepPos == std::string::npos) { + throw std::runtime_error("Invalid response format: " + std::string(response)); + } + bringauto::fleet_protocol::cxx::StringAsBuffer::createBufferAndCopyData( + &raw_buffer, + response.substr(sepPos + settings::Constants::SEPARATOR.size()) + ); + return std::stoi(std::string(response.substr(0, sepPos))); +} + } diff --git a/source/bringauto/modules/memory_management/CMakeLists.txt b/source/bringauto/modules/memory_management/CMakeLists.txt new file mode 100644 index 0000000..e2e72b1 --- /dev/null +++ b/source/bringauto/modules/memory_management/CMakeLists.txt @@ -0,0 +1,10 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.25 FATAL_ERROR) +PROJECT(ModuleGateway) + +SET(CMAKE_CXX_STANDARD 20) + +FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) + +FILE(GLOB_RECURSE memory_management_cpp_files "./source/*") +ADD_LIBRARY(memory_management STATIC ${memory_management_cpp_files}) +TARGET_LINK_LIBRARIES(memory_management PUBLIC fleet-protocol-interface::common-headers-interface) \ No newline at end of file diff --git a/source/bringauto/modules/memory_management/source/memory_management.cpp b/source/bringauto/modules/memory_management/source/memory_management.cpp new file mode 100644 index 0000000..834c9f5 --- /dev/null +++ b/source/bringauto/modules/memory_management/source/memory_management.cpp @@ -0,0 +1,21 @@ +#include + +#include +#include + + +int allocate(struct buffer *buffer_pointer, size_t size_in_bytes){ + try{ + buffer_pointer->data = new char[size_in_bytes](); + } catch(std::bad_alloc&){ + return NOT_OK; + } + buffer_pointer->size_in_bytes = size_in_bytes; + return OK; +} + +void deallocate(struct buffer *buffer_pointer){ + delete[] static_cast(buffer_pointer->data); + buffer_pointer->data = nullptr; + buffer_pointer->size_in_bytes = 0; +} \ No newline at end of file From 7ff00e3e919cae174c275d5ab4ccf020febde17a Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Mon, 4 Aug 2025 10:46:57 +0200 Subject: [PATCH 04/15] added docstrings for AeronClient --- .../aeron_communication/AeronClient.hpp | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/bringauto/aeron_communication/AeronClient.hpp b/include/bringauto/aeron_communication/AeronClient.hpp index 00fff6d..a8c4feb 100644 --- a/include/bringauto/aeron_communication/AeronClient.hpp +++ b/include/bringauto/aeron_communication/AeronClient.hpp @@ -8,6 +8,10 @@ namespace bringauto::aeron_communication { +/** + * This class is responsible for managing Aeron communication. + * It is used for calling module functions on a separate module binary using Aeron. + */ class AeronClient { public: @@ -23,14 +27,35 @@ class AeronClient { STATUS_DATA_VALID = 8 }; + /** + * @brief Constructs an AeronClient instance. + * Initializes the Aeron context and sets up handlers for publications and subscriptions. + */ AeronClient(); ~AeronClient() = default; + /** + * @brief Adds a module to the Aeron client with the given module ID. + * Creates a publication and subscription for the module. + * Only supports one module for now. + * @param moduleId The ID of the module to be added. + */ void addModule(uint16_t moduleId); + /** + * @brief Calls a module function with the specified message. + * Constructs a full message by combining the function code and the provided message, + * then sends it via Aeron publication. + * @param function The module function to call. + * @param message The message to send to the module. + */ void callModuleFunction(ModuleFunctions function ,const std::string &message); + /** + * @brief Retrieves the last received message from Aeron. + * @return A string view of the last message received. + */ std::string_view getMessage() const; private: @@ -45,7 +70,9 @@ class AeronClient { std::shared_ptr aeronFragmentAssembler_ {nullptr}; std::shared_ptr aeronHandler_ {nullptr}; std::shared_ptr aeronIdleStrategy_ {nullptr}; + /// Indicates if the Aeron client is currently polling for messages std::atomic aeronPolling_ {false}; + /// Last message received from Aeron std::string aeronMessage_ {}; }; From fec035381e39a59a885291bd0efdae0bc8c7f9ca Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Mon, 22 Sep 2025 10:09:44 +0200 Subject: [PATCH 05/15] async function execution usage --- CMLibStorage.cmake | 4 + CMakeLists.txt | 12 +- README.md | 2 +- cmake/Dependencies.cmake | 2 +- .../aeron_communication/AeronClient.hpp | 80 ------- .../aeron_communication/AeronDriver.hpp | 51 ----- .../external_client/ErrorAggregator.hpp | 5 +- include/bringauto/modules/Buffer.hpp | 1 + .../modules/ModuleManagerLibraryHandler.hpp | 24 +- .../ModuleManagerLibraryHandlerAsync.hpp | 101 +++++++++ .../bringauto/modules/StatusAggregator.hpp | 9 +- include/bringauto/settings/Constants.hpp | 114 ++++++++++ include/bringauto/settings/Settings.hpp | 5 + .../bringauto/structures/ModuleLibrary.hpp | 10 +- main.cpp | 17 +- .../aeron_communication/AeronClient.cpp | 121 ---------- .../aeron_communication/AeronDriver.cpp | 56 ----- .../external_client/ErrorAggregator.cpp | 2 +- .../modules/ModuleManagerLibraryHandler.cpp | 109 +-------- .../ModuleManagerLibraryHandlerAsync.cpp | 207 ++++++++++++++++++ .../source/memory_management.cpp | 2 +- source/bringauto/settings/SettingsParser.cpp | 5 + source/bringauto/structures/ModuleLibrary.cpp | 11 +- 23 files changed, 480 insertions(+), 470 deletions(-) delete mode 100644 include/bringauto/aeron_communication/AeronClient.hpp delete mode 100644 include/bringauto/aeron_communication/AeronDriver.hpp create mode 100644 include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp delete mode 100644 source/bringauto/aeron_communication/AeronClient.cpp delete mode 100644 source/bringauto/aeron_communication/AeronDriver.cpp create mode 100644 source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp diff --git a/CMLibStorage.cmake b/CMLibStorage.cmake index 7e7142d..36796ba 100644 --- a/CMLibStorage.cmake +++ b/CMLibStorage.cmake @@ -1,3 +1,7 @@ +FIND_PACKAGE(CMLIB REQUIRED COMPONENTS CMCONF) + +CMCONF_INIT_SYSTEM(FLEET_PROTOCOL) + SET(STORAGE_LIST DEP) SET(STORAGE_LIST_DEP "https://github.com/bacpack-system/package-tracker.git") diff --git a/CMakeLists.txt b/CMakeLists.txt index 70c2285..9ca001a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ SET(Protobuf_USE_STATIC_LIBS ON) FIND_PACKAGE(Boost 1.74 REQUIRED CONFIG) FIND_PACKAGE(Protobuf 3.21.12 REQUIRED) -FIND_PACKAGE(cxxopts 3.0.0 REQUIRED) +FIND_PACKAGE(cxxopts 3.1.1 REQUIRED) FIND_PACKAGE(nlohmann_json 3.2.0 REQUIRED) FIND_PACKAGE(PahoMqttCpp REQUIRED) FIND_PACKAGE(eclipse-paho-mqtt-c REQUIRED) @@ -55,7 +55,9 @@ FIND_PACKAGE(libbringauto_logger 2.0.0 REQUIRED) FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) FIND_PACKAGE(ZLIB 1.2.11 REQUIRED) FIND_PACKAGE(fleet-protocol-cxx-helpers-static 1.1.1 REQUIRED) -FIND_PACKAGE(aeron REQUIRED) # Requires local installation + +#temp +ADD_SUBDIRECTORY(${CMAKE_CURRENT_LIST_DIR}/aeron-interface) FILE(GLOB_RECURSE source_files "source/*") ADD_LIBRARY(module-gateway-lib STATIC "${source_files}") @@ -75,9 +77,7 @@ TARGET_LINK_LIBRARIES(module-gateway-lib PUBLIC PahoMqttCpp::paho-mqttpp3 ZLIB::ZLIB fleet-protocol-cxx-helpers-static::fleet-protocol-cxx-helpers-static - aeron::aeron - aeron::aeron_client - aeron::aeron_driver + async-function-execution-static memory_management ${CMAKE_DL_LIBS} ) @@ -102,7 +102,7 @@ TARGET_LINK_LIBRARIES(module-gateway-app PUBLIC module-gateway-lib) IF(BRINGAUTO_TESTS) ENABLE_TESTING() - INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt) + #INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt) INCLUDE(CTest) ENDIF(BRINGAUTO_TESTS) diff --git a/README.md b/README.md index c56b1e2..be8a1b1 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ connection is broken and as soon as the connection is up, then error aggregated - [cmlib](https://github.com/cmakelib/cmakelib) - [protobuf](https://github.com/protocolbuffers/protobuf/tree/main/src) >= v3.21.12 -- [cxxopts](https://github.com/jarro2783/cxxopts) >= v3.0.0 +- [cxxopts](https://github.com/jarro2783/cxxopts) >= v3.1.1 - [boost](https://github.com/boostorg/boost) >= v1.74.0 - [nlohmann-json](https://github.com/nlohmann/json) >= v3.2.0 - [ba-logger](https://github.com/bringauto/ba-logger) >= v1.2.0 diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index ba66f51..072f74e 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -3,7 +3,7 @@ SET(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH FALSE) BA_PACKAGE_LIBRARY(protobuf v4.21.12) BA_PACKAGE_LIBRARY(fleet-protocol-interface v2.0.0 NO_DEBUG ON) BA_PACKAGE_LIBRARY(nlohmann-json v3.10.5 NO_DEBUG ON) -BA_PACKAGE_LIBRARY(cxxopts v3.0.5 NO_DEBUG ON) +BA_PACKAGE_LIBRARY(cxxopts v3.1.1 NO_DEBUG ON) BA_PACKAGE_LIBRARY(boost v1.86.0) BA_PACKAGE_LIBRARY(ba-logger v2.0.0) BA_PACKAGE_LIBRARY(pahomqttc v1.3.9) diff --git a/include/bringauto/aeron_communication/AeronClient.hpp b/include/bringauto/aeron_communication/AeronClient.hpp deleted file mode 100644 index a8c4feb..0000000 --- a/include/bringauto/aeron_communication/AeronClient.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include -#include -#include - - - -namespace bringauto::aeron_communication { - -/** - * This class is responsible for managing Aeron communication. - * It is used for calling module functions on a separate module binary using Aeron. - */ -class AeronClient { - -public: - enum ModuleFunctions { - ALLOCATE = 0, - AGGREGATE_ERROR = 1, - AGGREGATE_STATUS = 2, - COMMAND_DATA_VALID = 3, - DEALLOCATE = 4, - GENERATE_COMMAND = 5, - GENERATE_FIRST_COMMAND = 6, - SEND_STATUS_CONDITION = 7, - STATUS_DATA_VALID = 8 - }; - - /** - * @brief Constructs an AeronClient instance. - * Initializes the Aeron context and sets up handlers for publications and subscriptions. - */ - AeronClient(); - - ~AeronClient() = default; - - /** - * @brief Adds a module to the Aeron client with the given module ID. - * Creates a publication and subscription for the module. - * Only supports one module for now. - * @param moduleId The ID of the module to be added. - */ - void addModule(uint16_t moduleId); - - /** - * @brief Calls a module function with the specified message. - * Constructs a full message by combining the function code and the provided message, - * then sends it via Aeron publication. - * @param function The module function to call. - * @param message The message to send to the module. - */ - void callModuleFunction(ModuleFunctions function ,const std::string &message); - - /** - * @brief Retrieves the last received message from Aeron. - * @return A string view of the last message received. - */ - std::string_view getMessage() const; - -private: - bool waitForAeronResponse(); - aeron::fragment_handler_t handleMessage(); - std::string moduleFunctionToCode(ModuleFunctions function) const; - - aeron::Context aeronContext_ {}; - std::shared_ptr aeron_ {nullptr}; - std::shared_ptr aeronPublication_ {nullptr}; - std::shared_ptr aeronSubscription_ {nullptr}; - std::shared_ptr aeronFragmentAssembler_ {nullptr}; - std::shared_ptr aeronHandler_ {nullptr}; - std::shared_ptr aeronIdleStrategy_ {nullptr}; - /// Indicates if the Aeron client is currently polling for messages - std::atomic aeronPolling_ {false}; - /// Last message received from Aeron - std::string aeronMessage_ {}; - -}; - -} diff --git a/include/bringauto/aeron_communication/AeronDriver.hpp b/include/bringauto/aeron_communication/AeronDriver.hpp deleted file mode 100644 index 210548a..0000000 --- a/include/bringauto/aeron_communication/AeronDriver.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - - - -namespace bringauto::aeron_communication { - -/** - * This class is meant for aeron testing. It provides a simple interface to start the Aeron media driver. - */ -class AeronDriver { - -public: - /** - * @brief Constructs Aeron Driver. - * Initializes the driver with default settings. - */ - AeronDriver(); - - ~AeronDriver() = default; - - /** - * @brief Starts the Aeron Driver. - * This method will block until the driver is stopped or an error occurs. - */ - void run(); - - /** - * @brief Checks if the Aeron Driver is running. - * @return true if the driver is running, false otherwise. - */ - bool isRunning() const; - - /** - * @brief Stops the Aeron Driver. - * This method will stop the driver and release all resources. - */ - void stop(); - -private: - /// Context for the Aeron driver. Driver settings can be adjusted in this struct. - aeron_driver_context_t *driverContext_; - /// Pointer to the Aeron driver instance. - aeron_driver_t *driver_ {nullptr}; - /// Variable used in aeron macros that returns error codes. - volatile int exitStatus_ {AERON_NULL_VALUE}; - -}; - -} diff --git a/include/bringauto/external_client/ErrorAggregator.hpp b/include/bringauto/external_client/ErrorAggregator.hpp index dfa47cd..e6724f4 100644 --- a/include/bringauto/external_client/ErrorAggregator.hpp +++ b/include/bringauto/external_client/ErrorAggregator.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -25,7 +26,7 @@ class ErrorAggregator { * @return OK if initialization was successful * @return NOT_OK if an error occurred */ - int init_error_aggregator(const std::shared_ptr &library); + int init_error_aggregator(const std::shared_ptr &library); //TODO select type from config /** * @short Clean up. @@ -111,7 +112,7 @@ class ErrorAggregator { modules::Buffer lastStatus {}; }; - std::shared_ptr module_ {}; + std::shared_ptr module_ {}; //TODO select type from config /** * @brief Map of devices states, key is device identification converted to string diff --git a/include/bringauto/modules/Buffer.hpp b/include/bringauto/modules/Buffer.hpp index a6c5e8e..a616e9b 100644 --- a/include/bringauto/modules/Buffer.hpp +++ b/include/bringauto/modules/Buffer.hpp @@ -19,6 +19,7 @@ namespace bringauto::modules { struct Buffer final { friend class ModuleManagerLibraryHandler; + friend class ModuleManagerLibraryHandlerAsync; Buffer() = default; Buffer(const Buffer& buff) = default; diff --git a/include/bringauto/modules/ModuleManagerLibraryHandler.hpp b/include/bringauto/modules/ModuleManagerLibraryHandler.hpp index 3346edd..8d12252 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandler.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandler.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include @@ -18,8 +17,6 @@ namespace bringauto::modules { class ModuleManagerLibraryHandler { public: ModuleManagerLibraryHandler() = default; - ModuleManagerLibraryHandler(std::shared_ptr &aeronClient): - aeronClient_(aeronClient) {}; ~ModuleManagerLibraryHandler(); @@ -96,24 +93,6 @@ class ModuleManagerLibraryHandler { */ Buffer constructBufferByTakeOwnership(struct ::buffer& buffer); - /** - * @brief Constructs a message for AeronClient to send to the module - * - * @param buffers vector of raw c buffers to be included in the message - * @param deviceType type of the device for which the message is constructed - * @return a string message to be sent - */ - std::string constructAeronMessage(const std::vector &buffers, int deviceType) const; - - /** - * @brief Parses the response from AeronClient - * - * @param raw_buffer raw buffer to be filled with the response data - * @param response response string from AeronClient - * @return status code of the response - */ - int parseAeronResponse(struct ::buffer &raw_buffer, std::string_view response) const; - void *module_ {}; std::function getModuleNumber_ {}; @@ -130,7 +109,6 @@ class ModuleManagerLibraryHandler { std::function generateCommand_ {}; std::function allocate_ {}; std::function deallocate_ {}; - std::shared_ptr aeronClient_ {nullptr}; }; -} +} \ No newline at end of file diff --git a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp new file mode 100644 index 0000000..92acf29 --- /dev/null +++ b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp @@ -0,0 +1,101 @@ +#pragma once + +#include + +#include + +#include +#include + + + +namespace bringauto::modules { + +/** + * @brief Class used to load and handle library created by module maintainer + */ +class ModuleManagerLibraryHandlerAsync { +public: + ModuleManagerLibraryHandlerAsync(); + + ~ModuleManagerLibraryHandlerAsync(); + + /** + * @brief Load library created by a module maintainer + * + * @param path path to the library + * @param moduleBinaryPath path to the module binary + */ + void loadLibrary(const std::filesystem::path &path, const std::string &moduleBinaryPath); + + int getModuleNumber() const; + + int isDeviceTypeSupported(unsigned int device_type) const; + + int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const; + + /** + * @short After executing the respective module function, an error might be thrown when allocating the buffer. + * + * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h + */ + int generateCommand(Buffer &generated_command, const Buffer &new_status, + const Buffer ¤t_status, const Buffer ¤t_command, + unsigned int device_type); + + /** + * @short After executing the respective module function, an error might be thrown when allocating the buffer. + * + * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h + */ + int aggregateStatus(Buffer &aggregated_status, const Buffer ¤t_status, + const Buffer &new_status, unsigned int device_type); + + /** + * @short After executing the respective module function, an error might be thrown when allocating the buffer. + * + * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h + */ + int aggregateError(Buffer &error_message, const Buffer ¤t_error_message, const Buffer &status, + unsigned int device_type); + + /** + * @short After executing the respective module function, an error might be thrown when allocating the buffer. + * + * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h + */ + int generateFirstCommand(Buffer &default_command, unsigned int device_type); + + int statusDataValid(const Buffer &status, unsigned int device_type) const; + + int commandDataValid(const Buffer &command, unsigned int device_type) const; + + /** + * @brief Constructs a buffer with the given size + * + * @param size size of the buffer + * @return a new Buffer object + */ + Buffer constructBuffer(std::size_t size = 0); + +private: + + int allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const; + + void deallocate(struct buffer *buffer) const; + + /** + * @brief Constructs a buffer with the same raw c buffer as provided + * + * @param buffer c buffer to be used + * @return a new Buffer object + */ + Buffer constructBufferByTakeOwnership(struct ::buffer& buffer); + + std::function deallocate_ {}; + + /// Process id of the module binary + pid_t moduleBinaryPid_ {}; +}; + +} diff --git a/include/bringauto/modules/StatusAggregator.hpp b/include/bringauto/modules/StatusAggregator.hpp index 03c84e9..4cf426f 100644 --- a/include/bringauto/modules/StatusAggregator.hpp +++ b/include/bringauto/modules/StatusAggregator.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -20,9 +21,9 @@ class StatusAggregator { public: explicit StatusAggregator(const std::shared_ptr &context, - const std::shared_ptr &libraryHandler): context_ { context }, - module_ { - libraryHandler } {}; + const std::shared_ptr &libraryHandler): context_ { context }, //TODO select type from config + module_ { + libraryHandler } {}; StatusAggregator() = default; @@ -186,7 +187,7 @@ class StatusAggregator { std::shared_ptr context_ {}; - const std::shared_ptr module_ {}; + const std::shared_ptr module_ {}; //TODO select type from config /** * @brief Map of devices states, key is device identification diff --git a/include/bringauto/settings/Constants.hpp b/include/bringauto/settings/Constants.hpp index 5d4e954..34dd5fb 100644 --- a/include/bringauto/settings/Constants.hpp +++ b/include/bringauto/settings/Constants.hpp @@ -1,5 +1,11 @@ #pragma once +#include + +#include +#include +#include + #include #include @@ -152,6 +158,7 @@ class Constants { inline static constexpr std::string_view PORT { "port" }; inline static constexpr std::string_view MODULE_PATHS { "module-paths" }; + inline static constexpr std::string_view MODULE_BINARY_PATH { "module-binary-path" }; inline static constexpr std::string_view INTERNAL_SERVER_SETTINGS { "internal-server-settings" }; @@ -175,4 +182,111 @@ class Constants { inline static constexpr std::string_view SEPARATOR { ":::" }; }; +struct ConvertibleBufferReturn final { + int returnCode { 0 }; //TODO temporary, need to serialize return code aswell + struct ::buffer buffer {}; + ConvertibleBufferReturn() = default; + ConvertibleBufferReturn(int code, struct ::buffer buff) : returnCode(code), buffer(buff) {} + ~ConvertibleBufferReturn() { + buffer.data = nullptr; + } + + std::span serialize() const { + return std::span {reinterpret_cast(buffer.data), buffer.size_in_bytes}; + } + void deserialize(std::span bytes) { + if(buffer.data != nullptr) { + delete[] buffer.data; + } + buffer.size_in_bytes = bytes.size(); + buffer.data = new uint8_t[buffer.size_in_bytes]; + std::memcpy(buffer.data, bytes.data(), buffer.size_in_bytes); + } +}; + +struct ConvertibleBuffer final { + struct ::buffer buffer {}; + ConvertibleBuffer() = default; + ConvertibleBuffer(struct ::buffer buff) : buffer(buff) {} + + std::span serialize() const { + return std::span {reinterpret_cast(buffer.data), buffer.size_in_bytes}; + } + void deserialize(std::span bytes) { + buffer.data = const_cast(bytes.data()); + buffer.size_in_bytes = bytes.size(); + } +}; + +class FunctionIds { +public: + inline static const async_function_execution::FunctionDefinition getModuleNumber { + async_function_execution::FunctionId { 0 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments {} + }; + + inline static const async_function_execution::FunctionDefinition isDeviceTypeSupported { + async_function_execution::FunctionId { 1 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { uint32_t {} } + }; + + inline static const async_function_execution::FunctionDefinition sendStatusCondition { + async_function_execution::FunctionId { 2 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } + }; + + inline static const async_function_execution::FunctionDefinition generateCommand { + async_function_execution::FunctionId { 3 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } + }; + + inline static const async_function_execution::FunctionDefinition aggregateStatus { + async_function_execution::FunctionId { 4 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } + }; + + inline static const async_function_execution::FunctionDefinition aggregateError { + async_function_execution::FunctionId { 5 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } + }; + + inline static const async_function_execution::FunctionDefinition generateFirstCommand { + async_function_execution::FunctionId { 6 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { uint32_t {} } + }; + + inline static const async_function_execution::FunctionDefinition statusDataValid { + async_function_execution::FunctionId { 7 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } + }; + + inline static const async_function_execution::FunctionDefinition commandDataValid { + async_function_execution::FunctionId { 8 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } + }; + + inline static const async_function_execution::FunctionList functionList { + std::tuple { + getModuleNumber, + isDeviceTypeSupported, + sendStatusCondition, + generateCommand, + aggregateStatus, + aggregateError, + generateFirstCommand, + statusDataValid, + commandDataValid + } + }; +}; + } diff --git a/include/bringauto/settings/Settings.hpp b/include/bringauto/settings/Settings.hpp index aad2db8..1075820 100644 --- a/include/bringauto/settings/Settings.hpp +++ b/include/bringauto/settings/Settings.hpp @@ -33,6 +33,11 @@ struct Settings { */ std::unordered_map modulePaths {}; + /** + * @brief path to module binary + */ + std::string moduleBinaryPath {}; + /** * @brief Setting of external connection endpoints and protocols */ diff --git a/include/bringauto/structures/ModuleLibrary.hpp b/include/bringauto/structures/ModuleLibrary.hpp index 88655b5..124e84c 100644 --- a/include/bringauto/structures/ModuleLibrary.hpp +++ b/include/bringauto/structures/ModuleLibrary.hpp @@ -1,8 +1,8 @@ #pragma once #include +#include #include -#include #include @@ -14,7 +14,7 @@ namespace bringauto::structures { * @brief Library with library handlers and status aggregators */ struct ModuleLibrary { - ModuleLibrary(); + ModuleLibrary() = default; ~ModuleLibrary(); @@ -23,7 +23,7 @@ struct ModuleLibrary { * * @param libPaths paths to the libraries */ - void loadLibraries(const std::unordered_map &libPaths); + void loadLibraries(const std::unordered_map &libPaths, const std::string &moduleBinaryPath); /** * @brief Initialize status aggregators with context @@ -32,11 +32,9 @@ struct ModuleLibrary { */ void initStatusAggregators(std::shared_ptr &context); /// Map of module handlers, key is module id - std::unordered_map> moduleLibraryHandlers {}; + std::unordered_map> moduleLibraryHandlers {}; //TODO select type from config /// Map of status aggregators, key is module id std::unordered_map> statusAggregators {}; - /// Aeron client used for communication with modules - std::shared_ptr aeronClient {nullptr}; }; } diff --git a/main.cpp b/main.cpp index 4c8a32a..a220471 100644 --- a/main.cpp +++ b/main.cpp @@ -10,9 +10,9 @@ #include #include #include -#include #include +#include #include #include #include @@ -69,14 +69,15 @@ int main(int argc, char **argv) { return 1; } - bringauto::aeron_communication::AeronDriver aeronDriver {}; - std::jthread aeronDriverThread([&aeronDriver]() { aeronDriver.run(); }); - baset::Logger::logInfo("Aeron Driver starting..."); - std::this_thread::sleep_for(std::chrono::seconds(2)); //TODO Not sure how much time is needed. + // bringauto::aeron_interface::AeronDriver aeronDriver {}; + // std::jthread aeronDriverThread([&aeronDriver]() { aeronDriver.run(); }); + // baset::Logger::logInfo("Aeron Driver starting..."); + // std::this_thread::sleep_for(std::chrono::seconds(3)); //TODO Not sure how much time is needed. + bas::ModuleLibrary moduleLibrary {}; try { - moduleLibrary.loadLibraries(context->settings->modulePaths); + moduleLibrary.loadLibraries(context->settings->modulePaths, context->settings->moduleBinaryPath); moduleLibrary.initStatusAggregators(context); } catch(std::exception &e) { std::cerr << "[ERROR] Error occurred during module initialization: " << e.what() << std::endl; @@ -106,12 +107,12 @@ int main(int argc, char **argv) { context->ioContext.stop(); } - aeronDriver.stop(); + // aeronDriver.stop(); contextThread2.join(); contextThread1.join(); externalClientThread.join(); moduleHandlerThread.join(); - aeronDriverThread.join(); + // aeronDriverThread.join(); internalServer.destroy(); moduleHandler.destroy(); diff --git a/source/bringauto/aeron_communication/AeronClient.cpp b/source/bringauto/aeron_communication/AeronClient.cpp deleted file mode 100644 index dec69df..0000000 --- a/source/bringauto/aeron_communication/AeronClient.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include -#include -#include - - - -namespace bringauto::aeron_communication { - -using log = settings::Logger; - -AeronClient::AeronClient() { - aeronContext_.newPublicationHandler( - [](const std::string &channel, std::int32_t streamId, std::int32_t sessionId, std::int64_t correlationId) { - log::logDebug("AeronClient: New publication on channel: " + channel + - " with correlationId: " + std::to_string(correlationId) + - ", streamId: " + std::to_string(streamId) + - ", sessionId: " + std::to_string(sessionId) - ); - } - ); - - aeronContext_.newSubscriptionHandler( - [](const std::string &channel, std::int32_t streamId, std::int64_t correlationId) { - log::logDebug("AeronClient: New subscription on channel: " + channel + - " with correlationId: " + std::to_string(correlationId) + - ", streamId: " + std::to_string(streamId) - ); - } - ); - - aeronContext_.availableImageHandler( - [](aeron::Image &image) { - log::logDebug("AeronClient: Available image on correlationId: " + std::to_string(image.correlationId()) + - ", sessionId: " + std::to_string(image.sessionId()) + - ", position: " + std::to_string(image.position()) + - ", sourceIdentity: " + image.sourceIdentity() - ); - } - ); - - aeronContext_.unavailableImageHandler( - [](aeron::Image &image) { - log::logDebug("AeronClient: Unavailable image on correlationId: " + std::to_string(image.correlationId()) + - ", sessionId: " + std::to_string(image.sessionId()) + - ", position: " + std::to_string(image.position()) + - ", sourceIdentity: " + image.sourceIdentity() - ); - } - ); - - aeron_ = aeron::Aeron::connect(aeronContext_); - aeronFragmentAssembler_ = std::make_shared(handleMessage()); - aeronHandler_ = std::make_shared(aeronFragmentAssembler_->handler()); - aeronIdleStrategy_ = std::make_shared(); -} - - -void AeronClient::addModule(uint16_t moduleId) { - std::int64_t id = aeron_->addPublication( - std::string(settings::Constants::AERON_CONNECTION), - settings::aeron_to_module_stream_id_base + moduleId - ); - aeronPublication_ = aeron_->findPublication(id); - while (!aeronPublication_) { - std::this_thread::yield(); - aeronPublication_ = aeron_->findPublication(id); - } - - id = aeron_->addSubscription( - std::string(settings::Constants::AERON_CONNECTION), - settings::aeron_to_gateway_stream_id_base + moduleId - ); - aeronSubscription_ = aeron_->findSubscription(id); - while (!aeronSubscription_) { - std::this_thread::yield(); - aeronSubscription_ = aeron_->findSubscription(id); - } -} - - -void AeronClient::callModuleFunction(ModuleFunctions function, const std::string &message) { - std::string fullMessage = std::string(moduleFunctionToCode(function)) + ":" + message; - - std::array buff; - aeron::concurrent::AtomicBuffer srcBuffer(&buff[0], buff.size()); - char charMessage[256]; - const int messageLen = ::snprintf(charMessage, sizeof(charMessage), "%s", fullMessage.c_str()); - srcBuffer.putBytes(0, reinterpret_cast(charMessage), messageLen); - aeronPublication_->offer(srcBuffer, 0, messageLen); - waitForAeronResponse(); -} - - -std::string_view AeronClient::getMessage() const { - return aeronMessage_; -} - - -bool AeronClient::waitForAeronResponse() { - aeronPolling_ = true; - while (aeronPolling_) { - const int fragmentsRead = aeronSubscription_->poll(*aeronHandler_, 10); - aeronIdleStrategy_->idle(fragmentsRead); - } - return true; -} - - -aeron::fragment_handler_t AeronClient::handleMessage() { - return [&](const aeron::AtomicBuffer &buffer, aeron::util::index_t offset, aeron::util::index_t length, const aeron::Header &header) { - std::string message(reinterpret_cast(buffer.buffer()) + offset, static_cast(length)); - aeronMessage_ = message; - aeronPolling_ = false; - }; -} - -std::string AeronClient::moduleFunctionToCode(ModuleFunctions function) const { - return std::to_string(static_cast(function)); -} - -} diff --git a/source/bringauto/aeron_communication/AeronDriver.cpp b/source/bringauto/aeron_communication/AeronDriver.cpp deleted file mode 100644 index f6a4b13..0000000 --- a/source/bringauto/aeron_communication/AeronDriver.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include - -#include - - - -static bringauto::aeron_communication::AeronDriver* globalDriverInstance = nullptr; - -void terminationHook(void *state) { - if (globalDriverInstance == nullptr) { - globalDriverInstance->stop(); - } -} - -void signalHandler(int signal) { - if (globalDriverInstance != nullptr) { - globalDriverInstance->stop(); - } -} - - -namespace bringauto::aeron_communication { - -AeronDriver::AeronDriver() { - globalDriverInstance = this; - signal(SIGINT, signalHandler); - signal(SIGTERM, signalHandler); - aeron_driver_context_init(&driverContext_); - aeron_driver_context_set_driver_termination_hook(driverContext_, terminationHook, NULL); - driverContext_->agent_on_start_func_delegate = driverContext_->agent_on_start_func; - driverContext_->agent_on_start_state_delegate = driverContext_->agent_on_start_state; - aeron_driver_context_set_agent_on_start_function(driverContext_, aeron_set_thread_affinity_on_start, driverContext_); - aeron_driver_init(&driver_, driverContext_); -} - - -void AeronDriver::run() { - aeron_driver_start(driver_, true); - while (isRunning()) { - aeron_driver_main_idle_strategy(driver_, aeron_driver_main_do_work(driver_)); - } -} - - -bool AeronDriver::isRunning() const { - int result; - AERON_GET_ACQUIRE(result, exitStatus_); - return result == AERON_NULL_VALUE; -} - - -void AeronDriver::stop() { - AERON_SET_RELEASE(exitStatus_, EXIT_SUCCESS); -} - -} diff --git a/source/bringauto/external_client/ErrorAggregator.cpp b/source/bringauto/external_client/ErrorAggregator.cpp index b0f650f..8989061 100644 --- a/source/bringauto/external_client/ErrorAggregator.cpp +++ b/source/bringauto/external_client/ErrorAggregator.cpp @@ -8,7 +8,7 @@ namespace bringauto::external_client { -int ErrorAggregator::init_error_aggregator(const std::shared_ptr &library) { +int ErrorAggregator::init_error_aggregator(const std::shared_ptr &library) { //TODO select type from config module_ = library; return OK; } diff --git a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp b/source/bringauto/modules/ModuleManagerLibraryHandler.cpp index 801b04b..6d21bba 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandler.cpp @@ -1,8 +1,6 @@ #include #include -#include -#include #include #include @@ -56,11 +54,6 @@ void ModuleManagerLibraryHandler::loadLibrary(const std::filesystem::path &path) "allocate")); deallocate_ = reinterpret_cast::fncptr>(checkFunction( "deallocate")); - - if (aeronClient_ != nullptr) { - aeronClient_->addModule(getModuleNumber_()); - } - log::logDebug("Library " + path.string() + " was successfully loaded"); } @@ -93,13 +86,6 @@ int ModuleManagerLibraryHandler::sendStatusCondition(const Buffer ¤t_statu new_status_raw_buffer = new_status.getStructBuffer(); } - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction( - aeron_communication::AeronClient::ModuleFunctions::SEND_STATUS_CONDITION, - constructAeronMessage({¤t_status_raw_buffer, &new_status_raw_buffer}, device_type) - ); - return std::stoi(std::string(aeronClient_->getMessage())); - } return sendStatusCondition_(current_status_raw_buffer, new_status_raw_buffer, device_type); } @@ -122,17 +108,8 @@ int ModuleManagerLibraryHandler::generateCommand(Buffer &generated_command, current_command_raw_buffer = current_command.getStructBuffer(); } - int ret; - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction( - aeron_communication::AeronClient::ModuleFunctions::GENERATE_COMMAND, - constructAeronMessage({&new_status_raw_buffer, ¤t_status_raw_buffer, ¤t_command_raw_buffer}, device_type) - ); - ret = parseAeronResponse(raw_buffer, aeronClient_->getMessage()); - } else { - ret = generateCommand_(&raw_buffer, new_status_raw_buffer, - current_status_raw_buffer, current_command_raw_buffer, device_type); - } + int ret = generateCommand_(&raw_buffer, new_status_raw_buffer, + current_status_raw_buffer, current_command_raw_buffer, device_type); if (ret == OK) { generated_command = constructBufferByTakeOwnership(raw_buffer); } else { @@ -155,16 +132,7 @@ int ModuleManagerLibraryHandler::aggregateStatus(Buffer &aggregated_status, new_status_raw_buffer = new_status.getStructBuffer(); } - int ret; - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction( - aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_STATUS, - constructAeronMessage({¤t_status_raw_buffer, &new_status_raw_buffer}, device_type) - ); - ret = parseAeronResponse(raw_buffer, aeronClient_->getMessage()); - } else { - ret = aggregateStatus_(&raw_buffer, current_status_raw_buffer, new_status_raw_buffer, device_type); - } + const int ret = aggregateStatus_(&raw_buffer, current_status_raw_buffer, new_status_raw_buffer, device_type); if (ret == OK) { aggregated_status = constructBufferByTakeOwnership(raw_buffer); } else { @@ -187,16 +155,8 @@ int ModuleManagerLibraryHandler::aggregateError(Buffer &error_message, if (status.isAllocated()) { status_raw_buffer = status.getStructBuffer(); } - int ret; - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction( - aeron_communication::AeronClient::ModuleFunctions::AGGREGATE_ERROR, - constructAeronMessage({¤t_error_raw_buffer, &status_raw_buffer}, device_type) - ); - ret = parseAeronResponse(raw_buffer, aeronClient_->getMessage()); - } else { - ret = aggregateError_(&raw_buffer, current_error_raw_buffer, status_raw_buffer, device_type); - } + + const int ret = aggregateError_(&raw_buffer, current_error_raw_buffer, status_raw_buffer, device_type); if (ret == OK) { error_message = constructBufferByTakeOwnership(raw_buffer); } else { @@ -207,16 +167,7 @@ int ModuleManagerLibraryHandler::aggregateError(Buffer &error_message, int ModuleManagerLibraryHandler::generateFirstCommand(Buffer &default_command, unsigned int device_type) { struct ::buffer raw_buffer {}; - int ret; - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction( - aeron_communication::AeronClient::ModuleFunctions::GENERATE_FIRST_COMMAND, - constructAeronMessage({}, device_type) - ); - ret = parseAeronResponse(raw_buffer, aeronClient_->getMessage()); - } else { - ret = generateFirstCommand_(&raw_buffer, device_type); - } + const int ret = generateFirstCommand_(&raw_buffer, device_type); if (ret == OK) { default_command = constructBufferByTakeOwnership(raw_buffer); } else { @@ -230,13 +181,6 @@ int ModuleManagerLibraryHandler::statusDataValid(const Buffer &status, unsigned if (status.isAllocated()) { raw_buffer = status.getStructBuffer(); } - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction( - aeron_communication::AeronClient::ModuleFunctions::STATUS_DATA_VALID, - constructAeronMessage({&raw_buffer}, device_type) - ); - return std::stoi(std::string(aeronClient_->getMessage())); - } return statusDataValid_(raw_buffer, device_type); } @@ -245,33 +189,14 @@ int ModuleManagerLibraryHandler::commandDataValid(const Buffer &command, unsigne if (command.isAllocated()) { raw_buffer = command.getStructBuffer(); } - if (aeronClient_ != nullptr) { - aeronClient_->callModuleFunction( - aeron_communication::AeronClient::ModuleFunctions::COMMAND_DATA_VALID, - constructAeronMessage({&raw_buffer}, device_type) - ); - return std::stoi(std::string(aeronClient_->getMessage())); - } return commandDataValid_(raw_buffer, device_type); } int ModuleManagerLibraryHandler::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { - // if (aeronClient_ != nullptr) { - // aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::ALLOCATE, "TODO"); - // if (aeronClient_->getMessage() != "allocate") { - // throw std::runtime_error("AeronClient did not receive the expected message"); - // } - // } return allocate_(buffer_pointer, size_in_bytes); } void ModuleManagerLibraryHandler::deallocate(struct buffer *buffer) const { - // if (aeronClient_ != nullptr) { - // aeronClient_->callModuleFunction(aeron_communication::AeronClient::ModuleFunctions::DEALLOCATE, "TODO"); - // if (aeronClient_->getMessage() != "deallocate") { - // throw std::runtime_error("AeronClient did not receive the expected message"); - // } - // } deallocate_(buffer); } @@ -294,24 +219,4 @@ Buffer ModuleManagerLibraryHandler::constructBufferByTakeOwnership(struct ::buff return { buffer, deallocate_ }; } -std::string ModuleManagerLibraryHandler::constructAeronMessage(const std::vector &buffers, int deviceType) const { - std::string message; - for (const auto &buff : buffers) { - message += std::string(static_cast(buff->data), buff->size_in_bytes) + std::string(settings::Constants::SEPARATOR); - } - return message + std::to_string(deviceType); -} - -int ModuleManagerLibraryHandler::parseAeronResponse(struct ::buffer &raw_buffer, std::string_view response) const { - size_t sepPos = response.find(settings::Constants::SEPARATOR); - if (sepPos == std::string::npos) { - throw std::runtime_error("Invalid response format: " + std::string(response)); - } - bringauto::fleet_protocol::cxx::StringAsBuffer::createBufferAndCopyData( - &raw_buffer, - response.substr(sepPos + settings::Constants::SEPARATOR.size()) - ); - return std::stoi(std::string(response.substr(0, sepPos))); -} - -} +} \ No newline at end of file diff --git a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp new file mode 100644 index 0000000..fbc930c --- /dev/null +++ b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp @@ -0,0 +1,207 @@ +#include +#include + +#include + +#include + + + +namespace bringauto::modules { + +async_function_execution::AsyncFunctionExecutor aeronClient { + async_function_execution::Config { + .isProducer = true, + .defaultTimeout = std::chrono::seconds(1) + }, + settings::FunctionIds::functionList +}; + +ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync() { + aeronClient.connect(); + deallocate_ = [this](struct buffer *buffer) { + this->deallocate(buffer); + }; +} + +ModuleManagerLibraryHandlerAsync::~ModuleManagerLibraryHandlerAsync() { + if (moduleBinaryPid_ != 0) { + ::kill(moduleBinaryPid_, SIGTERM); + } +} + +void ModuleManagerLibraryHandlerAsync::loadLibrary(const std::filesystem::path &path, const std::string &moduleBinaryPath) { + pid_t pid = ::fork(); + if (pid < 0) { + throw std::runtime_error { "Fork failed when trying to start module binary " + moduleBinaryPath }; + } + if (pid > 0) { + moduleBinaryPid_ = pid; + return; + } + char *args[4]; + args[0] = const_cast(moduleBinaryPath.c_str()); + args[1] = const_cast("-m"); + args[2] = const_cast(path.c_str()); + args[3] = nullptr; + if (::execv(moduleBinaryPath.c_str(), args) < 0) { + throw std::runtime_error { "Exec failed when trying to start module binary " + moduleBinaryPath }; + } +} + +int ModuleManagerLibraryHandlerAsync::getModuleNumber() const { + return aeronClient.callFunc(settings::FunctionIds::getModuleNumber); +} + +int ModuleManagerLibraryHandlerAsync::isDeviceTypeSupported(unsigned int device_type) const { + return aeronClient.callFunc(settings::FunctionIds::isDeviceTypeSupported, device_type); +} + +int ModuleManagerLibraryHandlerAsync::sendStatusCondition(const Buffer ¤t_status, + const Buffer &new_status, + unsigned int device_type) const { + settings::ConvertibleBuffer current_status_raw_buffer; + settings::ConvertibleBuffer new_status_raw_buffer; + + if (current_status.isAllocated()) { + current_status_raw_buffer = current_status.getStructBuffer(); + } + if (new_status.isAllocated()) { + new_status_raw_buffer = new_status.getStructBuffer(); + } + + return aeronClient.callFunc(settings::FunctionIds::sendStatusCondition, current_status_raw_buffer, new_status_raw_buffer, device_type); +} + +int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, + const Buffer &new_status, + const Buffer ¤t_status, + const Buffer ¤t_command, unsigned int device_type) { + settings::ConvertibleBuffer new_status_raw_buffer; + settings::ConvertibleBuffer current_status_raw_buffer; + settings::ConvertibleBuffer current_command_raw_buffer; + + if (new_status.isAllocated()) { + new_status_raw_buffer = new_status.getStructBuffer(); + } + if (current_status.isAllocated()) { + current_status_raw_buffer = current_status.getStructBuffer(); + } + if (current_command.isAllocated()) { + current_command_raw_buffer = current_command.getStructBuffer(); + } + + auto ret = aeronClient.callFunc(settings::FunctionIds::generateCommand, + new_status_raw_buffer, + current_status_raw_buffer, + current_command_raw_buffer, + device_type); + + if (ret.returnCode == OK) { + generated_command = constructBufferByTakeOwnership(ret.buffer); + } else { + generated_command = constructBuffer(); + } + return ret.returnCode; +} + +int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, + const Buffer ¤t_status, + const Buffer &new_status, unsigned int device_type) { + settings::ConvertibleBuffer current_status_raw_buffer; + settings::ConvertibleBuffer new_status_raw_buffer; + + if (current_status.isAllocated()) { + current_status_raw_buffer = current_status.getStructBuffer(); + } + if (new_status.isAllocated()) { + new_status_raw_buffer = new_status.getStructBuffer(); + } + + auto ret = aeronClient.callFunc(settings::FunctionIds::aggregateStatus, current_status_raw_buffer, new_status_raw_buffer, device_type); + if (ret.returnCode == OK) { + aggregated_status = constructBufferByTakeOwnership(ret.buffer); + } else { + aggregated_status = current_status; + } + return ret.returnCode; +} + +int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, + const Buffer ¤t_error_message, + const Buffer &status, unsigned int device_type) { + settings::ConvertibleBuffer current_error_raw_buffer; + settings::ConvertibleBuffer status_raw_buffer; + + if (current_error_message.isAllocated()) { + current_error_raw_buffer = current_error_message.getStructBuffer(); + } + if (status.isAllocated()) { + status_raw_buffer = status.getStructBuffer(); + } + + auto ret = aeronClient.callFunc(settings::FunctionIds::aggregateError, current_error_raw_buffer, status_raw_buffer, device_type); + if (ret.returnCode == OK) { + error_message = constructBufferByTakeOwnership(ret.buffer); + } else { + error_message = constructBuffer(); + } + return ret.returnCode; +} + +int ModuleManagerLibraryHandlerAsync::generateFirstCommand(Buffer &default_command, unsigned int device_type) { + auto ret = aeronClient.callFunc(settings::FunctionIds::generateFirstCommand, device_type); + if (ret.returnCode == OK) { + default_command = constructBufferByTakeOwnership(ret.buffer); + } else { + default_command = constructBuffer(); + } + return ret.returnCode; +} + +int ModuleManagerLibraryHandlerAsync::statusDataValid(const Buffer &status, unsigned int device_type) const { + settings::ConvertibleBuffer status_raw_buffer; + if (status.isAllocated()) { + status_raw_buffer = status.getStructBuffer(); + } + + return aeronClient.callFunc(settings::FunctionIds::statusDataValid, status_raw_buffer, device_type); +} + +int ModuleManagerLibraryHandlerAsync::commandDataValid(const Buffer &command, unsigned int device_type) const { + settings::ConvertibleBuffer command_raw_buffer; + if (command.isAllocated()) { + command_raw_buffer = command.getStructBuffer(); + } + + return aeronClient.callFunc(settings::FunctionIds::commandDataValid, command_raw_buffer, device_type); +} + +int ModuleManagerLibraryHandlerAsync::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { + return ::allocate(buffer_pointer, size_in_bytes); +} + +void ModuleManagerLibraryHandlerAsync::deallocate(struct buffer *buffer) const { + ::deallocate(buffer); +} + +Buffer ModuleManagerLibraryHandlerAsync::constructBuffer(std::size_t size) { + if (size == 0) { + return Buffer {}; + } + struct ::buffer buff {}; + buff.size_in_bytes = size; + if(allocate(&buff, size) != OK) { + throw std::bad_alloc {}; + } + return { buff, deallocate_ }; +} + +Buffer ModuleManagerLibraryHandlerAsync::constructBufferByTakeOwnership(struct ::buffer &buffer) { + if (buffer.data == nullptr) { + throw Buffer::BufferNotAllocated { "Buffer not allocated - cannot take ownership" }; + } + return { buffer, deallocate_ }; +} + +} diff --git a/source/bringauto/modules/memory_management/source/memory_management.cpp b/source/bringauto/modules/memory_management/source/memory_management.cpp index 834c9f5..bb270e8 100644 --- a/source/bringauto/modules/memory_management/source/memory_management.cpp +++ b/source/bringauto/modules/memory_management/source/memory_management.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include int allocate(struct buffer *buffer_pointer, size_t size_in_bytes){ diff --git a/source/bringauto/settings/SettingsParser.cpp b/source/bringauto/settings/SettingsParser.cpp index a5885cb..2ec7a6b 100644 --- a/source/bringauto/settings/SettingsParser.cpp +++ b/source/bringauto/settings/SettingsParser.cpp @@ -98,6 +98,10 @@ bool SettingsParser::areSettingsCorrect() const { std::cerr << "No shared module library provided." << std::endl; isCorrect = false; } + if(!settings_->moduleBinaryPath.empty() && !std::filesystem::exists(settings_->moduleBinaryPath)) { + std::cerr << "Given module binary path (" << settings_->moduleBinaryPath << ") does not exist." << std::endl; + isCorrect = false; + } if(!std::regex_match(settings_->company, std::regex("^[a-z0-9_]+$"))) { std::cerr << "Company name (" << settings_->company << ") is not valid." << std::endl; isCorrect = false; @@ -153,6 +157,7 @@ void SettingsParser::fillModulePathsSettings(const nlohmann::json &file) const { for(auto &[key, val]: file[std::string(Constants::MODULE_PATHS)].items()) { settings_->modulePaths[stoi(key)] = val; } + settings_->moduleBinaryPath = file[std::string(Constants::MODULE_BINARY_PATH)]; } void SettingsParser::fillExternalConnectionSettings(const nlohmann::json &file) const { diff --git a/source/bringauto/structures/ModuleLibrary.cpp b/source/bringauto/structures/ModuleLibrary.cpp index 20f6dfd..3b0a23d 100644 --- a/source/bringauto/structures/ModuleLibrary.cpp +++ b/source/bringauto/structures/ModuleLibrary.cpp @@ -6,19 +6,16 @@ namespace bringauto::structures { -ModuleLibrary::ModuleLibrary() { - aeronClient = std::make_shared(); -} - ModuleLibrary::~ModuleLibrary() { std::for_each(statusAggregators.cbegin(), statusAggregators.cend(), [](auto &pair) { pair.second->destroy_status_aggregator(); }); } -void ModuleLibrary::loadLibraries(const std::unordered_map &libPaths) { +void ModuleLibrary::loadLibraries(const std::unordered_map &libPaths, const std::string &moduleBinaryPath) { for(auto const &[key, path]: libPaths) { - auto handler = std::make_shared(aeronClient); - handler->loadLibrary(path); + auto handler = std::make_shared(); //TODO select type from config + handler->loadLibrary(path, moduleBinaryPath); + std::this_thread::sleep_for(std::chrono::seconds(3)); // TODO Not sure how much time is needed. if(handler->getModuleNumber() != key) { settings::Logger::logError("Module number from shared library {} does not match the module number from config. Config: {}, binary: {}.", path, key, handler->getModuleNumber()); throw std::runtime_error {"Module numbers from config are not corresponding to binaries. Unable to continue. Fix configuration file."}; From b0834cbe3096cfbe2db3c741d7e27da9c3771e72 Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Wed, 24 Sep 2025 15:46:42 +0200 Subject: [PATCH 06/15] async client as a package --- CMakeLists.txt | 7 +++---- cmake/Dependencies.cmake | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ca001a..dc71956 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,9 +55,8 @@ FIND_PACKAGE(libbringauto_logger 2.0.0 REQUIRED) FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) FIND_PACKAGE(ZLIB 1.2.11 REQUIRED) FIND_PACKAGE(fleet-protocol-cxx-helpers-static 1.1.1 REQUIRED) - -#temp -ADD_SUBDIRECTORY(${CMAKE_CURRENT_LIST_DIR}/aeron-interface) +FIND_PACKAGE(aeron 1.48.6 REQUIRED) +FIND_PACKAGE(async-function-execution-shared 0.1.0 REQUIRED) FILE(GLOB_RECURSE source_files "source/*") ADD_LIBRARY(module-gateway-lib STATIC "${source_files}") @@ -77,7 +76,7 @@ TARGET_LINK_LIBRARIES(module-gateway-lib PUBLIC PahoMqttCpp::paho-mqttpp3 ZLIB::ZLIB fleet-protocol-cxx-helpers-static::fleet-protocol-cxx-helpers-static - async-function-execution-static + async-function-execution-shared::async-function-execution-shared memory_management ${CMAKE_DL_LIBS} ) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 072f74e..eaa8a4a 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -10,6 +10,8 @@ BA_PACKAGE_LIBRARY(pahomqttc v1.3.9) BA_PACKAGE_LIBRARY(pahomqttcpp v1.3.2) BA_PACKAGE_LIBRARY(zlib v1.2.11 OUTPUT_PATH_VAR ZLIB_DIR) BA_PACKAGE_LIBRARY(fleet-protocol-cpp v1.1.1) +BA_PACKAGE_LIBRARY(aeron v1.48.6) +BA_PACKAGE_LIBRARY(async-function-execution v0.1.0) IF (BRINGAUTO_TESTS) BA_PACKAGE_LIBRARY(gtest v1.12.1) From 0c31aca856d493df08ab7ff6bab3a6cc930c9db5 Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Fri, 17 Oct 2025 14:17:10 +0200 Subject: [PATCH 07/15] refactor of module library handler --- CMLibStorage.cmake | 2 +- CMakeLists.txt | 10 +- README.md | 15 +- cmake/Dependencies.cmake | 2 +- .../external_client/ErrorAggregator.hpp | 7 +- include/bringauto/modules/Buffer.hpp | 2 +- .../modules/IModuleManagerLibraryHandler.hpp | 81 ++++++++++ .../ModuleManagerLibraryHandlerAsync.hpp | 138 +++++++++++++++--- ...p => ModuleManagerLibraryHandlerLocal.hpp} | 35 ++--- .../bringauto/modules/StatusAggregator.hpp | 11 +- include/bringauto/settings/Constants.hpp | 107 -------------- .../bringauto/structures/ModuleLibrary.hpp | 8 +- main.cpp | 8 - resources/config/README.md | 2 + resources/config/default.json | 1 + resources/config/example.json | 1 + resources/config/for_docker.json | 1 + .../external_client/ErrorAggregator.cpp | 2 +- source/bringauto/modules/ModuleHandler.cpp | 2 +- .../ModuleManagerLibraryHandlerAsync.cpp | 88 +++++------ ...p => ModuleManagerLibraryHandlerLocal.cpp} | 52 +++---- .../modules/memory_management/CMakeLists.txt | 2 +- source/bringauto/settings/SettingsParser.cpp | 18 +-- source/bringauto/structures/ModuleLibrary.cpp | 12 +- test/CMakeLists.txt | 2 +- test/include/ErrorAggregatorTests.hpp | 4 +- test/include/ExternalConnectionTests.hpp | 1 - test/include/StatusAggregatorTests.hpp | 4 +- test/include/testing_utils/ConfigMock.hpp | 1 + test/source/ErrorAggregatorTests.cpp | 8 +- test/source/StatusAggregatorTests.cpp | 8 +- 31 files changed, 357 insertions(+), 278 deletions(-) create mode 100644 include/bringauto/modules/IModuleManagerLibraryHandler.hpp rename include/bringauto/modules/{ModuleManagerLibraryHandler.hpp => ModuleManagerLibraryHandlerLocal.hpp} (81%) rename source/bringauto/modules/{ModuleManagerLibraryHandler.cpp => ModuleManagerLibraryHandlerLocal.cpp} (74%) diff --git a/CMLibStorage.cmake b/CMLibStorage.cmake index 36796ba..c9e0b59 100644 --- a/CMLibStorage.cmake +++ b/CMLibStorage.cmake @@ -1,6 +1,6 @@ FIND_PACKAGE(CMLIB REQUIRED COMPONENTS CMCONF) -CMCONF_INIT_SYSTEM(FLEET_PROTOCOL) +CMCONF_INIT_SYSTEM(EXAMPLE) SET(STORAGE_LIST DEP) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc71956..7746990 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ FIND_PACKAGE(CMLIB REQUIRED ) -SET(BRINGAUTO_MODULE_GATEWAY_VERSION 1.3.5) +SET(BRINGAUTO_MODULE_GATEWAY_VERSION 1.4.0) SET(MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY "DEBUG" CACHE STRING "Minimum logger verbosity level for module-gateway") @@ -16,7 +16,7 @@ CMDEF_COMPILE_DEFINITIONS( "MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY=\"${MODULE_GATEWAY_MINIMUM_LOGGER_VERBOSITY}\"" ) SET(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMDEF_LIBRARY_INSTALL_DIR}") -SET(CMAKE_CXX_STANDARD 20) +SET(CMAKE_CXX_STANDARD 23) INCLUDE(CheckPIESupported) CHECK_PIE_SUPPORTED() @@ -48,7 +48,7 @@ SET(Protobuf_USE_STATIC_LIBS ON) FIND_PACKAGE(Boost 1.74 REQUIRED CONFIG) FIND_PACKAGE(Protobuf 3.21.12 REQUIRED) FIND_PACKAGE(cxxopts 3.1.1 REQUIRED) -FIND_PACKAGE(nlohmann_json 3.2.0 REQUIRED) +FIND_PACKAGE(nlohmann_json 3.10.5 REQUIRED) FIND_PACKAGE(PahoMqttCpp REQUIRED) FIND_PACKAGE(eclipse-paho-mqtt-c REQUIRED) FIND_PACKAGE(libbringauto_logger 2.0.0 REQUIRED) @@ -56,7 +56,7 @@ FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) FIND_PACKAGE(ZLIB 1.2.11 REQUIRED) FIND_PACKAGE(fleet-protocol-cxx-helpers-static 1.1.1 REQUIRED) FIND_PACKAGE(aeron 1.48.6 REQUIRED) -FIND_PACKAGE(async-function-execution-shared 0.1.0 REQUIRED) +FIND_PACKAGE(async-function-execution-shared 1.0.0 REQUIRED) FILE(GLOB_RECURSE source_files "source/*") ADD_LIBRARY(module-gateway-lib STATIC "${source_files}") @@ -101,7 +101,7 @@ TARGET_LINK_LIBRARIES(module-gateway-app PUBLIC module-gateway-lib) IF(BRINGAUTO_TESTS) ENABLE_TESTING() - #INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt) + INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt) INCLUDE(CTest) ENDIF(BRINGAUTO_TESTS) diff --git a/README.md b/README.md index be8a1b1..7290425 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,16 @@ connection is broken and as soon as the connection is up, then error aggregated - [protobuf](https://github.com/protocolbuffers/protobuf/tree/main/src) >= v3.21.12 - [cxxopts](https://github.com/jarro2783/cxxopts) >= v3.1.1 -- [boost](https://github.com/boostorg/boost) >= v1.74.0 -- [nlohmann-json](https://github.com/nlohmann/json) >= v3.2.0 -- [ba-logger](https://github.com/bringauto/ba-logger) >= v1.2.0 +- [boost](https://github.com/boostorg/boost) >= v1.86.0 +- [nlohmann-json](https://github.com/nlohmann/json) >= v3.10.5/ +- [pahomqtt](https://github.com/eclipse-paho/paho.mqtt.c) >= v1.3.9 +- [pahomqttcpp](https://github.com/eclipse-paho/paho.mqtt.cpp) >= v1.3.2 +- [zlib](https://github.com/madler/zlib) >= v1.2.11 +- [ba-logger](https://github.com/bringauto/ba-logger) >= v2.0.0 +- [fleet-protocol-interface](https://github.com/bringauto/fleet-protocol) >= v2.0.0 +- [fleet-protocol-cpp](https://github.com/bringauto/fleet-protocol-cpp) >= v1.1.1 +- [aeron](https://github.com/aeron-io/aeron) >= v1.48.6 +- [async-function-execution](https://github.com/bringauto/async-function-execution) >= 0.1.0 - g++ >= 10 or other compiler with c++20 support ## Build @@ -50,7 +57,7 @@ make ### Arguments -* required arguments: +* Required arguments: * `-c | --config-path=`path to json configuration file ([Configs Readme](./configs/README.md)) * All arguments: * `-h | --help` print help diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index eaa8a4a..e57bd00 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -11,7 +11,7 @@ BA_PACKAGE_LIBRARY(pahomqttcpp v1.3.2) BA_PACKAGE_LIBRARY(zlib v1.2.11 OUTPUT_PATH_VAR ZLIB_DIR) BA_PACKAGE_LIBRARY(fleet-protocol-cpp v1.1.1) BA_PACKAGE_LIBRARY(aeron v1.48.6) -BA_PACKAGE_LIBRARY(async-function-execution v0.1.0) +BA_PACKAGE_LIBRARY(async-function-execution v1.0.0) IF (BRINGAUTO_TESTS) BA_PACKAGE_LIBRARY(gtest v1.12.1) diff --git a/include/bringauto/external_client/ErrorAggregator.hpp b/include/bringauto/external_client/ErrorAggregator.hpp index e6724f4..e72fd82 100644 --- a/include/bringauto/external_client/ErrorAggregator.hpp +++ b/include/bringauto/external_client/ErrorAggregator.hpp @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include #include #include @@ -26,7 +25,7 @@ class ErrorAggregator { * @return OK if initialization was successful * @return NOT_OK if an error occurred */ - int init_error_aggregator(const std::shared_ptr &library); //TODO select type from config + int init_error_aggregator(const std::shared_ptr &library); /** * @short Clean up. @@ -112,7 +111,7 @@ class ErrorAggregator { modules::Buffer lastStatus {}; }; - std::shared_ptr module_ {}; //TODO select type from config + std::shared_ptr module_ {}; /** * @brief Map of devices states, key is device identification converted to string diff --git a/include/bringauto/modules/Buffer.hpp b/include/bringauto/modules/Buffer.hpp index a616e9b..235bf26 100644 --- a/include/bringauto/modules/Buffer.hpp +++ b/include/bringauto/modules/Buffer.hpp @@ -18,7 +18,7 @@ namespace bringauto::modules { */ struct Buffer final { - friend class ModuleManagerLibraryHandler; + friend class ModuleManagerLibraryHandlerLocal; friend class ModuleManagerLibraryHandlerAsync; Buffer() = default; diff --git a/include/bringauto/modules/IModuleManagerLibraryHandler.hpp b/include/bringauto/modules/IModuleManagerLibraryHandler.hpp new file mode 100644 index 0000000..75d51ec --- /dev/null +++ b/include/bringauto/modules/IModuleManagerLibraryHandler.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include + +#include +#include + + + +namespace bringauto::modules { + +/** + * @brief Class used to load and handle library created by module maintainer + */ +class IModuleManagerLibraryHandler { +public: + explicit IModuleManagerLibraryHandler() = default; + + virtual ~IModuleManagerLibraryHandler() = default; + + /** + * @brief Load library created by a module maintainer + * + * @param path path to the library + */ + virtual void loadLibrary(const std::filesystem::path &path) = 0; + + virtual int getModuleNumber() const = 0; + + virtual int isDeviceTypeSupported(unsigned int device_type) = 0; + + virtual int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const = 0; + + /** + * @short After executing the respective module function, an error might be thrown when allocating the buffer. + * + * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h + */ + virtual int generateCommand(Buffer &generated_command, const Buffer &new_status, + const Buffer ¤t_status, const Buffer ¤t_command, + unsigned int device_type) = 0; + + /** + * @short After executing the respective module function, an error might be thrown when allocating the buffer. + * + * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h + */ + virtual int aggregateStatus(Buffer &aggregated_status, const Buffer ¤t_status, + const Buffer &new_status, unsigned int device_type) = 0; + + /** + * @short After executing the respective module function, an error might be thrown when allocating the buffer. + * + * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h + */ + virtual int aggregateError(Buffer &error_message, const Buffer ¤t_error_message, const Buffer &status, + unsigned int device_type) = 0; + + /** + * @short After executing the respective module function, an error might be thrown when allocating the buffer. + * + * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h + */ + virtual int generateFirstCommand(Buffer &default_command, unsigned int device_type) = 0; + + virtual int statusDataValid(const Buffer &status, unsigned int device_type) const = 0; + + virtual int commandDataValid(const Buffer &command, unsigned int device_type) const = 0; + + /** + * @brief Constructs a buffer with the given size + * + * @param size size of the buffer + * @return a new Buffer object + */ + virtual Buffer constructBuffer(std::size_t size = 0) = 0; +}; + +} diff --git a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp index 92acf29..d1a0be1 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp @@ -1,38 +1,130 @@ #pragma once -#include +#include -#include +#include +#include + +#include -#include -#include namespace bringauto::modules { +struct ConvertibleBufferReturn final { + int returnCode {}; + struct ::buffer buffer {}; + ConvertibleBufferReturn() = default; + ConvertibleBufferReturn(int code, struct ::buffer buff) : returnCode(code), buffer(buff) {} + + std::span serialize() const { + size_t total_size = sizeof(int) + buffer.size_in_bytes; + uint8_t* data = new uint8_t[total_size]; + std::memcpy(data, &returnCode, sizeof(int)); + std::memcpy(data + sizeof(int), buffer.data, buffer.size_in_bytes); + return {data, total_size}; + } + void deserialize(std::span bytes) { + auto size = bytes.size(); + if (size < sizeof(int)) return; + std::memcpy(&returnCode, bytes.data(), sizeof(int)); + size -= sizeof(int); + allocate(&buffer, size); + std::memcpy(buffer.data, bytes.data() + sizeof(int), size); + buffer.size_in_bytes = size; + } +}; + +struct ConvertibleBuffer final { + struct ::buffer buffer {}; + ConvertibleBuffer() = default; + ConvertibleBuffer(struct ::buffer buff) : buffer(buff) {} + + std::span serialize() const { + return std::span {reinterpret_cast(buffer.data), buffer.size_in_bytes}; + } + void deserialize(std::span bytes) { + buffer.data = const_cast(bytes.data()); + buffer.size_in_bytes = bytes.size(); + } +}; + +inline static const async_function_execution::FunctionDefinition getModuleNumberAsync { + async_function_execution::FunctionId { 0 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments {} +}; + +inline static const async_function_execution::FunctionDefinition isDeviceTypeSupportedAsync { + async_function_execution::FunctionId { 1 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition sendStatusConditionAsync { + async_function_execution::FunctionId { 2 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition generateCommandAsync { + async_function_execution::FunctionId { 3 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition aggregateStatusAsync { + async_function_execution::FunctionId { 4 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition aggregateErrorAsync { + async_function_execution::FunctionId { 5 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition generateFirstCommandAsync { + async_function_execution::FunctionId { 6 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition statusDataValidAsync { + async_function_execution::FunctionId { 7 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition commandDataValidAsync { + async_function_execution::FunctionId { 8 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } +}; + /** * @brief Class used to load and handle library created by module maintainer */ -class ModuleManagerLibraryHandlerAsync { +class ModuleManagerLibraryHandlerAsync : public IModuleManagerLibraryHandler { public: - ModuleManagerLibraryHandlerAsync(); + explicit ModuleManagerLibraryHandlerAsync(const std::string &moduleBinaryPath); - ~ModuleManagerLibraryHandlerAsync(); + ~ModuleManagerLibraryHandlerAsync() override; /** * @brief Load library created by a module maintainer * * @param path path to the library - * @param moduleBinaryPath path to the module binary */ - void loadLibrary(const std::filesystem::path &path, const std::string &moduleBinaryPath); + void loadLibrary(const std::filesystem::path &path) override; - int getModuleNumber() const; + int getModuleNumber() const override; - int isDeviceTypeSupported(unsigned int device_type) const; + int isDeviceTypeSupported(unsigned int device_type) override; - int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const; + int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -41,7 +133,7 @@ class ModuleManagerLibraryHandlerAsync { */ int generateCommand(Buffer &generated_command, const Buffer &new_status, const Buffer ¤t_status, const Buffer ¤t_command, - unsigned int device_type); + unsigned int device_type) override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -49,7 +141,7 @@ class ModuleManagerLibraryHandlerAsync { * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h */ int aggregateStatus(Buffer &aggregated_status, const Buffer ¤t_status, - const Buffer &new_status, unsigned int device_type); + const Buffer &new_status, unsigned int device_type) override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -57,18 +149,18 @@ class ModuleManagerLibraryHandlerAsync { * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h */ int aggregateError(Buffer &error_message, const Buffer ¤t_error_message, const Buffer &status, - unsigned int device_type); + unsigned int device_type) override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. * * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h */ - int generateFirstCommand(Buffer &default_command, unsigned int device_type); + int generateFirstCommand(Buffer &default_command, unsigned int device_type) override; - int statusDataValid(const Buffer &status, unsigned int device_type) const; + int statusDataValid(const Buffer &status, unsigned int device_type) const override; - int commandDataValid(const Buffer &command, unsigned int device_type) const; + int commandDataValid(const Buffer &command, unsigned int device_type) const override; /** * @brief Constructs a buffer with the given size @@ -76,7 +168,7 @@ class ModuleManagerLibraryHandlerAsync { * @param size size of the buffer * @return a new Buffer object */ - Buffer constructBuffer(std::size_t size = 0); + Buffer constructBuffer(std::size_t size = 0) override; private: @@ -94,8 +186,12 @@ class ModuleManagerLibraryHandlerAsync { std::function deallocate_ {}; - /// Process id of the module binary - pid_t moduleBinaryPid_ {}; + /// Path to the module binary + std::string moduleBinaryPath_ {}; + /// Process of the module binary + boost::process::child moduleBinaryProcess_ {}; + /// TODO find a way to not need this + std::mutex tmpMutex_ {}; }; } diff --git a/include/bringauto/modules/ModuleManagerLibraryHandler.hpp b/include/bringauto/modules/ModuleManagerLibraryHandlerLocal.hpp similarity index 81% rename from include/bringauto/modules/ModuleManagerLibraryHandler.hpp rename to include/bringauto/modules/ModuleManagerLibraryHandlerLocal.hpp index 8d12252..a1fd601 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandler.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandlerLocal.hpp @@ -1,11 +1,6 @@ #pragma once -#include - -#include - -#include -#include +#include @@ -14,24 +9,24 @@ namespace bringauto::modules { /** * @brief Class used to load and handle library created by module maintainer */ -class ModuleManagerLibraryHandler { +class ModuleManagerLibraryHandlerLocal : public IModuleManagerLibraryHandler { public: - ModuleManagerLibraryHandler() = default; + explicit ModuleManagerLibraryHandlerLocal() = default; - ~ModuleManagerLibraryHandler(); + ~ModuleManagerLibraryHandlerLocal() override; /** * @brief Load library created by a module maintainer * * @param path path to the library */ - void loadLibrary(const std::filesystem::path &path); + void loadLibrary(const std::filesystem::path &path) override; - int getModuleNumber() const; + int getModuleNumber() const override; - int isDeviceTypeSupported(unsigned int device_type) const; + int isDeviceTypeSupported(unsigned int device_type) override; - int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const; + int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -40,7 +35,7 @@ class ModuleManagerLibraryHandler { */ int generateCommand(Buffer &generated_command, const Buffer &new_status, const Buffer ¤t_status, const Buffer ¤t_command, - unsigned int device_type); + unsigned int device_type) override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -48,7 +43,7 @@ class ModuleManagerLibraryHandler { * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h */ int aggregateStatus(Buffer &aggregated_status, const Buffer ¤t_status, - const Buffer &new_status, unsigned int device_type); + const Buffer &new_status, unsigned int device_type) override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -56,18 +51,18 @@ class ModuleManagerLibraryHandler { * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h */ int aggregateError(Buffer &error_message, const Buffer ¤t_error_message, const Buffer &status, - unsigned int device_type); + unsigned int device_type) override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. * * @see fleet-protocol/lib/module_maintainer/module_gateway/include/module_manager.h */ - int generateFirstCommand(Buffer &default_command, unsigned int device_type); + int generateFirstCommand(Buffer &default_command, unsigned int device_type) override; - int statusDataValid(const Buffer &status, unsigned int device_type) const; + int statusDataValid(const Buffer &status, unsigned int device_type) const override; - int commandDataValid(const Buffer &command, unsigned int device_type) const; + int commandDataValid(const Buffer &command, unsigned int device_type) const override; /** * @brief Constructs a buffer with the given size @@ -75,7 +70,7 @@ class ModuleManagerLibraryHandler { * @param size size of the buffer * @return a new Buffer object */ - Buffer constructBuffer(std::size_t size = 0); + Buffer constructBuffer(std::size_t size = 0) override; private: diff --git a/include/bringauto/modules/StatusAggregator.hpp b/include/bringauto/modules/StatusAggregator.hpp index 4cf426f..33580bf 100644 --- a/include/bringauto/modules/StatusAggregator.hpp +++ b/include/bringauto/modules/StatusAggregator.hpp @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include #include #include @@ -21,9 +20,9 @@ class StatusAggregator { public: explicit StatusAggregator(const std::shared_ptr &context, - const std::shared_ptr &libraryHandler): context_ { context }, //TODO select type from config - module_ { - libraryHandler } {}; + const std::shared_ptr &libraryHandler): context_ { context }, + module_ { + libraryHandler } {}; StatusAggregator() = default; @@ -187,7 +186,7 @@ class StatusAggregator { std::shared_ptr context_ {}; - const std::shared_ptr module_ {}; //TODO select type from config + const std::shared_ptr module_ {}; /** * @brief Map of devices states, key is device identification diff --git a/include/bringauto/settings/Constants.hpp b/include/bringauto/settings/Constants.hpp index 34dd5fb..28a0470 100644 --- a/include/bringauto/settings/Constants.hpp +++ b/include/bringauto/settings/Constants.hpp @@ -182,111 +182,4 @@ class Constants { inline static constexpr std::string_view SEPARATOR { ":::" }; }; -struct ConvertibleBufferReturn final { - int returnCode { 0 }; //TODO temporary, need to serialize return code aswell - struct ::buffer buffer {}; - ConvertibleBufferReturn() = default; - ConvertibleBufferReturn(int code, struct ::buffer buff) : returnCode(code), buffer(buff) {} - ~ConvertibleBufferReturn() { - buffer.data = nullptr; - } - - std::span serialize() const { - return std::span {reinterpret_cast(buffer.data), buffer.size_in_bytes}; - } - void deserialize(std::span bytes) { - if(buffer.data != nullptr) { - delete[] buffer.data; - } - buffer.size_in_bytes = bytes.size(); - buffer.data = new uint8_t[buffer.size_in_bytes]; - std::memcpy(buffer.data, bytes.data(), buffer.size_in_bytes); - } -}; - -struct ConvertibleBuffer final { - struct ::buffer buffer {}; - ConvertibleBuffer() = default; - ConvertibleBuffer(struct ::buffer buff) : buffer(buff) {} - - std::span serialize() const { - return std::span {reinterpret_cast(buffer.data), buffer.size_in_bytes}; - } - void deserialize(std::span bytes) { - buffer.data = const_cast(bytes.data()); - buffer.size_in_bytes = bytes.size(); - } -}; - -class FunctionIds { -public: - inline static const async_function_execution::FunctionDefinition getModuleNumber { - async_function_execution::FunctionId { 0 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments {} - }; - - inline static const async_function_execution::FunctionDefinition isDeviceTypeSupported { - async_function_execution::FunctionId { 1 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments { uint32_t {} } - }; - - inline static const async_function_execution::FunctionDefinition sendStatusCondition { - async_function_execution::FunctionId { 2 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } - }; - - inline static const async_function_execution::FunctionDefinition generateCommand { - async_function_execution::FunctionId { 3 }, - async_function_execution::Return { ConvertibleBufferReturn {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } - }; - - inline static const async_function_execution::FunctionDefinition aggregateStatus { - async_function_execution::FunctionId { 4 }, - async_function_execution::Return { ConvertibleBufferReturn {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } - }; - - inline static const async_function_execution::FunctionDefinition aggregateError { - async_function_execution::FunctionId { 5 }, - async_function_execution::Return { ConvertibleBufferReturn {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } - }; - - inline static const async_function_execution::FunctionDefinition generateFirstCommand { - async_function_execution::FunctionId { 6 }, - async_function_execution::Return { ConvertibleBufferReturn {} }, - async_function_execution::Arguments { uint32_t {} } - }; - - inline static const async_function_execution::FunctionDefinition statusDataValid { - async_function_execution::FunctionId { 7 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } - }; - - inline static const async_function_execution::FunctionDefinition commandDataValid { - async_function_execution::FunctionId { 8 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } - }; - - inline static const async_function_execution::FunctionList functionList { - std::tuple { - getModuleNumber, - isDeviceTypeSupported, - sendStatusCondition, - generateCommand, - aggregateStatus, - aggregateError, - generateFirstCommand, - statusDataValid, - commandDataValid - } - }; -}; - } diff --git a/include/bringauto/structures/ModuleLibrary.hpp b/include/bringauto/structures/ModuleLibrary.hpp index 124e84c..7cb1360 100644 --- a/include/bringauto/structures/ModuleLibrary.hpp +++ b/include/bringauto/structures/ModuleLibrary.hpp @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include #include #include @@ -22,8 +21,9 @@ struct ModuleLibrary { * @brief Load libraries from paths * * @param libPaths paths to the libraries + * @param moduleBinaryPath path to module binary for async function execution over shared memory */ - void loadLibraries(const std::unordered_map &libPaths, const std::string &moduleBinaryPath); + void loadLibraries(const std::unordered_map &libPaths, const std::string &moduleBinaryPath = ""); /** * @brief Initialize status aggregators with context @@ -32,7 +32,7 @@ struct ModuleLibrary { */ void initStatusAggregators(std::shared_ptr &context); /// Map of module handlers, key is module id - std::unordered_map> moduleLibraryHandlers {}; //TODO select type from config + std::unordered_map> moduleLibraryHandlers {}; /// Map of status aggregators, key is module id std::unordered_map> statusAggregators {}; }; diff --git a/main.cpp b/main.cpp index a220471..46e5fe4 100644 --- a/main.cpp +++ b/main.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -69,11 +68,6 @@ int main(int argc, char **argv) { return 1; } - // bringauto::aeron_interface::AeronDriver aeronDriver {}; - // std::jthread aeronDriverThread([&aeronDriver]() { aeronDriver.run(); }); - // baset::Logger::logInfo("Aeron Driver starting..."); - // std::this_thread::sleep_for(std::chrono::seconds(3)); //TODO Not sure how much time is needed. - bas::ModuleLibrary moduleLibrary {}; try { @@ -107,12 +101,10 @@ int main(int argc, char **argv) { context->ioContext.stop(); } - // aeronDriver.stop(); contextThread2.join(); contextThread1.join(); externalClientThread.join(); moduleHandlerThread.join(); - // aeronDriverThread.join(); internalServer.destroy(); moduleHandler.destroy(); diff --git a/resources/config/README.md b/resources/config/README.md index 8451e27..2889f14 100644 --- a/resources/config/README.md +++ b/resources/config/README.md @@ -22,6 +22,8 @@ Note: at least one logging sink needs to be used ### module-paths: * key : number that corresponds to the module being loaded * value : path to the module shared library file +### module-binary-path: + - path to the module binary for async function execution over shared memory. If none is provided, the module will be loaded as a shared library ### external-connection: * company : company name used as identification in external connection (string) * vehicle-name : vehicle name used as identification in external connection (string) diff --git a/resources/config/default.json b/resources/config/default.json index 3fc59eb..0402e35 100644 --- a/resources/config/default.json +++ b/resources/config/default.json @@ -14,6 +14,7 @@ "port": 8888 }, "module-paths": { }, + "module-binary-path": "", "external-connection" : { "company": "", "vehicle-name": "", diff --git a/resources/config/example.json b/resources/config/example.json index 3bb8d46..2a5bc02 100644 --- a/resources/config/example.json +++ b/resources/config/example.json @@ -20,6 +20,7 @@ "1000": "./libmission-module-gateway-shared.so" }, + "module-binary-path": "", "external-connection" : { "company" : "bringauto", "vehicle-name" : "virtual_vehicle", diff --git a/resources/config/for_docker.json b/resources/config/for_docker.json index c28bea5..68cbcb4 100644 --- a/resources/config/for_docker.json +++ b/resources/config/for_docker.json @@ -18,6 +18,7 @@ "2": "/home/bringauto/modules/io_module/lib/libio-module-gateway-shared.so", "3": "/home/bringauto/modules/transparent_module/lib/libtransparent-module-gateway-shared.so" }, + "module-binary-path": "", "external-connection" : { "company" : "bringauto", "vehicle-name" : "virtual_vehicle", diff --git a/source/bringauto/external_client/ErrorAggregator.cpp b/source/bringauto/external_client/ErrorAggregator.cpp index 8989061..4f83b6c 100644 --- a/source/bringauto/external_client/ErrorAggregator.cpp +++ b/source/bringauto/external_client/ErrorAggregator.cpp @@ -8,7 +8,7 @@ namespace bringauto::external_client { -int ErrorAggregator::init_error_aggregator(const std::shared_ptr &library) { //TODO select type from config +int ErrorAggregator::init_error_aggregator(const std::shared_ptr &library) { module_ = library; return OK; } diff --git a/source/bringauto/modules/ModuleHandler.cpp b/source/bringauto/modules/ModuleHandler.cpp index 5f1bd81..5059cdb 100644 --- a/source/bringauto/modules/ModuleHandler.cpp +++ b/source/bringauto/modules/ModuleHandler.cpp @@ -194,7 +194,7 @@ void ModuleHandler::handleStatus(const ip::DeviceStatus &status) const { settings::Logger::logWarning("Add status to aggregator failed with return code: {}", addStatusToAggregatorRc); return; } - + Buffer commandBuffer {}; int getCommandRc = statusAggregator->get_command(statusBuffer, deviceId, commandBuffer); if(getCommandRc == OK) { diff --git a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp index fbc930c..00d3a5f 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp @@ -14,10 +14,21 @@ async_function_execution::AsyncFunctionExecutor aeronClient { .isProducer = true, .defaultTimeout = std::chrono::seconds(1) }, - settings::FunctionIds::functionList + async_function_execution::FunctionList { + getModuleNumberAsync, + isDeviceTypeSupportedAsync, + sendStatusConditionAsync, + generateCommandAsync, + aggregateStatusAsync, + aggregateErrorAsync, + generateFirstCommandAsync, + statusDataValidAsync, + commandDataValidAsync + } }; -ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync() { +ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync(const std::string &moduleBinaryPath) : + moduleBinaryPath_ { moduleBinaryPath } { aeronClient.connect(); deallocate_ = [this](struct buffer *buffer) { this->deallocate(buffer); @@ -25,43 +36,34 @@ ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync() { } ModuleManagerLibraryHandlerAsync::~ModuleManagerLibraryHandlerAsync() { - if (moduleBinaryPid_ != 0) { - ::kill(moduleBinaryPid_, SIGTERM); + if (moduleBinaryProcess_.valid()) { + ::kill(moduleBinaryProcess_.id(), SIGTERM); + moduleBinaryProcess_.wait(); } } -void ModuleManagerLibraryHandlerAsync::loadLibrary(const std::filesystem::path &path, const std::string &moduleBinaryPath) { - pid_t pid = ::fork(); - if (pid < 0) { - throw std::runtime_error { "Fork failed when trying to start module binary " + moduleBinaryPath }; - } - if (pid > 0) { - moduleBinaryPid_ = pid; - return; - } - char *args[4]; - args[0] = const_cast(moduleBinaryPath.c_str()); - args[1] = const_cast("-m"); - args[2] = const_cast(path.c_str()); - args[3] = nullptr; - if (::execv(moduleBinaryPath.c_str(), args) < 0) { - throw std::runtime_error { "Exec failed when trying to start module binary " + moduleBinaryPath }; +void ModuleManagerLibraryHandlerAsync::loadLibrary(const std::filesystem::path &path) { + moduleBinaryProcess_ = boost::process::child { moduleBinaryPath_, "-m", path.string() }; + if (!moduleBinaryProcess_.valid()) { + throw std::runtime_error { "Failed to start module binary " + moduleBinaryPath_ }; } + std::this_thread::sleep_for(std::chrono::seconds(1)); // TODO Not sure how much time is needed. } int ModuleManagerLibraryHandlerAsync::getModuleNumber() const { - return aeronClient.callFunc(settings::FunctionIds::getModuleNumber); + return aeronClient.callFunc(getModuleNumberAsync).value(); } -int ModuleManagerLibraryHandlerAsync::isDeviceTypeSupported(unsigned int device_type) const { - return aeronClient.callFunc(settings::FunctionIds::isDeviceTypeSupported, device_type); +int ModuleManagerLibraryHandlerAsync::isDeviceTypeSupported(unsigned int device_type) { + std::lock_guard lock { tmpMutex_ }; + return aeronClient.callFunc(isDeviceTypeSupportedAsync, device_type).value(); } int ModuleManagerLibraryHandlerAsync::sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const { - settings::ConvertibleBuffer current_status_raw_buffer; - settings::ConvertibleBuffer new_status_raw_buffer; + ConvertibleBuffer current_status_raw_buffer; + ConvertibleBuffer new_status_raw_buffer; if (current_status.isAllocated()) { current_status_raw_buffer = current_status.getStructBuffer(); @@ -70,16 +72,16 @@ int ModuleManagerLibraryHandlerAsync::sendStatusCondition(const Buffer ¤t_ new_status_raw_buffer = new_status.getStructBuffer(); } - return aeronClient.callFunc(settings::FunctionIds::sendStatusCondition, current_status_raw_buffer, new_status_raw_buffer, device_type); + return aeronClient.callFunc(sendStatusConditionAsync, current_status_raw_buffer, new_status_raw_buffer, device_type).value(); } int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, const Buffer &new_status, const Buffer ¤t_status, const Buffer ¤t_command, unsigned int device_type) { - settings::ConvertibleBuffer new_status_raw_buffer; - settings::ConvertibleBuffer current_status_raw_buffer; - settings::ConvertibleBuffer current_command_raw_buffer; + ConvertibleBuffer new_status_raw_buffer; + ConvertibleBuffer current_status_raw_buffer; + ConvertibleBuffer current_command_raw_buffer; if (new_status.isAllocated()) { new_status_raw_buffer = new_status.getStructBuffer(); @@ -91,11 +93,11 @@ int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, current_command_raw_buffer = current_command.getStructBuffer(); } - auto ret = aeronClient.callFunc(settings::FunctionIds::generateCommand, + auto ret = aeronClient.callFunc(generateCommandAsync, new_status_raw_buffer, current_status_raw_buffer, current_command_raw_buffer, - device_type); + device_type).value(); if (ret.returnCode == OK) { generated_command = constructBufferByTakeOwnership(ret.buffer); @@ -108,8 +110,8 @@ int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) { - settings::ConvertibleBuffer current_status_raw_buffer; - settings::ConvertibleBuffer new_status_raw_buffer; + ConvertibleBuffer current_status_raw_buffer; + ConvertibleBuffer new_status_raw_buffer; if (current_status.isAllocated()) { current_status_raw_buffer = current_status.getStructBuffer(); @@ -118,10 +120,12 @@ int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, new_status_raw_buffer = new_status.getStructBuffer(); } - auto ret = aeronClient.callFunc(settings::FunctionIds::aggregateStatus, current_status_raw_buffer, new_status_raw_buffer, device_type); + auto ret = aeronClient.callFunc(aggregateStatusAsync, current_status_raw_buffer, new_status_raw_buffer, device_type).value(); if (ret.returnCode == OK) { aggregated_status = constructBufferByTakeOwnership(ret.buffer); } else { + // Needed to properly free the allocated buffer memory + auto invalid_buffer = constructBufferByTakeOwnership(ret.buffer); aggregated_status = current_status; } return ret.returnCode; @@ -130,8 +134,8 @@ int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, const Buffer ¤t_error_message, const Buffer &status, unsigned int device_type) { - settings::ConvertibleBuffer current_error_raw_buffer; - settings::ConvertibleBuffer status_raw_buffer; + ConvertibleBuffer current_error_raw_buffer; + ConvertibleBuffer status_raw_buffer; if (current_error_message.isAllocated()) { current_error_raw_buffer = current_error_message.getStructBuffer(); @@ -140,7 +144,7 @@ int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, status_raw_buffer = status.getStructBuffer(); } - auto ret = aeronClient.callFunc(settings::FunctionIds::aggregateError, current_error_raw_buffer, status_raw_buffer, device_type); + auto ret = aeronClient.callFunc(aggregateErrorAsync, current_error_raw_buffer, status_raw_buffer, device_type).value(); if (ret.returnCode == OK) { error_message = constructBufferByTakeOwnership(ret.buffer); } else { @@ -150,7 +154,7 @@ int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, } int ModuleManagerLibraryHandlerAsync::generateFirstCommand(Buffer &default_command, unsigned int device_type) { - auto ret = aeronClient.callFunc(settings::FunctionIds::generateFirstCommand, device_type); + auto ret = aeronClient.callFunc(generateFirstCommandAsync, device_type).value(); if (ret.returnCode == OK) { default_command = constructBufferByTakeOwnership(ret.buffer); } else { @@ -160,21 +164,21 @@ int ModuleManagerLibraryHandlerAsync::generateFirstCommand(Buffer &default_comma } int ModuleManagerLibraryHandlerAsync::statusDataValid(const Buffer &status, unsigned int device_type) const { - settings::ConvertibleBuffer status_raw_buffer; + ConvertibleBuffer status_raw_buffer; if (status.isAllocated()) { status_raw_buffer = status.getStructBuffer(); } - return aeronClient.callFunc(settings::FunctionIds::statusDataValid, status_raw_buffer, device_type); + return aeronClient.callFunc(statusDataValidAsync, status_raw_buffer, device_type).value(); } int ModuleManagerLibraryHandlerAsync::commandDataValid(const Buffer &command, unsigned int device_type) const { - settings::ConvertibleBuffer command_raw_buffer; + ConvertibleBuffer command_raw_buffer; if (command.isAllocated()) { command_raw_buffer = command.getStructBuffer(); } - return aeronClient.callFunc(settings::FunctionIds::commandDataValid, command_raw_buffer, device_type); + return aeronClient.callFunc(commandDataValidAsync, command_raw_buffer, device_type).value(); } int ModuleManagerLibraryHandlerAsync::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { diff --git a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp b/source/bringauto/modules/ModuleManagerLibraryHandlerLocal.cpp similarity index 74% rename from source/bringauto/modules/ModuleManagerLibraryHandler.cpp rename to source/bringauto/modules/ModuleManagerLibraryHandlerLocal.cpp index 6d21bba..cadd716 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandler.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandlerLocal.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -20,14 +20,14 @@ struct FunctionTypeDeducer> { using log = settings::Logger; -ModuleManagerLibraryHandler::~ModuleManagerLibraryHandler() { +ModuleManagerLibraryHandlerLocal::~ModuleManagerLibraryHandlerLocal() { if(module_ != nullptr) { dlclose(module_); module_ = nullptr; } } -void ModuleManagerLibraryHandler::loadLibrary(const std::filesystem::path &path) { +void ModuleManagerLibraryHandlerLocal::loadLibrary(const std::filesystem::path &path) { module_ = dlmopen(LM_ID_NEWLM, path.c_str(), RTLD_LAZY); if(module_ == nullptr) { throw std::runtime_error {"Unable to load library " + path.string() + dlerror()}; @@ -57,7 +57,7 @@ void ModuleManagerLibraryHandler::loadLibrary(const std::filesystem::path &path) log::logDebug("Library " + path.string() + " was successfully loaded"); } -void *ModuleManagerLibraryHandler::checkFunction(const char *functionName) const { +void *ModuleManagerLibraryHandlerLocal::checkFunction(const char *functionName) const { const auto function = dlsym(module_, functionName); if(not function) { throw std::runtime_error {"Function " + std::string(functionName) + " is not included in library"}; @@ -65,17 +65,17 @@ void *ModuleManagerLibraryHandler::checkFunction(const char *functionName) const return function; } -int ModuleManagerLibraryHandler::getModuleNumber() const { +int ModuleManagerLibraryHandlerLocal::getModuleNumber() const { return getModuleNumber_(); } -int ModuleManagerLibraryHandler::isDeviceTypeSupported(unsigned int device_type) const { +int ModuleManagerLibraryHandlerLocal::isDeviceTypeSupported(unsigned int device_type) { return isDeviceTypeSupported_(device_type); } -int ModuleManagerLibraryHandler::sendStatusCondition(const Buffer ¤t_status, - const Buffer &new_status, - unsigned int device_type) const { +int ModuleManagerLibraryHandlerLocal::sendStatusCondition(const Buffer ¤t_status, + const Buffer &new_status, + unsigned int device_type) const { struct ::buffer current_status_raw_buffer {}; struct ::buffer new_status_raw_buffer {}; @@ -89,10 +89,10 @@ int ModuleManagerLibraryHandler::sendStatusCondition(const Buffer ¤t_statu return sendStatusCondition_(current_status_raw_buffer, new_status_raw_buffer, device_type); } -int ModuleManagerLibraryHandler::generateCommand(Buffer &generated_command, - const Buffer &new_status, - const Buffer ¤t_status, - const Buffer ¤t_command, unsigned int device_type) { +int ModuleManagerLibraryHandlerLocal::generateCommand(Buffer &generated_command, + const Buffer &new_status, + const Buffer ¤t_status, + const Buffer ¤t_command, unsigned int device_type) { struct ::buffer raw_buffer {}; struct ::buffer new_status_raw_buffer {}; struct ::buffer current_status_raw_buffer {}; @@ -118,9 +118,9 @@ int ModuleManagerLibraryHandler::generateCommand(Buffer &generated_command, return ret; } -int ModuleManagerLibraryHandler::aggregateStatus(Buffer &aggregated_status, - const Buffer ¤t_status, - const Buffer &new_status, unsigned int device_type) { +int ModuleManagerLibraryHandlerLocal::aggregateStatus(Buffer &aggregated_status, + const Buffer ¤t_status, + const Buffer &new_status, unsigned int device_type) { struct ::buffer raw_buffer {}; struct ::buffer current_status_raw_buffer {}; struct ::buffer new_status_raw_buffer {}; @@ -141,9 +141,9 @@ int ModuleManagerLibraryHandler::aggregateStatus(Buffer &aggregated_status, return ret; } -int ModuleManagerLibraryHandler::aggregateError(Buffer &error_message, - const Buffer ¤t_error_message, - const Buffer &status, unsigned int device_type) { +int ModuleManagerLibraryHandlerLocal::aggregateError(Buffer &error_message, + const Buffer ¤t_error_message, + const Buffer &status, unsigned int device_type) { struct ::buffer raw_buffer {}; struct ::buffer current_error_raw_buffer {}; @@ -165,7 +165,7 @@ int ModuleManagerLibraryHandler::aggregateError(Buffer &error_message, return ret; } -int ModuleManagerLibraryHandler::generateFirstCommand(Buffer &default_command, unsigned int device_type) { +int ModuleManagerLibraryHandlerLocal::generateFirstCommand(Buffer &default_command, unsigned int device_type) { struct ::buffer raw_buffer {}; const int ret = generateFirstCommand_(&raw_buffer, device_type); if (ret == OK) { @@ -176,7 +176,7 @@ int ModuleManagerLibraryHandler::generateFirstCommand(Buffer &default_command, u return ret; } -int ModuleManagerLibraryHandler::statusDataValid(const Buffer &status, unsigned int device_type) const { +int ModuleManagerLibraryHandlerLocal::statusDataValid(const Buffer &status, unsigned int device_type) const { struct ::buffer raw_buffer {}; if (status.isAllocated()) { raw_buffer = status.getStructBuffer(); @@ -184,7 +184,7 @@ int ModuleManagerLibraryHandler::statusDataValid(const Buffer &status, unsigned return statusDataValid_(raw_buffer, device_type); } -int ModuleManagerLibraryHandler::commandDataValid(const Buffer &command, unsigned int device_type) const { +int ModuleManagerLibraryHandlerLocal::commandDataValid(const Buffer &command, unsigned int device_type) const { struct ::buffer raw_buffer {}; if (command.isAllocated()) { raw_buffer = command.getStructBuffer(); @@ -192,15 +192,15 @@ int ModuleManagerLibraryHandler::commandDataValid(const Buffer &command, unsigne return commandDataValid_(raw_buffer, device_type); } -int ModuleManagerLibraryHandler::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { +int ModuleManagerLibraryHandlerLocal::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { return allocate_(buffer_pointer, size_in_bytes); } -void ModuleManagerLibraryHandler::deallocate(struct buffer *buffer) const { +void ModuleManagerLibraryHandlerLocal::deallocate(struct buffer *buffer) const { deallocate_(buffer); } -Buffer ModuleManagerLibraryHandler::constructBuffer(std::size_t size) { +Buffer ModuleManagerLibraryHandlerLocal::constructBuffer(std::size_t size) { if (size == 0) { return Buffer {}; } @@ -212,7 +212,7 @@ Buffer ModuleManagerLibraryHandler::constructBuffer(std::size_t size) { return { buff, deallocate_ }; } -Buffer ModuleManagerLibraryHandler::constructBufferByTakeOwnership(struct ::buffer &buffer) { +Buffer ModuleManagerLibraryHandlerLocal::constructBufferByTakeOwnership(struct ::buffer &buffer) { if (buffer.data == nullptr) { throw Buffer::BufferNotAllocated { "Buffer not allocated - cannot take ownership" }; } diff --git a/source/bringauto/modules/memory_management/CMakeLists.txt b/source/bringauto/modules/memory_management/CMakeLists.txt index e2e72b1..f47babe 100644 --- a/source/bringauto/modules/memory_management/CMakeLists.txt +++ b/source/bringauto/modules/memory_management/CMakeLists.txt @@ -1,7 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.25 FATAL_ERROR) PROJECT(ModuleGateway) -SET(CMAKE_CXX_STANDARD 20) +SET(CMAKE_CXX_STANDARD 23) FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) diff --git a/source/bringauto/settings/SettingsParser.cpp b/source/bringauto/settings/SettingsParser.cpp index 2ec7a6b..9a09d46 100644 --- a/source/bringauto/settings/SettingsParser.cpp +++ b/source/bringauto/settings/SettingsParser.cpp @@ -37,8 +37,6 @@ void SettingsParser::parseCmdArguments(int argc, char **argv) { cxxopts::value()); options.add_options("Internal Server")(std::string(Constants::PORT), "Port on which Server listens", cxxopts::value()); - options.add_options("Module Handler")(std::string(Constants::MODULE_PATHS), "Paths to shared module libraries", - cxxopts::value>()); options.allow_unrecognised_options(); cmdArguments_ = options.parse(argc, argv); @@ -55,8 +53,7 @@ bool SettingsParser::areCmdArgumentsCorrect() const { }; std::vector allParameters = { std::string(Constants::CONFIG_PATH), - std::string(Constants::PORT), - std::string(Constants::MODULE_PATHS) + std::string(Constants::PORT) }; allParameters.insert(allParameters.end(), requiredParams.begin(), requiredParams.end()); @@ -155,15 +152,16 @@ void SettingsParser::fillInternalServerSettings(const nlohmann::json &file) cons void SettingsParser::fillModulePathsSettings(const nlohmann::json &file) const { for(auto &[key, val]: file[std::string(Constants::MODULE_PATHS)].items()) { - settings_->modulePaths[stoi(key)] = val; + val.get_to(settings_->modulePaths[stoi(key)]); } - settings_->moduleBinaryPath = file[std::string(Constants::MODULE_BINARY_PATH)]; + file.at(std::string(Constants::MODULE_BINARY_PATH)).get_to(settings_->moduleBinaryPath); } void SettingsParser::fillExternalConnectionSettings(const nlohmann::json &file) const { - settings_->vehicleName = file[std::string(Constants::EXTERNAL_CONNECTION)][std::string( - Constants::VEHICLE_NAME)]; - settings_->company = file[std::string(Constants::EXTERNAL_CONNECTION)][std::string(Constants::COMPANY)]; + file.at(std::string(Constants::EXTERNAL_CONNECTION)).at(std::string(Constants::VEHICLE_NAME)).get_to( + settings_->vehicleName); + file.at(std::string(Constants::EXTERNAL_CONNECTION)).at(std::string(Constants::COMPANY)).get_to( + settings_->company); for(const auto &endpoint: file[std::string(Constants::EXTERNAL_CONNECTION)][std::string( Constants::EXTERNAL_ENDPOINTS)]) { @@ -183,7 +181,7 @@ void SettingsParser::fillExternalConnectionSettings(const nlohmann::json &file) continue; } - externalConnectionSettings.serverIp = endpoint[std::string(Constants::SERVER_IP)]; + endpoint.at(std::string(Constants::SERVER_IP)).get_to(externalConnectionSettings.serverIp); externalConnectionSettings.port = endpoint[std::string(Constants::PORT)]; externalConnectionSettings.modules = endpoint[std::string(Constants::MODULES)].get>(); diff --git a/source/bringauto/structures/ModuleLibrary.cpp b/source/bringauto/structures/ModuleLibrary.cpp index 3b0a23d..28bb84b 100644 --- a/source/bringauto/structures/ModuleLibrary.cpp +++ b/source/bringauto/structures/ModuleLibrary.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include @@ -12,10 +14,14 @@ ModuleLibrary::~ModuleLibrary() { } void ModuleLibrary::loadLibraries(const std::unordered_map &libPaths, const std::string &moduleBinaryPath) { + std::shared_ptr handler; for(auto const &[key, path]: libPaths) { - auto handler = std::make_shared(); //TODO select type from config - handler->loadLibrary(path, moduleBinaryPath); - std::this_thread::sleep_for(std::chrono::seconds(3)); // TODO Not sure how much time is needed. + if (moduleBinaryPath.empty()) { + handler = std::make_shared(); + } else { + handler = std::make_shared(moduleBinaryPath); + } + handler->loadLibrary(path); if(handler->getModuleNumber() != key) { settings::Logger::logError("Module number from shared library {} does not match the module number from config. Config: {}, binary: {}.", path, key, handler->getModuleNumber()); throw std::runtime_error {"Module numbers from config are not corresponding to binaries. Unable to continue. Fix configuration file."}; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 54f4550..dbf05a6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,7 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.25) PROJECT(ModuleGateway) -SET(CMAKE_CXX_STANDARD 20) +SET(CMAKE_CXX_STANDARD 23) ADD_SUBDIRECTORY("${CMAKE_CURRENT_LIST_DIR}/lib/example-module") diff --git a/test/include/ErrorAggregatorTests.hpp b/test/include/ErrorAggregatorTests.hpp index 2c176f0..64214d0 100644 --- a/test/include/ErrorAggregatorTests.hpp +++ b/test/include/ErrorAggregatorTests.hpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -31,7 +31,7 @@ class ErrorAggregatorTests: public ::testing::Test { bringauto::modules::Buffer init_status_buffer(); bringauto::external_client::ErrorAggregator errorAggregator_ {}; - std::shared_ptr libHandler_ {}; + std::shared_ptr libHandler_ {}; #ifdef DEBUG static constexpr const char* PATH_TO_MODULE { "./test/lib/example-module/libexample-module-gateway-sharedd.so" }; #else diff --git a/test/include/ExternalConnectionTests.hpp b/test/include/ExternalConnectionTests.hpp index 0fb241e..ea7e09f 100644 --- a/test/include/ExternalConnectionTests.hpp +++ b/test/include/ExternalConnectionTests.hpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/test/include/StatusAggregatorTests.hpp b/test/include/StatusAggregatorTests.hpp index a5a6922..848208e 100644 --- a/test/include/StatusAggregatorTests.hpp +++ b/test/include/StatusAggregatorTests.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include @@ -43,7 +43,7 @@ class StatusAggregatorTests: public ::testing::Test { std::unique_ptr statusAggregator_ {}; - std::shared_ptr libHandler_ {}; + std::shared_ptr libHandler_ {}; #ifdef DEBUG static constexpr const char* PATH_TO_MODULE { "./test/lib/example-module/libexample-module-gateway-sharedd.so" }; diff --git a/test/include/testing_utils/ConfigMock.hpp b/test/include/testing_utils/ConfigMock.hpp index 859f836..c30fda3 100644 --- a/test/include/testing_utils/ConfigMock.hpp +++ b/test/include/testing_utils/ConfigMock.hpp @@ -105,6 +105,7 @@ class ConfigMock { "\"module-paths\": {{\n" "{}\n" "}},\n" + "\"module-binary-path\": \"\",\n" "\"external-connection\": {{\n" "\"company\": \"{}\",\n" "\"vehicle-name\": \"{}\",\n" diff --git a/test/source/ErrorAggregatorTests.cpp b/test/source/ErrorAggregatorTests.cpp index 12d2dc4..258b3fc 100644 --- a/test/source/ErrorAggregatorTests.cpp +++ b/test/source/ErrorAggregatorTests.cpp @@ -1,5 +1,7 @@ #include #include +#include + #include @@ -15,7 +17,7 @@ bam::Buffer ErrorAggregatorTests::init_status_buffer() { } void ErrorAggregatorTests::SetUp(){ - libHandler_ = std::make_shared(); + libHandler_ = std::make_shared(); libHandler_->loadLibrary(PATH_TO_MODULE); errorAggregator_.init_error_aggregator(libHandler_); } @@ -26,14 +28,14 @@ void ErrorAggregatorTests::TearDown(){ TEST_F(ErrorAggregatorTests, init_error_aggregator_ok) { external_client::ErrorAggregator errorAggregatorTest {}; - const auto libHandler = std::make_shared(); + const auto libHandler = std::make_shared(); const int ret = errorAggregatorTest.init_error_aggregator(libHandler); EXPECT_EQ(ret, OK); } TEST_F(ErrorAggregatorTests, destroy_error_aggregator_ok) { external_client::ErrorAggregator errorAggregatorTest {}; - const auto libHandler = std::make_shared(); + const auto libHandler = std::make_shared(); errorAggregatorTest.init_error_aggregator(libHandler); const int ret = errorAggregatorTest.destroy_error_aggregator(); EXPECT_EQ(ret, OK); diff --git a/test/source/StatusAggregatorTests.cpp b/test/source/StatusAggregatorTests.cpp index 81ea7c9..813218c 100644 --- a/test/source/StatusAggregatorTests.cpp +++ b/test/source/StatusAggregatorTests.cpp @@ -1,5 +1,7 @@ #include #include +#include + #include @@ -41,7 +43,7 @@ void StatusAggregatorTests::remove_device_from_status_aggregator(){ void StatusAggregatorTests::SetUp(){ context_ = std::make_shared(); - libHandler_ = std::make_shared(); + libHandler_ = std::make_shared(); libHandler_->loadLibrary(PATH_TO_MODULE); statusAggregator_ = std::make_unique(context_, libHandler_); statusAggregator_->init_status_aggregator(); @@ -59,7 +61,7 @@ TEST_F(StatusAggregatorTests, init_status_aggregator_ok) { } TEST_F(StatusAggregatorTests, init_status_aggregator_bad_path) { - auto libHandler = std::make_shared(); + auto libHandler = std::make_shared(); EXPECT_THROW(libHandler->loadLibrary(WRONG_PATH_TO_MODULE), std::runtime_error); } @@ -94,7 +96,7 @@ TEST_F(StatusAggregatorTests, add_status_to_aggregator_status_register_device){ } TEST_F(StatusAggregatorTests, add_status_to_aggregator_without_aggregation){ - auto libHandler = std::make_shared(); + auto libHandler = std::make_shared(); libHandler->loadLibrary(PATH_TO_MODULE); add_status_to_aggregator(); auto size = std::string(BUTTON_PRESSED).size(); From e87960a6de2c7ec033fb725c8c9d95473a887419 Mon Sep 17 00:00:00 2001 From: Jan Kubalek Date: Fri, 17 Oct 2025 20:45:08 +0200 Subject: [PATCH 08/15] Set correct system name --- CMLibStorage.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMLibStorage.cmake b/CMLibStorage.cmake index c9e0b59..36796ba 100644 --- a/CMLibStorage.cmake +++ b/CMLibStorage.cmake @@ -1,6 +1,6 @@ FIND_PACKAGE(CMLIB REQUIRED COMPONENTS CMCONF) -CMCONF_INIT_SYSTEM(EXAMPLE) +CMCONF_INIT_SYSTEM(FLEET_PROTOCOL) SET(STORAGE_LIST DEP) From e18d1f777e63375f0ae6370af91e0dd6eac2a2ff Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Mon, 3 Nov 2025 09:10:00 +0100 Subject: [PATCH 09/15] added mutexes for async client; use filesystem::path for file paths --- CMLibStorage.cmake | 2 +- .../modules/IModuleManagerLibraryHandler.hpp | 8 +++---- .../ModuleManagerLibraryHandlerAsync.hpp | 23 ++++++++++++------ .../ModuleManagerLibraryHandlerLocal.hpp | 8 +++---- include/bringauto/settings/Settings.hpp | 4 ++-- .../bringauto/structures/ModuleLibrary.hpp | 9 ++++++- main.cpp | 6 ++++- .../ModuleManagerLibraryHandlerAsync.cpp | 24 ++++++++++++------- .../ModuleManagerLibraryHandlerLocal.cpp | 8 +++---- source/bringauto/structures/ModuleLibrary.cpp | 21 +++++++++++----- test/include/testing_utils/ConfigMock.hpp | 4 ++-- 11 files changed, 77 insertions(+), 40 deletions(-) diff --git a/CMLibStorage.cmake b/CMLibStorage.cmake index 36796ba..c9e0b59 100644 --- a/CMLibStorage.cmake +++ b/CMLibStorage.cmake @@ -1,6 +1,6 @@ FIND_PACKAGE(CMLIB REQUIRED COMPONENTS CMCONF) -CMCONF_INIT_SYSTEM(FLEET_PROTOCOL) +CMCONF_INIT_SYSTEM(EXAMPLE) SET(STORAGE_LIST DEP) diff --git a/include/bringauto/modules/IModuleManagerLibraryHandler.hpp b/include/bringauto/modules/IModuleManagerLibraryHandler.hpp index 75d51ec..49bf44b 100644 --- a/include/bringauto/modules/IModuleManagerLibraryHandler.hpp +++ b/include/bringauto/modules/IModuleManagerLibraryHandler.hpp @@ -27,11 +27,11 @@ class IModuleManagerLibraryHandler { */ virtual void loadLibrary(const std::filesystem::path &path) = 0; - virtual int getModuleNumber() const = 0; + virtual int getModuleNumber() = 0; virtual int isDeviceTypeSupported(unsigned int device_type) = 0; - virtual int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const = 0; + virtual int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) = 0; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -65,9 +65,9 @@ class IModuleManagerLibraryHandler { */ virtual int generateFirstCommand(Buffer &default_command, unsigned int device_type) = 0; - virtual int statusDataValid(const Buffer &status, unsigned int device_type) const = 0; + virtual int statusDataValid(const Buffer &status, unsigned int device_type) = 0; - virtual int commandDataValid(const Buffer &command, unsigned int device_type) const = 0; + virtual int commandDataValid(const Buffer &command, unsigned int device_type) = 0; /** * @brief Constructs a buffer with the given size diff --git a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp index d1a0be1..2300e06 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp @@ -109,7 +109,7 @@ inline static const async_function_execution::FunctionDefinition commandDataVali */ class ModuleManagerLibraryHandlerAsync : public IModuleManagerLibraryHandler { public: - explicit ModuleManagerLibraryHandlerAsync(const std::string &moduleBinaryPath); + explicit ModuleManagerLibraryHandlerAsync(const std::filesystem::path &moduleBinaryPath); ~ModuleManagerLibraryHandlerAsync() override; @@ -120,11 +120,11 @@ class ModuleManagerLibraryHandlerAsync : public IModuleManagerLibraryHandler { */ void loadLibrary(const std::filesystem::path &path) override; - int getModuleNumber() const override; + int getModuleNumber() override; int isDeviceTypeSupported(unsigned int device_type) override; - int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const override; + int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -158,9 +158,9 @@ class ModuleManagerLibraryHandlerAsync : public IModuleManagerLibraryHandler { */ int generateFirstCommand(Buffer &default_command, unsigned int device_type) override; - int statusDataValid(const Buffer &status, unsigned int device_type) const override; + int statusDataValid(const Buffer &status, unsigned int device_type) override; - int commandDataValid(const Buffer &command, unsigned int device_type) const override; + int commandDataValid(const Buffer &command, unsigned int device_type) override; /** * @brief Constructs a buffer with the given size @@ -187,11 +187,20 @@ class ModuleManagerLibraryHandlerAsync : public IModuleManagerLibraryHandler { std::function deallocate_ {}; /// Path to the module binary - std::string moduleBinaryPath_ {}; + std::filesystem::path moduleBinaryPath_ {}; /// Process of the module binary boost::process::child moduleBinaryProcess_ {}; + /// TODO find a way to not need this - std::mutex tmpMutex_ {}; + std::mutex getModuleNumberMutex_ {}; + std::mutex isDeviceTypeSupportedMutex_ {}; + std::mutex sendStatusConditionMutex_ {}; + std::mutex generateCommandMutex_ {}; + std::mutex aggregateStatusMutex_ {}; + std::mutex aggregateErrorMutex_ {}; + std::mutex generateFirstCommandMutex_ {}; + std::mutex statusDataValidMutex_ {}; + std::mutex commandDataValidMutex_ {}; }; } diff --git a/include/bringauto/modules/ModuleManagerLibraryHandlerLocal.hpp b/include/bringauto/modules/ModuleManagerLibraryHandlerLocal.hpp index a1fd601..bd897d5 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandlerLocal.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandlerLocal.hpp @@ -22,11 +22,11 @@ class ModuleManagerLibraryHandlerLocal : public IModuleManagerLibraryHandler { */ void loadLibrary(const std::filesystem::path &path) override; - int getModuleNumber() const override; + int getModuleNumber() override; int isDeviceTypeSupported(unsigned int device_type) override; - int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) const override; + int sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) override; /** * @short After executing the respective module function, an error might be thrown when allocating the buffer. @@ -60,9 +60,9 @@ class ModuleManagerLibraryHandlerLocal : public IModuleManagerLibraryHandler { */ int generateFirstCommand(Buffer &default_command, unsigned int device_type) override; - int statusDataValid(const Buffer &status, unsigned int device_type) const override; + int statusDataValid(const Buffer &status, unsigned int device_type) override; - int commandDataValid(const Buffer &command, unsigned int device_type) const override; + int commandDataValid(const Buffer &command, unsigned int device_type) override; /** * @brief Constructs a buffer with the given size diff --git a/include/bringauto/settings/Settings.hpp b/include/bringauto/settings/Settings.hpp index 1075820..b105dda 100644 --- a/include/bringauto/settings/Settings.hpp +++ b/include/bringauto/settings/Settings.hpp @@ -31,12 +31,12 @@ struct Settings { /** * @brief paths to shared module libraries */ - std::unordered_map modulePaths {}; + std::unordered_map modulePaths {}; /** * @brief path to module binary */ - std::string moduleBinaryPath {}; + std::filesystem::path moduleBinaryPath {}; /** * @brief Setting of external connection endpoints and protocols diff --git a/include/bringauto/structures/ModuleLibrary.hpp b/include/bringauto/structures/ModuleLibrary.hpp index 7cb1360..d6b3a0d 100644 --- a/include/bringauto/structures/ModuleLibrary.hpp +++ b/include/bringauto/structures/ModuleLibrary.hpp @@ -17,13 +17,20 @@ struct ModuleLibrary { ~ModuleLibrary(); + /** + * @brief Load libraries from paths + * + * @param libPaths paths to the libraries + */ + void loadLibraries(const std::unordered_map &libPaths); + /** * @brief Load libraries from paths * * @param libPaths paths to the libraries * @param moduleBinaryPath path to module binary for async function execution over shared memory */ - void loadLibraries(const std::unordered_map &libPaths, const std::string &moduleBinaryPath = ""); + void loadLibraries(const std::unordered_map &libPaths, const std::filesystem::path &moduleBinaryPath); /** * @brief Initialize status aggregators with context diff --git a/main.cpp b/main.cpp index 46e5fe4..0753644 100644 --- a/main.cpp +++ b/main.cpp @@ -71,7 +71,11 @@ int main(int argc, char **argv) { bas::ModuleLibrary moduleLibrary {}; try { - moduleLibrary.loadLibraries(context->settings->modulePaths, context->settings->moduleBinaryPath); + if(context->settings->moduleBinaryPath.empty()) { + moduleLibrary.loadLibraries(context->settings->modulePaths); + } else { + moduleLibrary.loadLibraries(context->settings->modulePaths, context->settings->moduleBinaryPath); + } moduleLibrary.initStatusAggregators(context); } catch(std::exception &e) { std::cerr << "[ERROR] Error occurred during module initialization: " << e.what() << std::endl; diff --git a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp index 00d3a5f..bb44536 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp @@ -27,7 +27,7 @@ async_function_execution::AsyncFunctionExecutor aeronClient { } }; -ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync(const std::string &moduleBinaryPath) : +ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync(const std::filesystem::path &moduleBinaryPath) : moduleBinaryPath_ { moduleBinaryPath } { aeronClient.connect(); deallocate_ = [this](struct buffer *buffer) { @@ -43,25 +43,27 @@ ModuleManagerLibraryHandlerAsync::~ModuleManagerLibraryHandlerAsync() { } void ModuleManagerLibraryHandlerAsync::loadLibrary(const std::filesystem::path &path) { - moduleBinaryProcess_ = boost::process::child { moduleBinaryPath_, "-m", path.string() }; + moduleBinaryProcess_ = boost::process::child { moduleBinaryPath_.string(), "-m", path.string() }; if (!moduleBinaryProcess_.valid()) { - throw std::runtime_error { "Failed to start module binary " + moduleBinaryPath_ }; + throw std::runtime_error { "Failed to start module binary " + moduleBinaryPath_.string() }; } std::this_thread::sleep_for(std::chrono::seconds(1)); // TODO Not sure how much time is needed. } -int ModuleManagerLibraryHandlerAsync::getModuleNumber() const { +int ModuleManagerLibraryHandlerAsync::getModuleNumber() { + std::lock_guard lock { getModuleNumberMutex_ }; return aeronClient.callFunc(getModuleNumberAsync).value(); } int ModuleManagerLibraryHandlerAsync::isDeviceTypeSupported(unsigned int device_type) { - std::lock_guard lock { tmpMutex_ }; + std::lock_guard lock { isDeviceTypeSupportedMutex_ }; return aeronClient.callFunc(isDeviceTypeSupportedAsync, device_type).value(); } int ModuleManagerLibraryHandlerAsync::sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, - unsigned int device_type) const { + unsigned int device_type) { + std::lock_guard lock { isDeviceTypeSupportedMutex_ }; ConvertibleBuffer current_status_raw_buffer; ConvertibleBuffer new_status_raw_buffer; @@ -79,6 +81,7 @@ int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, const Buffer &new_status, const Buffer ¤t_status, const Buffer ¤t_command, unsigned int device_type) { + std::lock_guard lock { generateCommandMutex_ }; ConvertibleBuffer new_status_raw_buffer; ConvertibleBuffer current_status_raw_buffer; ConvertibleBuffer current_command_raw_buffer; @@ -110,6 +113,7 @@ int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) { + std::lock_guard lock { aggregateStatusMutex_ }; ConvertibleBuffer current_status_raw_buffer; ConvertibleBuffer new_status_raw_buffer; @@ -134,6 +138,7 @@ int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, const Buffer ¤t_error_message, const Buffer &status, unsigned int device_type) { + std::lock_guard lock { aggregateErrorMutex_ }; ConvertibleBuffer current_error_raw_buffer; ConvertibleBuffer status_raw_buffer; @@ -154,6 +159,7 @@ int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, } int ModuleManagerLibraryHandlerAsync::generateFirstCommand(Buffer &default_command, unsigned int device_type) { + std::lock_guard lock { generateFirstCommandMutex_ }; auto ret = aeronClient.callFunc(generateFirstCommandAsync, device_type).value(); if (ret.returnCode == OK) { default_command = constructBufferByTakeOwnership(ret.buffer); @@ -163,7 +169,8 @@ int ModuleManagerLibraryHandlerAsync::generateFirstCommand(Buffer &default_comma return ret.returnCode; } -int ModuleManagerLibraryHandlerAsync::statusDataValid(const Buffer &status, unsigned int device_type) const { +int ModuleManagerLibraryHandlerAsync::statusDataValid(const Buffer &status, unsigned int device_type) { + std::lock_guard lock { statusDataValidMutex_ }; ConvertibleBuffer status_raw_buffer; if (status.isAllocated()) { status_raw_buffer = status.getStructBuffer(); @@ -172,7 +179,8 @@ int ModuleManagerLibraryHandlerAsync::statusDataValid(const Buffer &status, unsi return aeronClient.callFunc(statusDataValidAsync, status_raw_buffer, device_type).value(); } -int ModuleManagerLibraryHandlerAsync::commandDataValid(const Buffer &command, unsigned int device_type) const { +int ModuleManagerLibraryHandlerAsync::commandDataValid(const Buffer &command, unsigned int device_type) { + std::lock_guard lock { commandDataValidMutex_ }; ConvertibleBuffer command_raw_buffer; if (command.isAllocated()) { command_raw_buffer = command.getStructBuffer(); diff --git a/source/bringauto/modules/ModuleManagerLibraryHandlerLocal.cpp b/source/bringauto/modules/ModuleManagerLibraryHandlerLocal.cpp index cadd716..193dc5c 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandlerLocal.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandlerLocal.cpp @@ -65,7 +65,7 @@ void *ModuleManagerLibraryHandlerLocal::checkFunction(const char *functionName) return function; } -int ModuleManagerLibraryHandlerLocal::getModuleNumber() const { +int ModuleManagerLibraryHandlerLocal::getModuleNumber() { return getModuleNumber_(); } @@ -75,7 +75,7 @@ int ModuleManagerLibraryHandlerLocal::isDeviceTypeSupported(unsigned int device_ int ModuleManagerLibraryHandlerLocal::sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, - unsigned int device_type) const { + unsigned int device_type) { struct ::buffer current_status_raw_buffer {}; struct ::buffer new_status_raw_buffer {}; @@ -176,7 +176,7 @@ int ModuleManagerLibraryHandlerLocal::generateFirstCommand(Buffer &default_comma return ret; } -int ModuleManagerLibraryHandlerLocal::statusDataValid(const Buffer &status, unsigned int device_type) const { +int ModuleManagerLibraryHandlerLocal::statusDataValid(const Buffer &status, unsigned int device_type) { struct ::buffer raw_buffer {}; if (status.isAllocated()) { raw_buffer = status.getStructBuffer(); @@ -184,7 +184,7 @@ int ModuleManagerLibraryHandlerLocal::statusDataValid(const Buffer &status, unsi return statusDataValid_(raw_buffer, device_type); } -int ModuleManagerLibraryHandlerLocal::commandDataValid(const Buffer &command, unsigned int device_type) const { +int ModuleManagerLibraryHandlerLocal::commandDataValid(const Buffer &command, unsigned int device_type) { struct ::buffer raw_buffer {}; if (command.isAllocated()) { raw_buffer = command.getStructBuffer(); diff --git a/source/bringauto/structures/ModuleLibrary.cpp b/source/bringauto/structures/ModuleLibrary.cpp index 28bb84b..3dd1e22 100644 --- a/source/bringauto/structures/ModuleLibrary.cpp +++ b/source/bringauto/structures/ModuleLibrary.cpp @@ -13,17 +13,26 @@ ModuleLibrary::~ModuleLibrary() { [](auto &pair) { pair.second->destroy_status_aggregator(); }); } -void ModuleLibrary::loadLibraries(const std::unordered_map &libPaths, const std::string &moduleBinaryPath) { +void ModuleLibrary::loadLibraries(const std::unordered_map &libPaths) { std::shared_ptr handler; for(auto const &[key, path]: libPaths) { - if (moduleBinaryPath.empty()) { - handler = std::make_shared(); - } else { - handler = std::make_shared(moduleBinaryPath); + handler = std::make_shared(); + handler->loadLibrary(path); + if(handler->getModuleNumber() != key) { + settings::Logger::logError("Module number from shared library {} does not match the module number from config. Config: {}, binary: {}.", path.string(), key, handler->getModuleNumber()); + throw std::runtime_error {"Module numbers from config are not corresponding to binaries. Unable to continue. Fix configuration file."}; } + moduleLibraryHandlers.emplace(key, handler); + } +} + +void ModuleLibrary::loadLibraries(const std::unordered_map &libPaths, const std::filesystem::path &moduleBinaryPath) { + std::shared_ptr handler; + for(auto const &[key, path]: libPaths) { + handler = std::make_shared(moduleBinaryPath); handler->loadLibrary(path); if(handler->getModuleNumber() != key) { - settings::Logger::logError("Module number from shared library {} does not match the module number from config. Config: {}, binary: {}.", path, key, handler->getModuleNumber()); + settings::Logger::logError("Module number from shared library {} does not match the module number from config. Config: {}, binary: {}.", path.string(), key, handler->getModuleNumber()); throw std::runtime_error {"Module numbers from config are not corresponding to binaries. Unable to continue. Fix configuration file."}; } moduleLibraryHandlers.emplace(key, handler); diff --git a/test/include/testing_utils/ConfigMock.hpp b/test/include/testing_utils/ConfigMock.hpp index c30fda3..97514f5 100644 --- a/test/include/testing_utils/ConfigMock.hpp +++ b/test/include/testing_utils/ConfigMock.hpp @@ -27,11 +27,11 @@ class ConfigMock { int port { 1636 }; } internal_server_settings; - std::unordered_map module_paths { {1, "/path/to/lib1.so"}, {2, "/path/to/lib2.so"}, {3, "/path/to/lib3.so"} }; + std::unordered_map module_paths { {1, "/path/to/lib1.so"}, {2, "/path/to/lib2.so"}, {3, "/path/to/lib3.so"} }; std::string modulePathsToString() const { std::string result = ""; for (auto [key, value] : module_paths) { - result += std::format("\"{}\": \"{}\",\n", key, value); + result += std::format("\"{}\": \"{}\",\n", key, value.string()); } if (!result.empty()) { result.pop_back(); From f5c0f4c5039435a434718736e9f64205272346bc Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Mon, 3 Nov 2025 14:08:27 +0100 Subject: [PATCH 10/15] removed memory management; added module based channel offset --- CMLibStorage.cmake | 2 +- CMakeLists.txt | 2 -- .../modules/IModuleManagerLibraryHandler.hpp | 3 -- .../ModuleManagerLibraryHandlerAsync.hpp | 5 +-- include/bringauto/settings/Constants.hpp | 36 ++++++++----------- .../ModuleManagerLibraryHandlerAsync.cpp | 18 +++++++--- .../modules/memory_management/CMakeLists.txt | 10 ------ .../source/memory_management.cpp | 21 ----------- source/bringauto/structures/ModuleLibrary.cpp | 2 +- 9 files changed, 33 insertions(+), 66 deletions(-) delete mode 100644 source/bringauto/modules/memory_management/CMakeLists.txt delete mode 100644 source/bringauto/modules/memory_management/source/memory_management.cpp diff --git a/CMLibStorage.cmake b/CMLibStorage.cmake index c9e0b59..36796ba 100644 --- a/CMLibStorage.cmake +++ b/CMLibStorage.cmake @@ -1,6 +1,6 @@ FIND_PACKAGE(CMLIB REQUIRED COMPONENTS CMCONF) -CMCONF_INIT_SYSTEM(EXAMPLE) +CMCONF_INIT_SYSTEM(FLEET_PROTOCOL) SET(STORAGE_LIST DEP) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7746990..ac6eb24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,6 @@ FIND_PACKAGE(async-function-execution-shared 1.0.0 REQUIRED) FILE(GLOB_RECURSE source_files "source/*") ADD_LIBRARY(module-gateway-lib STATIC "${source_files}") TARGET_INCLUDE_DIRECTORIES(module-gateway-lib PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) -ADD_SUBDIRECTORY(source/bringauto/modules/memory_management) TARGET_LINK_LIBRARIES(module-gateway-lib PUBLIC Boost::headers protobuf::libprotobuf @@ -77,7 +76,6 @@ TARGET_LINK_LIBRARIES(module-gateway-lib PUBLIC ZLIB::ZLIB fleet-protocol-cxx-helpers-static::fleet-protocol-cxx-helpers-static async-function-execution-shared::async-function-execution-shared - memory_management ${CMAKE_DL_LIBS} ) diff --git a/include/bringauto/modules/IModuleManagerLibraryHandler.hpp b/include/bringauto/modules/IModuleManagerLibraryHandler.hpp index 49bf44b..c125406 100644 --- a/include/bringauto/modules/IModuleManagerLibraryHandler.hpp +++ b/include/bringauto/modules/IModuleManagerLibraryHandler.hpp @@ -2,9 +2,6 @@ #include -#include - -#include #include diff --git a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp index 2300e06..73fe982 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp @@ -30,7 +30,8 @@ struct ConvertibleBufferReturn final { if (size < sizeof(int)) return; std::memcpy(&returnCode, bytes.data(), sizeof(int)); size -= sizeof(int); - allocate(&buffer, size); + buffer.data = new uint8_t[size]; + buffer.size_in_bytes = size; std::memcpy(buffer.data, bytes.data() + sizeof(int), size); buffer.size_in_bytes = size; } @@ -109,7 +110,7 @@ inline static const async_function_execution::FunctionDefinition commandDataVali */ class ModuleManagerLibraryHandlerAsync : public IModuleManagerLibraryHandler { public: - explicit ModuleManagerLibraryHandlerAsync(const std::filesystem::path &moduleBinaryPath); + explicit ModuleManagerLibraryHandlerAsync(const std::filesystem::path &moduleBinaryPath, const int moduleNumber); ~ModuleManagerLibraryHandlerAsync() override; diff --git a/include/bringauto/settings/Constants.hpp b/include/bringauto/settings/Constants.hpp index 28a0470..3aa6238 100644 --- a/include/bringauto/settings/Constants.hpp +++ b/include/bringauto/settings/Constants.hpp @@ -1,11 +1,5 @@ #pragma once -#include - -#include -#include -#include - #include #include @@ -92,47 +86,47 @@ constexpr unsigned int max_external_commands { 3 }; */ constexpr unsigned int max_external_queue_size { 500 }; -/** - * @brief base stream id for Aeron communication from Module Gateway to module binary - */ -constexpr unsigned int aeron_to_module_stream_id_base { 10000 }; - -/** - * @brief base stream id for Aeron communication from module binary to Module Gateway - */ -constexpr unsigned int aeron_to_gateway_stream_id_base { 20000 }; - /** * @brief Constants for Mqtt communication -*/ + */ struct MqttConstants { /** * @brief keep alive interval in seconds; * value reasoning: keepalive is half of the default timeout in Fleet protocol * The value is chosen based on empiric measurement. - */ + */ static constexpr std::chrono::seconds keepalive { status_response_timeout / 2U }; /** * @brief automatic reconnection of mqtt client option - */ + */ static constexpr bool automatic_reconnect { true }; /** * @brief max time that the mqtt client will wait for a connection before failing; * value reasoning: TCP timeout for retransmission when TCP packet is dropped is 200ms, * this value is multiple of three of this value - */ + */ static constexpr std::chrono::milliseconds connect_timeout { 600 }; /** * @brief max messages that can be in the process of transmission simultaneously; * value reasoning: How many MQTT inflight messages can be open at one time. * The value is chosen as a recommendation from a MQTT community. - */ + */ static constexpr size_t max_inflight { 20 }; }; +/** + * @brief Constants for Aeron client communication + */ +struct AeronClientConstants { + /** + * @brief default timeout for Aeron client function calls + */ + static constexpr std::chrono::milliseconds aeron_client_default_timeout { 1000 }; +}; + /** * @brief Constant string views */ diff --git a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp index bb44536..61d1531 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp @@ -12,7 +12,7 @@ namespace bringauto::modules { async_function_execution::AsyncFunctionExecutor aeronClient { async_function_execution::Config { .isProducer = true, - .defaultTimeout = std::chrono::seconds(1) + .defaultTimeout = settings::AeronClientConstants::aeron_client_default_timeout, }, async_function_execution::FunctionList { getModuleNumberAsync, @@ -27,9 +27,9 @@ async_function_execution::AsyncFunctionExecutor aeronClient { } }; -ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync(const std::filesystem::path &moduleBinaryPath) : +ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync(const std::filesystem::path &moduleBinaryPath, const int moduleNumber) : moduleBinaryPath_ { moduleBinaryPath } { - aeronClient.connect(); + aeronClient.connect(moduleNumber); deallocate_ = [this](struct buffer *buffer) { this->deallocate(buffer); }; @@ -190,11 +190,19 @@ int ModuleManagerLibraryHandlerAsync::commandDataValid(const Buffer &command, un } int ModuleManagerLibraryHandlerAsync::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { - return ::allocate(buffer_pointer, size_in_bytes); + try{ + buffer_pointer->data = new char[size_in_bytes](); + } catch(std::bad_alloc&){ + return NOT_OK; + } + buffer_pointer->size_in_bytes = size_in_bytes; + return OK; } void ModuleManagerLibraryHandlerAsync::deallocate(struct buffer *buffer) const { - ::deallocate(buffer); + delete[] static_cast(buffer->data); + buffer->data = nullptr; + buffer->size_in_bytes = 0; } Buffer ModuleManagerLibraryHandlerAsync::constructBuffer(std::size_t size) { diff --git a/source/bringauto/modules/memory_management/CMakeLists.txt b/source/bringauto/modules/memory_management/CMakeLists.txt deleted file mode 100644 index f47babe..0000000 --- a/source/bringauto/modules/memory_management/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.25 FATAL_ERROR) -PROJECT(ModuleGateway) - -SET(CMAKE_CXX_STANDARD 23) - -FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) - -FILE(GLOB_RECURSE memory_management_cpp_files "./source/*") -ADD_LIBRARY(memory_management STATIC ${memory_management_cpp_files}) -TARGET_LINK_LIBRARIES(memory_management PUBLIC fleet-protocol-interface::common-headers-interface) \ No newline at end of file diff --git a/source/bringauto/modules/memory_management/source/memory_management.cpp b/source/bringauto/modules/memory_management/source/memory_management.cpp deleted file mode 100644 index bb270e8..0000000 --- a/source/bringauto/modules/memory_management/source/memory_management.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#include -#include - - -int allocate(struct buffer *buffer_pointer, size_t size_in_bytes){ - try{ - buffer_pointer->data = new char[size_in_bytes](); - } catch(std::bad_alloc&){ - return NOT_OK; - } - buffer_pointer->size_in_bytes = size_in_bytes; - return OK; -} - -void deallocate(struct buffer *buffer_pointer){ - delete[] static_cast(buffer_pointer->data); - buffer_pointer->data = nullptr; - buffer_pointer->size_in_bytes = 0; -} \ No newline at end of file diff --git a/source/bringauto/structures/ModuleLibrary.cpp b/source/bringauto/structures/ModuleLibrary.cpp index 3dd1e22..b8fa6b3 100644 --- a/source/bringauto/structures/ModuleLibrary.cpp +++ b/source/bringauto/structures/ModuleLibrary.cpp @@ -29,7 +29,7 @@ void ModuleLibrary::loadLibraries(const std::unordered_map &libPaths, const std::filesystem::path &moduleBinaryPath) { std::shared_ptr handler; for(auto const &[key, path]: libPaths) { - handler = std::make_shared(moduleBinaryPath); + handler = std::make_shared(moduleBinaryPath, key); handler->loadLibrary(path); if(handler->getModuleNumber() != key) { settings::Logger::logError("Module number from shared library {} does not match the module number from config. Config: {}, binary: {}.", path.string(), key, handler->getModuleNumber()); From 19e7613a3a0cb7593d0c343021197b64c21678d1 Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Tue, 4 Nov 2025 12:52:16 +0100 Subject: [PATCH 11/15] added error handling to async module --- .../ModuleManagerLibraryHandlerAsync.cpp | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp index 61d1531..f588c5c 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp @@ -52,12 +52,12 @@ void ModuleManagerLibraryHandlerAsync::loadLibrary(const std::filesystem::path & int ModuleManagerLibraryHandlerAsync::getModuleNumber() { std::lock_guard lock { getModuleNumberMutex_ }; - return aeronClient.callFunc(getModuleNumberAsync).value(); + return aeronClient.callFunc(getModuleNumberAsync).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::isDeviceTypeSupported(unsigned int device_type) { std::lock_guard lock { isDeviceTypeSupportedMutex_ }; - return aeronClient.callFunc(isDeviceTypeSupportedAsync, device_type).value(); + return aeronClient.callFunc(isDeviceTypeSupportedAsync, device_type).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::sendStatusCondition(const Buffer ¤t_status, @@ -74,7 +74,7 @@ int ModuleManagerLibraryHandlerAsync::sendStatusCondition(const Buffer ¤t_ new_status_raw_buffer = new_status.getStructBuffer(); } - return aeronClient.callFunc(sendStatusConditionAsync, current_status_raw_buffer, new_status_raw_buffer, device_type).value(); + return aeronClient.callFunc(sendStatusConditionAsync, current_status_raw_buffer, new_status_raw_buffer, device_type).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, @@ -100,14 +100,18 @@ int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, new_status_raw_buffer, current_status_raw_buffer, current_command_raw_buffer, - device_type).value(); + device_type); - if (ret.returnCode == OK) { - generated_command = constructBufferByTakeOwnership(ret.buffer); + if (!ret.has_value()) { + return NOT_OK; + } + + if (ret.value().returnCode == OK) { + generated_command = constructBufferByTakeOwnership(ret.value().buffer); } else { generated_command = constructBuffer(); } - return ret.returnCode; + return ret.value().returnCode; } int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, @@ -124,15 +128,18 @@ int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, new_status_raw_buffer = new_status.getStructBuffer(); } - auto ret = aeronClient.callFunc(aggregateStatusAsync, current_status_raw_buffer, new_status_raw_buffer, device_type).value(); - if (ret.returnCode == OK) { - aggregated_status = constructBufferByTakeOwnership(ret.buffer); + auto ret = aeronClient.callFunc(aggregateStatusAsync, current_status_raw_buffer, new_status_raw_buffer, device_type); + if (!ret.has_value()) { + return NOT_OK; + } + if (ret.value().returnCode == OK) { + aggregated_status = constructBufferByTakeOwnership(ret.value().buffer); } else { // Needed to properly free the allocated buffer memory - auto invalid_buffer = constructBufferByTakeOwnership(ret.buffer); + auto invalid_buffer = constructBufferByTakeOwnership(ret.value().buffer); aggregated_status = current_status; } - return ret.returnCode; + return ret.value().returnCode; } int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, @@ -149,24 +156,30 @@ int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, status_raw_buffer = status.getStructBuffer(); } - auto ret = aeronClient.callFunc(aggregateErrorAsync, current_error_raw_buffer, status_raw_buffer, device_type).value(); - if (ret.returnCode == OK) { - error_message = constructBufferByTakeOwnership(ret.buffer); + auto ret = aeronClient.callFunc(aggregateErrorAsync, current_error_raw_buffer, status_raw_buffer, device_type); + if (!ret.has_value()) { + return NOT_OK; + } + if (ret.value().returnCode == OK) { + error_message = constructBufferByTakeOwnership(ret.value().buffer); } else { error_message = constructBuffer(); } - return ret.returnCode; + return ret.value().returnCode; } int ModuleManagerLibraryHandlerAsync::generateFirstCommand(Buffer &default_command, unsigned int device_type) { std::lock_guard lock { generateFirstCommandMutex_ }; - auto ret = aeronClient.callFunc(generateFirstCommandAsync, device_type).value(); - if (ret.returnCode == OK) { - default_command = constructBufferByTakeOwnership(ret.buffer); + auto ret = aeronClient.callFunc(generateFirstCommandAsync, device_type); + if (!ret.has_value()) { + return NOT_OK; + } + if (ret.value().returnCode == OK) { + default_command = constructBufferByTakeOwnership(ret.value().buffer); } else { default_command = constructBuffer(); } - return ret.returnCode; + return ret.value().returnCode; } int ModuleManagerLibraryHandlerAsync::statusDataValid(const Buffer &status, unsigned int device_type) { @@ -176,7 +189,7 @@ int ModuleManagerLibraryHandlerAsync::statusDataValid(const Buffer &status, unsi status_raw_buffer = status.getStructBuffer(); } - return aeronClient.callFunc(statusDataValidAsync, status_raw_buffer, device_type).value(); + return aeronClient.callFunc(statusDataValidAsync, status_raw_buffer, device_type).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::commandDataValid(const Buffer &command, unsigned int device_type) { @@ -186,7 +199,7 @@ int ModuleManagerLibraryHandlerAsync::commandDataValid(const Buffer &command, un command_raw_buffer = command.getStructBuffer(); } - return aeronClient.callFunc(commandDataValidAsync, command_raw_buffer, device_type).value(); + return aeronClient.callFunc(commandDataValidAsync, command_raw_buffer, device_type).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { From 0be5cfd5101a02eabd7fa673609d785396dec5b9 Mon Sep 17 00:00:00 2001 From: MarioIvancik Date: Fri, 21 Nov 2025 16:07:06 +0100 Subject: [PATCH 12/15] use function definitions from fleet protocol cpp --- CMakeLists.txt | 2 +- cmake/Dependencies.cmake | 2 +- .../ModuleManagerLibraryHandlerAsync.hpp | 104 ++---------------- .../ModuleManagerLibraryHandlerAsync.cpp | 73 ++++++------ 4 files changed, 46 insertions(+), 135 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac6eb24..9a84157 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ FIND_PACKAGE(eclipse-paho-mqtt-c REQUIRED) FIND_PACKAGE(libbringauto_logger 2.0.0 REQUIRED) FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) FIND_PACKAGE(ZLIB 1.2.11 REQUIRED) -FIND_PACKAGE(fleet-protocol-cxx-helpers-static 1.1.1 REQUIRED) +FIND_PACKAGE(fleet-protocol-cxx-helpers-static 1.2.0 REQUIRED) FIND_PACKAGE(aeron 1.48.6 REQUIRED) FIND_PACKAGE(async-function-execution-shared 1.0.0 REQUIRED) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index e57bd00..ea369ef 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -9,7 +9,7 @@ BA_PACKAGE_LIBRARY(ba-logger v2.0.0) BA_PACKAGE_LIBRARY(pahomqttc v1.3.9) BA_PACKAGE_LIBRARY(pahomqttcpp v1.3.2) BA_PACKAGE_LIBRARY(zlib v1.2.11 OUTPUT_PATH_VAR ZLIB_DIR) -BA_PACKAGE_LIBRARY(fleet-protocol-cpp v1.1.1) +BA_PACKAGE_LIBRARY(fleet-protocol-cpp v1.2.0) BA_PACKAGE_LIBRARY(aeron v1.48.6) BA_PACKAGE_LIBRARY(async-function-execution v1.0.0) diff --git a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp index 73fe982..558da78 100644 --- a/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp +++ b/include/bringauto/modules/ModuleManagerLibraryHandlerAsync.hpp @@ -1,110 +1,18 @@ #pragma once #include +#include #include +#include #include #include - namespace bringauto::modules { -struct ConvertibleBufferReturn final { - int returnCode {}; - struct ::buffer buffer {}; - ConvertibleBufferReturn() = default; - ConvertibleBufferReturn(int code, struct ::buffer buff) : returnCode(code), buffer(buff) {} - - std::span serialize() const { - size_t total_size = sizeof(int) + buffer.size_in_bytes; - uint8_t* data = new uint8_t[total_size]; - std::memcpy(data, &returnCode, sizeof(int)); - std::memcpy(data + sizeof(int), buffer.data, buffer.size_in_bytes); - return {data, total_size}; - } - void deserialize(std::span bytes) { - auto size = bytes.size(); - if (size < sizeof(int)) return; - std::memcpy(&returnCode, bytes.data(), sizeof(int)); - size -= sizeof(int); - buffer.data = new uint8_t[size]; - buffer.size_in_bytes = size; - std::memcpy(buffer.data, bytes.data() + sizeof(int), size); - buffer.size_in_bytes = size; - } -}; - -struct ConvertibleBuffer final { - struct ::buffer buffer {}; - ConvertibleBuffer() = default; - ConvertibleBuffer(struct ::buffer buff) : buffer(buff) {} - - std::span serialize() const { - return std::span {reinterpret_cast(buffer.data), buffer.size_in_bytes}; - } - void deserialize(std::span bytes) { - buffer.data = const_cast(bytes.data()); - buffer.size_in_bytes = bytes.size(); - } -}; - -inline static const async_function_execution::FunctionDefinition getModuleNumberAsync { - async_function_execution::FunctionId { 0 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments {} -}; - -inline static const async_function_execution::FunctionDefinition isDeviceTypeSupportedAsync { - async_function_execution::FunctionId { 1 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments { uint32_t {} } -}; - -inline static const async_function_execution::FunctionDefinition sendStatusConditionAsync { - async_function_execution::FunctionId { 2 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } -}; - -inline static const async_function_execution::FunctionDefinition generateCommandAsync { - async_function_execution::FunctionId { 3 }, - async_function_execution::Return { ConvertibleBufferReturn {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } -}; - -inline static const async_function_execution::FunctionDefinition aggregateStatusAsync { - async_function_execution::FunctionId { 4 }, - async_function_execution::Return { ConvertibleBufferReturn {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } -}; - -inline static const async_function_execution::FunctionDefinition aggregateErrorAsync { - async_function_execution::FunctionId { 5 }, - async_function_execution::Return { ConvertibleBufferReturn {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } -}; - -inline static const async_function_execution::FunctionDefinition generateFirstCommandAsync { - async_function_execution::FunctionId { 6 }, - async_function_execution::Return { ConvertibleBufferReturn {} }, - async_function_execution::Arguments { uint32_t {} } -}; - -inline static const async_function_execution::FunctionDefinition statusDataValidAsync { - async_function_execution::FunctionId { 7 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } -}; - -inline static const async_function_execution::FunctionDefinition commandDataValidAsync { - async_function_execution::FunctionId { 8 }, - async_function_execution::Return { int {} }, - async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } -}; - /** * @brief Class used to load and handle library created by module maintainer */ @@ -202,6 +110,14 @@ class ModuleManagerLibraryHandlerAsync : public IModuleManagerLibraryHandler { std::mutex generateFirstCommandMutex_ {}; std::mutex statusDataValidMutex_ {}; std::mutex commandDataValidMutex_ {}; + + fleet_protocol::cxx::ModuleFunctionExecutor aeronClient { + async_function_execution::Config { + .isProducer = true, + .defaultTimeout = settings::AeronClientConstants::aeron_client_default_timeout, + }, + fleet_protocol::cxx::moduleFunctionList + }; }; } diff --git a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp index f588c5c..ffea062 100644 --- a/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp +++ b/source/bringauto/modules/ModuleManagerLibraryHandlerAsync.cpp @@ -1,5 +1,4 @@ #include -#include #include @@ -9,24 +8,6 @@ namespace bringauto::modules { -async_function_execution::AsyncFunctionExecutor aeronClient { - async_function_execution::Config { - .isProducer = true, - .defaultTimeout = settings::AeronClientConstants::aeron_client_default_timeout, - }, - async_function_execution::FunctionList { - getModuleNumberAsync, - isDeviceTypeSupportedAsync, - sendStatusConditionAsync, - generateCommandAsync, - aggregateStatusAsync, - aggregateErrorAsync, - generateFirstCommandAsync, - statusDataValidAsync, - commandDataValidAsync - } -}; - ModuleManagerLibraryHandlerAsync::ModuleManagerLibraryHandlerAsync(const std::filesystem::path &moduleBinaryPath, const int moduleNumber) : moduleBinaryPath_ { moduleBinaryPath } { aeronClient.connect(moduleNumber); @@ -52,20 +33,21 @@ void ModuleManagerLibraryHandlerAsync::loadLibrary(const std::filesystem::path & int ModuleManagerLibraryHandlerAsync::getModuleNumber() { std::lock_guard lock { getModuleNumberMutex_ }; - return aeronClient.callFunc(getModuleNumberAsync).value_or(NOT_OK); + return aeronClient.callFunc(fleet_protocol::cxx::getModuleNumberAsync).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::isDeviceTypeSupported(unsigned int device_type) { std::lock_guard lock { isDeviceTypeSupportedMutex_ }; - return aeronClient.callFunc(isDeviceTypeSupportedAsync, device_type).value_or(NOT_OK); + return aeronClient.callFunc(fleet_protocol::cxx::isDeviceTypeSupportedAsync, + device_type).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::sendStatusCondition(const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) { std::lock_guard lock { isDeviceTypeSupportedMutex_ }; - ConvertibleBuffer current_status_raw_buffer; - ConvertibleBuffer new_status_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer current_status_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer new_status_raw_buffer; if (current_status.isAllocated()) { current_status_raw_buffer = current_status.getStructBuffer(); @@ -74,7 +56,10 @@ int ModuleManagerLibraryHandlerAsync::sendStatusCondition(const Buffer ¤t_ new_status_raw_buffer = new_status.getStructBuffer(); } - return aeronClient.callFunc(sendStatusConditionAsync, current_status_raw_buffer, new_status_raw_buffer, device_type).value_or(NOT_OK); + return aeronClient.callFunc(fleet_protocol::cxx::sendStatusConditionAsync, + current_status_raw_buffer, + new_status_raw_buffer, + device_type).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, @@ -82,9 +67,9 @@ int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, const Buffer ¤t_status, const Buffer ¤t_command, unsigned int device_type) { std::lock_guard lock { generateCommandMutex_ }; - ConvertibleBuffer new_status_raw_buffer; - ConvertibleBuffer current_status_raw_buffer; - ConvertibleBuffer current_command_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer new_status_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer current_status_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer current_command_raw_buffer; if (new_status.isAllocated()) { new_status_raw_buffer = new_status.getStructBuffer(); @@ -96,7 +81,7 @@ int ModuleManagerLibraryHandlerAsync::generateCommand(Buffer &generated_command, current_command_raw_buffer = current_command.getStructBuffer(); } - auto ret = aeronClient.callFunc(generateCommandAsync, + auto ret = aeronClient.callFunc(fleet_protocol::cxx::generateCommandAsync, new_status_raw_buffer, current_status_raw_buffer, current_command_raw_buffer, @@ -118,8 +103,8 @@ int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, const Buffer ¤t_status, const Buffer &new_status, unsigned int device_type) { std::lock_guard lock { aggregateStatusMutex_ }; - ConvertibleBuffer current_status_raw_buffer; - ConvertibleBuffer new_status_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer current_status_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer new_status_raw_buffer; if (current_status.isAllocated()) { current_status_raw_buffer = current_status.getStructBuffer(); @@ -128,7 +113,10 @@ int ModuleManagerLibraryHandlerAsync::aggregateStatus(Buffer &aggregated_status, new_status_raw_buffer = new_status.getStructBuffer(); } - auto ret = aeronClient.callFunc(aggregateStatusAsync, current_status_raw_buffer, new_status_raw_buffer, device_type); + auto ret = aeronClient.callFunc(fleet_protocol::cxx::aggregateStatusAsync, + current_status_raw_buffer, + new_status_raw_buffer, + device_type); if (!ret.has_value()) { return NOT_OK; } @@ -146,8 +134,8 @@ int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, const Buffer ¤t_error_message, const Buffer &status, unsigned int device_type) { std::lock_guard lock { aggregateErrorMutex_ }; - ConvertibleBuffer current_error_raw_buffer; - ConvertibleBuffer status_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer current_error_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer status_raw_buffer; if (current_error_message.isAllocated()) { current_error_raw_buffer = current_error_message.getStructBuffer(); @@ -156,7 +144,10 @@ int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, status_raw_buffer = status.getStructBuffer(); } - auto ret = aeronClient.callFunc(aggregateErrorAsync, current_error_raw_buffer, status_raw_buffer, device_type); + auto ret = aeronClient.callFunc(fleet_protocol::cxx::aggregateErrorAsync, + current_error_raw_buffer, + status_raw_buffer, + device_type); if (!ret.has_value()) { return NOT_OK; } @@ -170,7 +161,7 @@ int ModuleManagerLibraryHandlerAsync::aggregateError(Buffer &error_message, int ModuleManagerLibraryHandlerAsync::generateFirstCommand(Buffer &default_command, unsigned int device_type) { std::lock_guard lock { generateFirstCommandMutex_ }; - auto ret = aeronClient.callFunc(generateFirstCommandAsync, device_type); + auto ret = aeronClient.callFunc(fleet_protocol::cxx::generateFirstCommandAsync, device_type); if (!ret.has_value()) { return NOT_OK; } @@ -184,22 +175,26 @@ int ModuleManagerLibraryHandlerAsync::generateFirstCommand(Buffer &default_comma int ModuleManagerLibraryHandlerAsync::statusDataValid(const Buffer &status, unsigned int device_type) { std::lock_guard lock { statusDataValidMutex_ }; - ConvertibleBuffer status_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer status_raw_buffer; if (status.isAllocated()) { status_raw_buffer = status.getStructBuffer(); } - return aeronClient.callFunc(statusDataValidAsync, status_raw_buffer, device_type).value_or(NOT_OK); + return aeronClient.callFunc(fleet_protocol::cxx::statusDataValidAsync, + status_raw_buffer, + device_type).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::commandDataValid(const Buffer &command, unsigned int device_type) { std::lock_guard lock { commandDataValidMutex_ }; - ConvertibleBuffer command_raw_buffer; + fleet_protocol::cxx::ConvertibleBuffer command_raw_buffer; if (command.isAllocated()) { command_raw_buffer = command.getStructBuffer(); } - return aeronClient.callFunc(commandDataValidAsync, command_raw_buffer, device_type).value_or(NOT_OK); + return aeronClient.callFunc(fleet_protocol::cxx::commandDataValidAsync, + command_raw_buffer, + device_type).value_or(NOT_OK); } int ModuleManagerLibraryHandlerAsync::allocate(struct buffer *buffer_pointer, size_t size_in_bytes) const { From 3a7005007b8d8cbd8c5cbe34e3a9fcfbe3cf51f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladislav=20R=C3=BDgl?= Date: Wed, 3 Dec 2025 14:36:18 +0100 Subject: [PATCH 13/15] Check if module defined in external-connection endpoint exists in module-paths --- .../connection/ExternalConnection.cpp | 10 +++++++++- source/bringauto/settings/SettingsParser.cpp | 14 ++++++++++++++ test/source/SettingsParserTests.cpp | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/source/bringauto/external_client/connection/ExternalConnection.cpp b/source/bringauto/external_client/connection/ExternalConnection.cpp index e7f58c2..df3606e 100644 --- a/source/bringauto/external_client/connection/ExternalConnection.cpp +++ b/source/bringauto/external_client/connection/ExternalConnection.cpp @@ -416,7 +416,15 @@ std::vector ExternalConnection::getAllConnecte std::vector devices {}; for(const auto &moduleNumber: settings_.modules) { std::list unique_devices {}; - const int ret = moduleLibrary_.statusAggregators.at(moduleNumber)->get_unique_devices(unique_devices); + auto statusAggregatorItr = moduleLibrary_.statusAggregators.find(moduleNumber); + + if (statusAggregatorItr == moduleLibrary_.statusAggregators.end()) + { + log::logWarning("Module {} is defined in external-connection endpoint but is not specified in module-paths"); + continue; + } + + const int ret = (*statusAggregatorItr).second->get_unique_devices(unique_devices); if(ret <= 0) { log::logWarning("Module {} does not have any connected devices", moduleNumber); continue; diff --git a/source/bringauto/settings/SettingsParser.cpp b/source/bringauto/settings/SettingsParser.cpp index 9a09d46..ae84d3b 100644 --- a/source/bringauto/settings/SettingsParser.cpp +++ b/source/bringauto/settings/SettingsParser.cpp @@ -5,6 +5,7 @@ #include #include +#include @@ -108,6 +109,19 @@ bool SettingsParser::areSettingsCorrect() const { isCorrect = false; } + std::ranges::any_of(settings_->externalConnectionSettingsList, [&](auto& externalConnectionSettings){ + return std::ranges::any_of(externalConnectionSettings.modules, [&](auto const& externalModuleId) { + bool isMissing = !settings_->modulePaths.contains(externalModuleId); + if (isMissing) + { + std::cerr << "Module " << externalModuleId << + " is defined in external-connection endpoint modules but is not specified in module-paths" << std::endl; + isCorrect = false; + } + return isMissing; + }); + }); + return isCorrect; } diff --git a/test/source/SettingsParserTests.cpp b/test/source/SettingsParserTests.cpp index 42af8b0..cd25d55 100644 --- a/test/source/SettingsParserTests.cpp +++ b/test/source/SettingsParserTests.cpp @@ -185,3 +185,21 @@ TEST_F(SettingsParserTests, InvalidProtocol){ EXPECT_TRUE(result); EXPECT_TRUE(settingsParser.getSettings()->externalConnectionSettingsList.empty()); } + +/** + * @brief Test if modules specified in endpoint missing in module-paths are handled correctly + */ +TEST_F(SettingsParserTests, MissingModules){ + testing_utils::ConfigMock::Config config {}; + config.module_paths = { {1, "/path/to/lib1.so"}, {2, "/path/to/lib2.so"}, {3, "/path/to/lib3.so"} }; + config.external_connection.endpoint.modules = { 1, 2, 3, 4}; + + bool failed = false; + try { + parseConfig(config); + }catch (std::invalid_argument &e){ + EXPECT_STREQ(e.what(), "Arguments are not correct."); + failed = true; + } + EXPECT_TRUE(failed); +} \ No newline at end of file From e02cf04049853cdef2ce2b84680cff2b31b6be71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladislav=20R=C3=BDgl?= Date: Fri, 5 Dec 2025 10:36:42 +0100 Subject: [PATCH 14/15] dont ignore nodiscard value in std::ranged::any_of --- source/bringauto/settings/SettingsParser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/bringauto/settings/SettingsParser.cpp b/source/bringauto/settings/SettingsParser.cpp index ae84d3b..ae2e332 100644 --- a/source/bringauto/settings/SettingsParser.cpp +++ b/source/bringauto/settings/SettingsParser.cpp @@ -109,14 +109,13 @@ bool SettingsParser::areSettingsCorrect() const { isCorrect = false; } - std::ranges::any_of(settings_->externalConnectionSettingsList, [&](auto& externalConnectionSettings){ + isCorrect &= !std::ranges::any_of(settings_->externalConnectionSettingsList, [&](auto& externalConnectionSettings){ return std::ranges::any_of(externalConnectionSettings.modules, [&](auto const& externalModuleId) { bool isMissing = !settings_->modulePaths.contains(externalModuleId); if (isMissing) { std::cerr << "Module " << externalModuleId << " is defined in external-connection endpoint modules but is not specified in module-paths" << std::endl; - isCorrect = false; } return isMissing; }); From e8fe4b768d3df07df88ace8b69faa3b37164b8f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladislav=20R=C3=BDgl?= Date: Fri, 5 Dec 2025 12:35:00 +0100 Subject: [PATCH 15/15] Added missing param in logWarning --- .../external_client/connection/ExternalConnection.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/bringauto/external_client/connection/ExternalConnection.cpp b/source/bringauto/external_client/connection/ExternalConnection.cpp index df3606e..4051818 100644 --- a/source/bringauto/external_client/connection/ExternalConnection.cpp +++ b/source/bringauto/external_client/connection/ExternalConnection.cpp @@ -420,7 +420,8 @@ std::vector ExternalConnection::getAllConnecte if (statusAggregatorItr == moduleLibrary_.statusAggregators.end()) { - log::logWarning("Module {} is defined in external-connection endpoint but is not specified in module-paths"); + log::logWarning("Module {} is defined in external-connection endpoint but is not specified in module-paths", + moduleNumber); continue; }