mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 08:41:16 +00:00
feat!: Remove deprecated components sdk, sdk_commands, dds_plugin
BREAKING CHANGE: Components have been moved to ODC project, see https://github.com/FairRootGroup/FairMQ/discussions/392 for details.
This commit is contained in:
parent
69faa63c5b
commit
e16cf67b94
|
@ -29,16 +29,10 @@ fairmq_build_option(BUILD_TESTING "Build tests."
|
||||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||||
fairmq_build_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport."
|
fairmq_build_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport."
|
||||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||||
fairmq_build_option(BUILD_SDK_COMMANDS "Build the FairMQ SDK commands."
|
|
||||||
DEFAULT OFF)
|
|
||||||
fairmq_build_option(BUILD_DDS_PLUGIN "Build DDS plugin."
|
|
||||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
|
|
||||||
fairmq_build_option(BUILD_PMIX_PLUGIN "Build PMIx plugin."
|
fairmq_build_option(BUILD_PMIX_PLUGIN "Build PMIx plugin."
|
||||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
|
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||||
fairmq_build_option(BUILD_EXAMPLES "Build FairMQ examples."
|
fairmq_build_option(BUILD_EXAMPLES "Build FairMQ examples."
|
||||||
DEFAULT ON REQUIRES "BUILD_FAIRMQ")
|
DEFAULT ON REQUIRES "BUILD_FAIRMQ")
|
||||||
fairmq_build_option(BUILD_SDK "Build the FairMQ controller SDK."
|
|
||||||
DEFAULT OFF REQUIRES "BUILD_DDS_PLUGIN;BUILD_SDK_COMMANDS")
|
|
||||||
fairmq_build_option(BUILD_TIDY_TOOL "Build the fairmq-tidy tool."
|
fairmq_build_option(BUILD_TIDY_TOOL "Build the fairmq-tidy tool."
|
||||||
DEFAULT OFF)
|
DEFAULT OFF)
|
||||||
fairmq_build_option(BUILD_DOCS "Build FairMQ documentation."
|
fairmq_build_option(BUILD_DOCS "Build FairMQ documentation."
|
||||||
|
@ -57,7 +51,7 @@ include(FairMQDependencies)
|
||||||
|
|
||||||
|
|
||||||
# Targets ######################################################################
|
# Targets ######################################################################
|
||||||
if(BUILD_FAIRMQ OR BUILD_SDK)
|
if(BUILD_FAIRMQ)
|
||||||
add_subdirectory(fairmq)
|
add_subdirectory(fairmq)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -92,9 +86,6 @@ endif()
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
list(APPEND PROJECT_PACKAGE_COMPONENTS tests)
|
list(APPEND PROJECT_PACKAGE_COMPONENTS tests)
|
||||||
endif()
|
endif()
|
||||||
if(BUILD_DDS_PLUGIN)
|
|
||||||
list(APPEND PROJECT_PACKAGE_COMPONENTS dds_plugin)
|
|
||||||
endif()
|
|
||||||
if(BUILD_PMIX_PLUGIN)
|
if(BUILD_PMIX_PLUGIN)
|
||||||
list(APPEND PROJECT_PACKAGE_COMPONENTS pmix_plugin)
|
list(APPEND PROJECT_PACKAGE_COMPONENTS pmix_plugin)
|
||||||
endif()
|
endif()
|
||||||
|
@ -107,12 +98,6 @@ endif()
|
||||||
if(BUILD_DOCS)
|
if(BUILD_DOCS)
|
||||||
list(APPEND PROJECT_PACKAGE_COMPONENTS docs)
|
list(APPEND PROJECT_PACKAGE_COMPONENTS docs)
|
||||||
endif()
|
endif()
|
||||||
if(BUILD_SDK)
|
|
||||||
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk)
|
|
||||||
endif()
|
|
||||||
if(BUILD_SDK_COMMANDS)
|
|
||||||
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk_commands)
|
|
||||||
endif()
|
|
||||||
if(BUILD_TIDY_TOOL)
|
if(BUILD_TIDY_TOOL)
|
||||||
list(APPEND PROJECT_PACKAGE_COMPONENTS tidy_tool)
|
list(APPEND PROJECT_PACKAGE_COMPONENTS tidy_tool)
|
||||||
endif()
|
endif()
|
||||||
|
@ -125,11 +110,6 @@ if(BUILD_FAIRMQ)
|
||||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
if(BUILD_SDK OR BUILD_DDS_PLUGIN)
|
|
||||||
install(FILES cmake/Findasio.cmake
|
|
||||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if(BUILD_DOCS)
|
if(BUILD_DOCS)
|
||||||
install(DIRECTORY ${CMAKE_BINARY_DIR}/doxygen/html
|
install(DIRECTORY ${CMAKE_BINARY_DIR}/doxygen/html
|
||||||
DESTINATION ${PROJECT_INSTALL_DATADIR}/docs
|
DESTINATION ${PROJECT_INSTALL_DATADIR}/docs
|
||||||
|
|
|
@ -42,11 +42,8 @@ endif()
|
||||||
ctest_start(Continuous)
|
ctest_start(Continuous)
|
||||||
|
|
||||||
list(APPEND options "-DDISABLE_COLOR=ON" "-DBUILD_EXAMPLES=ON" "-DBUILD_TESTING=ON")
|
list(APPEND options "-DDISABLE_COLOR=ON" "-DBUILD_EXAMPLES=ON" "-DBUILD_TESTING=ON")
|
||||||
if(HAS_ASIO AND HAS_DDS)
|
|
||||||
list(APPEND options "-DBUILD_SDK_COMMANDS=ON" "-DBUILD_SDK=ON" "-DBUILD_DDS_PLUGIN=ON")
|
|
||||||
endif()
|
|
||||||
if(HAS_PMIX)
|
if(HAS_PMIX)
|
||||||
list(APPEND options "-DBUILD_SDK_COMMANDS=ON" "-DBUILD_PMIX_PLUGIN=ON")
|
list(APPEND options "-DBUILD_PMIX_PLUGIN=ON")
|
||||||
endif()
|
endif()
|
||||||
if(HAS_ASIO AND HAS_ASIOFI)
|
if(HAS_ASIO AND HAS_ASIOFI)
|
||||||
list(APPEND options "-DBUILD_OFI_TRANSPORT=ON")
|
list(APPEND options "-DBUILD_OFI_TRANSPORT=ON")
|
||||||
|
|
|
@ -82,11 +82,9 @@ When building FairMQ, CMake will print a summary table of all available package
|
||||||
* [asiofi](https://github.com/FairRootGroup/asiofi)
|
* [asiofi](https://github.com/FairRootGroup/asiofi)
|
||||||
* [Boost](https://www.boost.org/)
|
* [Boost](https://www.boost.org/)
|
||||||
* [CMake](https://cmake.org/)
|
* [CMake](https://cmake.org/)
|
||||||
* [DDS](http://dds.gsi.de)
|
|
||||||
* [Doxygen](http://www.doxygen.org/)
|
* [Doxygen](http://www.doxygen.org/)
|
||||||
* [FairCMakeModules](https://github.com/FairRootGroup/FairCMakeModules) (optionally bundled)
|
* [FairCMakeModules](https://github.com/FairRootGroup/FairCMakeModules) (optionally bundled)
|
||||||
* [FairLogger](https://github.com/FairRootGroup/FairLogger)
|
* [FairLogger](https://github.com/FairRootGroup/FairLogger)
|
||||||
* [Flatbuffers](https://google.github.io/flatbuffers/)
|
|
||||||
* [GTest](https://github.com/google/googletest) (optionally bundled)
|
* [GTest](https://github.com/google/googletest) (optionally bundled)
|
||||||
* [PMIx](https://pmix.org/)
|
* [PMIx](https://pmix.org/)
|
||||||
* [ZeroMQ](http://zeromq.org/)
|
* [ZeroMQ](http://zeromq.org/)
|
||||||
|
@ -161,6 +159,4 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
|
||||||
1. [Usage](docs/Plugins.md#71-usage)
|
1. [Usage](docs/Plugins.md#71-usage)
|
||||||
2. [Development](docs/Plugins.md#72-development)
|
2. [Development](docs/Plugins.md#72-development)
|
||||||
3. [Provided Plugins](docs/Plugins.md#73-provided-plugins)
|
3. [Provided Plugins](docs/Plugins.md#73-provided-plugins)
|
||||||
1. [DDS](docs/Plugins.md#731-dds)
|
2. [PMIx](docs/Plugins.md#731-pmix)
|
||||||
2. [PMIx](docs/Plugins.md#732-pmix)
|
|
||||||
8. [Controller SDK](docs/SDK.md)
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ include(FairCMakeModules)
|
||||||
include(FairFindPackage2)
|
include(FairFindPackage2)
|
||||||
include(FairMQBundlePackageHelper)
|
include(FairMQBundlePackageHelper)
|
||||||
|
|
||||||
if(BUILD_FAIRMQ OR BUILD_SDK)
|
if(BUILD_FAIRMQ)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||||
find_package2(PUBLIC Threads REQUIRED)
|
find_package2(PUBLIC Threads REQUIRED)
|
||||||
set(Threads_PREFIX "<system>")
|
set(Threads_PREFIX "<system>")
|
||||||
|
@ -23,28 +23,18 @@ if(BUILD_OFI_TRANSPORT)
|
||||||
find_package2(PRIVATE OFI REQUIRED)
|
find_package2(PRIVATE OFI REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_SDK_COMMANDS)
|
|
||||||
find_package2(PRIVATE Flatbuffers REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_DDS_PLUGIN OR BUILD_SDK)
|
|
||||||
find_package2(PRIVATE DDS REQUIRED VERSION 3.5.13.7)
|
|
||||||
set(DDS_Boost_COMPONENTS system log log_setup regex filesystem thread)
|
|
||||||
set(DDS_Boost_VERSION 1.67)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_PMIX_PLUGIN)
|
if(BUILD_PMIX_PLUGIN)
|
||||||
find_package2(PRIVATE PMIx REQUIRED VERSION 2.1.4)
|
find_package2(PRIVATE PMIx REQUIRED VERSION 2.1.4)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_FAIRMQ OR BUILD_SDK OR BUILD_TIDY_TOOL)
|
if(BUILD_FAIRMQ OR BUILD_TIDY_TOOL)
|
||||||
find_package2(PUBLIC FairLogger REQUIRED VERSION 1.6.0)
|
find_package2(PUBLIC FairLogger REQUIRED VERSION 1.6.0)
|
||||||
find_package2(PUBLIC Boost REQUIRED VERSION 1.66
|
find_package2(PUBLIC Boost REQUIRED VERSION 1.66
|
||||||
COMPONENTS container program_options filesystem date_time regex
|
COMPONENTS container program_options filesystem date_time regex
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_OFI_TRANSPORT OR BUILD_SDK OR BUILD_DDS_PLUGIN)
|
if(BUILD_OFI_TRANSPORT)
|
||||||
set(__old ${CMAKE_FIND_PACKAGE_PREFER_CONFIG})
|
set(__old ${CMAKE_FIND_PACKAGE_PREFER_CONFIG})
|
||||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
|
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
|
||||||
find_package2(PUBLIC asio REQUIRED VERSION 1.18)
|
find_package2(PUBLIC asio REQUIRED VERSION 1.18)
|
||||||
|
@ -101,8 +91,6 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||||
if(NOT asiofi_PREFIX AND asiofi_ROOT)
|
if(NOT asiofi_PREFIX AND asiofi_ROOT)
|
||||||
set(asiofi_PREFIX ${asiofi_ROOT})
|
set(asiofi_PREFIX ${asiofi_ROOT})
|
||||||
endif()
|
endif()
|
||||||
elseif(${dep} STREQUAL DDS)
|
|
||||||
set(DDS_PREFIX "${DDS_INSTALL_PREFIX}")
|
|
||||||
elseif(${dep} STREQUAL Boost)
|
elseif(${dep} STREQUAL Boost)
|
||||||
if(TARGET Boost::headers)
|
if(TARGET Boost::headers)
|
||||||
get_target_property(boost_include Boost::headers INTERFACE_INCLUDE_DIRECTORIES)
|
get_target_property(boost_include Boost::headers INTERFACE_INCLUDE_DIRECTORIES)
|
||||||
|
@ -116,14 +104,6 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||||
get_filename_component(Doxygen_PREFIX ${doxygen_bin} DIRECTORY)
|
get_filename_component(Doxygen_PREFIX ${doxygen_bin} DIRECTORY)
|
||||||
get_filename_component(Doxygen_PREFIX ${Doxygen_PREFIX}/.. ABSOLUTE)
|
get_filename_component(Doxygen_PREFIX ${Doxygen_PREFIX}/.. ABSOLUTE)
|
||||||
unset(doxygen_bin)
|
unset(doxygen_bin)
|
||||||
elseif(${dep} STREQUAL Flatbuffers)
|
|
||||||
if(TARGET flatbuffers::flatbuffers)
|
|
||||||
get_target_property(flatbuffers_include flatbuffers::flatbuffers INTERFACE_INCLUDE_DIRECTORIES)
|
|
||||||
else()
|
|
||||||
get_target_property(flatbuffers_include flatbuffers::flatbuffers_shared INTERFACE_INCLUDE_DIRECTORIES)
|
|
||||||
endif()
|
|
||||||
get_filename_component(Flatbuffers_PREFIX ${flatbuffers_include}/.. ABSOLUTE)
|
|
||||||
unset(flatbuffers_include)
|
|
||||||
elseif(NOT ${dep}_PREFIX)
|
elseif(NOT ${dep}_PREFIX)
|
||||||
# try to guess
|
# try to guess
|
||||||
if(TARGET ${dep}::${dep})
|
if(TARGET ${dep}::${dep})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
# Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
# Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||||
# #
|
# #
|
||||||
# This software is distributed under the terms of the #
|
# This software is distributed under the terms of the #
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||||
|
@ -33,12 +33,6 @@ macro(fairmq_summary_components)
|
||||||
set(ofi_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_OFI_TRANSPORT=ON${CR})")
|
set(ofi_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_OFI_TRANSPORT=ON${CR})")
|
||||||
endif()
|
endif()
|
||||||
message(STATUS " ${BWhite}ofi_transport${CR} ${ofi_summary}")
|
message(STATUS " ${BWhite}ofi_transport${CR} ${ofi_summary}")
|
||||||
if(BUILD_DDS_PLUGIN)
|
|
||||||
set(dds_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_DDS_PLUGIN=OFF${CR})")
|
|
||||||
else()
|
|
||||||
set(dds_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_DDS_PLUGIN=ON${CR})")
|
|
||||||
endif()
|
|
||||||
message(STATUS " ${BWhite}dds_plugin${CR} ${dds_summary}")
|
|
||||||
if(BUILD_PMIX_PLUGIN)
|
if(BUILD_PMIX_PLUGIN)
|
||||||
set(pmix_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_PMIX_PLUGIN=OFF${CR})")
|
set(pmix_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_PMIX_PLUGIN=OFF${CR})")
|
||||||
else()
|
else()
|
||||||
|
@ -57,39 +51,12 @@ macro(fairmq_summary_components)
|
||||||
set(docs_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_DOCS=ON${CR})")
|
set(docs_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_DOCS=ON${CR})")
|
||||||
endif()
|
endif()
|
||||||
message(STATUS " ${BWhite}docs${CR} ${docs_summary}")
|
message(STATUS " ${BWhite}docs${CR} ${docs_summary}")
|
||||||
if(BUILD_SDK)
|
|
||||||
set(sdk_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_SDK=OFF${CR})")
|
|
||||||
else()
|
|
||||||
set(sdk_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_SDK=ON${CR})")
|
|
||||||
endif()
|
|
||||||
message(STATUS " ${BWhite}sdk${CR} ${sdk_summary}")
|
|
||||||
if(BUILD_SDK_COMMANDS)
|
|
||||||
set(sdk_commands_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_SDK_COMMANDS=OFF${CR})")
|
|
||||||
else()
|
|
||||||
set(sdk_commands_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_SDK_COMMANDS=ON${CR})")
|
|
||||||
endif()
|
|
||||||
message(STATUS " ${BWhite}sdk_commands${CR} ${sdk_commands_summary}")
|
|
||||||
if(BUILD_TIDY_TOOL)
|
if(BUILD_TIDY_TOOL)
|
||||||
set(sdk_tidy_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
|
set(sdk_tidy_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
|
||||||
else()
|
else()
|
||||||
set(sdk_tidy_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
|
set(sdk_tidy_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
|
||||||
endif()
|
endif()
|
||||||
message(STATUS " ${BWhite}tidy_tool${CR} ${sdk_tidy_summary}")
|
message(STATUS " ${BWhite}tidy_tool${CR} ${sdk_tidy_summary}")
|
||||||
|
|
||||||
set(_deprecated)
|
|
||||||
if(BUILD_SDK)
|
|
||||||
list(APPEND _deprecated sdk)
|
|
||||||
endif()
|
|
||||||
if(BUILD_SDK_COMMANDS)
|
|
||||||
list(APPEND _deprecated sdk_commands)
|
|
||||||
endif()
|
|
||||||
if(BUILD_DDS_PLUGIN)
|
|
||||||
list(APPEND _deprecated dds_plugin)
|
|
||||||
endif()
|
|
||||||
list(JOIN _deprecated ", " _deprecated)
|
|
||||||
if(_deprecated)
|
|
||||||
message(DEPRECATION "You have selected to build deprecated components '${_deprecated}' which will be removed in a future release. See https://github.com/FairRootGroup/FairMQ/discussions/392 for more information. Use '-Wno-deprecated' to silence deprecation warnings.")
|
|
||||||
endif()
|
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
macro(fairmq_summary_static_analysis)
|
macro(fairmq_summary_static_analysis)
|
||||||
|
|
|
@ -54,37 +54,7 @@ A more complete example which may serve as a start including example CMake code
|
||||||
|
|
||||||
## 7.3 Provided Plugins
|
## 7.3 Provided Plugins
|
||||||
|
|
||||||
### 7.3.1 DDS
|
### 7.3.1 PMIx
|
||||||
|
|
||||||
When launching a FairMQ topology via [DDS](http://dds.gsi.de/) the DDS plugin enables FairMQ devices to interact with DDS' custom command and property subsystems - enable the plugin by passing `-P dds` on the command line.
|
|
||||||
|
|
||||||
Via the property subsystem a FairMQ topology may exchange channel connection data (essentially to do service discovery) needed to connect/bind all FairMQ channels appropriately. DDS is highly optimized for this use case. See [examples/dds](examples/dds/README.md) for more details.
|
|
||||||
|
|
||||||
Via the custom command subsystem a FairMQ device can receive a number of commands. FairMQ provides a convenient command line tool `fairmq-dds-command-ui` that allows interactive or scripted control of a running FairMQ topology managed via DDS. If one develops directly against the custom command DDS API, the following table lists all the commands the DDS plugin currently understands:
|
|
||||||
|
|
||||||
| Custom Command | Response | Error | Description |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `check-state` | `<ID>: <STATE> (pid: <PID>)` | n/a | Query current device state, see state machine for possible states |
|
|
||||||
| `dump-config` | `(<ID>: <PKEY> -> <PVALUE>\n)+` | n/a | Query current device config (list property key/value pairs) |
|
|
||||||
| `INIT DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `BIND` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `CONNECT` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `INIT TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `RUN` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `STOP` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `RESET TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `RESET DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `END` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
|
||||||
| `subscribe-to-heartbeats` | `heartbeat-subscription: <ID>,OK` | n/a | Subscribe to heartbeats |
|
|
||||||
| on heartbeat subscription | `heartbeat: <ID>,<PID>` | n/a | Heartbeat every 100ms |
|
|
||||||
| `unsubscribe-from-heartbeats` | `heartbeat-unsubscription: <ID>,OK` | n/a | Unsubscribe from heartbeats |
|
|
||||||
| `subscribe-to-state-changes` | `state-changes-subscription: <ID>,OK` | n/a | Subscribe to state changes |
|
|
||||||
| on state changes subscription | `state-change: <ID>,<STATE>` | n/a | State change notification |
|
|
||||||
| `unsubscribe-from-state-changes` | `state-changes-unsubscription: <ID>,OK` | n/a | Unsubscribe from state changes |
|
|
||||||
|
|
||||||
If unknown commands are received the plugin will print a warning.
|
|
||||||
|
|
||||||
### 7.3.2 PMIx
|
|
||||||
|
|
||||||
The [PMIx](https://pmix.org/) plugin enables launching a FairMQ topology with any PMIx capable launcher, e.g. the [Open Run-Time Environment (ORTE) of OpenMPI](https://www.open-mpi.org/doc/v4.0/man1/mpirun.1.php) or the [Slurm workload manager](https://slurm.schedmd.com/srun.html). This plugin is not (yet) very mature and serves as a proof of concept at the moment.
|
The [PMIx](https://pmix.org/) plugin enables launching a FairMQ topology with any PMIx capable launcher, e.g. the [Open Run-Time Environment (ORTE) of OpenMPI](https://www.open-mpi.org/doc/v4.0/man1/mpirun.1.php) or the [Slurm workload manager](https://slurm.schedmd.com/srun.html). This plugin is not (yet) very mature and serves as a proof of concept at the moment.
|
||||||
|
|
||||||
|
|
34
docs/SDK.md
34
docs/SDK.md
|
@ -1,34 +0,0 @@
|
||||||
← [Back](../README.md)
|
|
||||||
|
|
||||||
# 8. Controller SDK
|
|
||||||
|
|
||||||
The FairMQ Controller Software Development Kit (`-DBUILD_SDK=ON`) contains a (as of today still experimental) set of C++ APIs that provide essential functionality to the implementer of a global controller.
|
|
||||||
|
|
||||||
The FairMQ core library only provides two local controllers - `static` (a fixed sequence of state transitions) and `interactive` (a read-eval-print-loop which reads keyboard commands from standard input). A local controller only knows how steer a single [FairMQ device](Device.md) - in fact, it runs in a thread within the device process.
|
|
||||||
|
|
||||||
A global controller has knowledge about the full topology of connected FairMQ devices. Its responsibility is to facilitate the lifecycle of a distributed FairMQ-based application (*executing a topology*), such as
|
|
||||||
|
|
||||||
* allocating/releasing compute resources from a resource management system,
|
|
||||||
* launching/setting up the run-time environment and the FairMQ devices,
|
|
||||||
* driving the device state machines in lock-step across the full topology,
|
|
||||||
* pushing the device configuration,
|
|
||||||
* monitoring (some aspects of the application's) operation,
|
|
||||||
* and handling/reporting (some) error cases.
|
|
||||||
|
|
||||||
The low-level hook to integrate FairMQ devices with such a global contoller is the [plugin mechanism](Plugins.md) in the FairMQ core library. The FairMQ Controller SDK provides C++ APIs that communicate to the endpoints exposed by such a FairMQ plugin.
|
|
||||||
|
|
||||||
At the moment, the Controller SDK only supports [DDS](https://dds.gsi.de) as resource manager and run-time environment. A second implementation based on [PMIx](https://pmix.org/) (targeting its implementation in [Slurm](https://slurm.schedmd.com/documentation.html) and [OpenRTE](https://www-lb.open-mpi.org/papers/euro-pvmmpi-2005-orte/)) is in development.
|
|
||||||
|
|
||||||
The following section give a short overview on the APIs provided.
|
|
||||||
|
|
||||||
## RMS and run-time environment
|
|
||||||
|
|
||||||
The classes [`fair::mq::sdk::DDSEnvironment`](../fairmq/sdk/DDSEnvironment.h), [`fair::mq::sdk::DDSSession`](../fairmq/sdk/DDSSession.h), and [`fair::mq::sdk::DDSTopology`](../fairmq/sdk/DDSTopology.h) are thin wrappers of most of the synchronous APIs exposed by DDS ([`dds::tools_api`](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1tools__api.html) and [`dds::topology_api`](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1topology__api.html)). E.g. they allow to [start a DDS session](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L26-L28), [allocate resources](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L34) and [launch a topology](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L39) from a C++ program.
|
|
||||||
|
|
||||||
## Driving the global state machine
|
|
||||||
|
|
||||||
The class [`fair::mq::sdk::Topology`](../fairmq/sdk/Topology.h) adds a FairMQ-specific view on an existing DDS session that is executing a topology of FairMQ devices. One can e.g. [initiate a state transition on all devices in the topology simultaneously](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L48-L49). This topology transition completes once a topology-wide barrier is passed (all devices completed the transition). This effectively exposes the device state machine as a topology state machine. The implementation is based on remote procedure calls over the [DDS intercom service](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1intercom__api.html) between the controller and the DDS plugin shipped with FairMQ (`-DBUILD_DDS_PLUGIN=ON`).
|
|
||||||
|
|
||||||
For future versions of the SDK new APIs are planned to inspect and modify the device configurations and also operate only on subsets of a given topology.
|
|
||||||
|
|
||||||
← [Back](../README.md)
|
|
|
@ -1,12 +1,12 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
# Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
# Copyright (C) 2012-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||||
# #
|
# #
|
||||||
# This software is distributed under the terms of the #
|
# This software is distributed under the terms of the #
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||||
# copied verbatim in the file "LICENSE" #
|
# copied verbatim in the file "LICENSE" #
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
if(BUILD_FAIRMQ OR BUILD_SDK)
|
if(BUILD_FAIRMQ)
|
||||||
|
|
||||||
if(BUILD_TIDY_TOOL)
|
if(BUILD_TIDY_TOOL)
|
||||||
include(FairMQTidy)
|
include(FairMQTidy)
|
||||||
|
@ -452,20 +452,9 @@ if(BUILD_FAIRMQ)
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_SDK_COMMANDS)
|
|
||||||
add_subdirectory(sdk/commands)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_SDK)
|
|
||||||
add_subdirectory(sdk)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# external plugins #
|
# external plugins #
|
||||||
####################
|
####################
|
||||||
if(BUILD_DDS_PLUGIN)
|
|
||||||
add_subdirectory(plugins/DDS)
|
|
||||||
endif()
|
|
||||||
if(BUILD_PMIX_PLUGIN)
|
if(BUILD_PMIX_PLUGIN)
|
||||||
add_subdirectory(plugins/PMIx)
|
add_subdirectory(plugins/PMIx)
|
||||||
endif()
|
endif()
|
||||||
|
|
26
fairmq/SDK.h
26
fairmq/SDK.h
|
@ -1,26 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_H
|
|
||||||
#define FAIR_MQ_SDK_H
|
|
||||||
|
|
||||||
// IWYU pragma: begin_exports
|
|
||||||
#include <fairmq/sdk/AsioAsyncOp.h>
|
|
||||||
#include <fairmq/sdk/AsioBase.h>
|
|
||||||
#include <fairmq/sdk/DDSAgent.h>
|
|
||||||
#include <fairmq/sdk/DDSEnvironment.h>
|
|
||||||
#include <fairmq/sdk/DDSInfo.h>
|
|
||||||
#include <fairmq/sdk/DDSSession.h>
|
|
||||||
#include <fairmq/sdk/DDSTask.h>
|
|
||||||
#include <fairmq/sdk/DDSTopology.h>
|
|
||||||
#include <fairmq/sdk/Error.h>
|
|
||||||
#include <fairmq/sdk/Topology.h>
|
|
||||||
#include <fairmq/sdk/Traits.h>
|
|
||||||
// IWYU pragma: end_exports
|
|
||||||
|
|
||||||
#endif // FAIR_MQ_SDK_H
|
|
|
@ -1,24 +0,0 @@
|
||||||
################################################################################
|
|
||||||
# Copyright (C) 2012-2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
|
||||||
# #
|
|
||||||
# This software is distributed under the terms of the #
|
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
|
||||||
# copied verbatim in the file "LICENSE" #
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
set(plugin FairMQPlugin_dds)
|
|
||||||
add_library(${plugin} SHARED ${CMAKE_CURRENT_SOURCE_DIR}/DDS.cxx ${CMAKE_CURRENT_SOURCE_DIR}/DDS.h)
|
|
||||||
target_compile_features(${plugin} PUBLIC cxx_std_17)
|
|
||||||
target_link_libraries(${plugin} PUBLIC FairMQ StateMachine DDS::dds_intercom_lib DDS::dds_protocol_lib Boost::boost PRIVATE Commands asio::asio)
|
|
||||||
target_include_directories(${plugin} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
set_target_properties(${plugin} PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
|
||||||
set_target_properties(${plugin} PROPERTIES
|
|
||||||
VERSION ${PROJECT_VERSION}
|
|
||||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
|
||||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/fairmq
|
|
||||||
)
|
|
||||||
|
|
||||||
install(TARGETS ${plugin}
|
|
||||||
EXPORT ${PROJECT_EXPORT_SET}
|
|
||||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
|
||||||
)
|
|
|
@ -1,457 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "DDS.h"
|
|
||||||
|
|
||||||
#include <fairmq/tools/Strings.h>
|
|
||||||
|
|
||||||
#include <boost/algorithm/string/join.hpp>
|
|
||||||
#include <boost/algorithm/string/split.hpp>
|
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
|
||||||
#include <asio/post.hpp>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using fair::mq::tools::ToString;
|
|
||||||
|
|
||||||
namespace fair::mq::plugins
|
|
||||||
{
|
|
||||||
|
|
||||||
DDS::DDS(const string& name,
|
|
||||||
const Plugin::Version version,
|
|
||||||
const string& maintainer,
|
|
||||||
const string& homepage,
|
|
||||||
PluginServices* pluginServices)
|
|
||||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
|
||||||
, fDDSTaskId(dds::env_prop<dds::task_id>())
|
|
||||||
, fCurrentState(DeviceState::Idle)
|
|
||||||
, fLastState(DeviceState::Idle)
|
|
||||||
, fDeviceTerminationRequested(false)
|
|
||||||
, fLastExternalController(0)
|
|
||||||
, fExitingAckedByLastExternalController(false)
|
|
||||||
, fUpdatesAllowed(false)
|
|
||||||
, fWorkGuard(fWorkerQueue.get_executor())
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
TakeDeviceControl();
|
|
||||||
|
|
||||||
string deviceId(GetProperty<string>("id"));
|
|
||||||
if (deviceId.empty()) {
|
|
||||||
SetProperty<string>("id", dds::env_prop<dds::task_path>());
|
|
||||||
}
|
|
||||||
string sessionId(GetProperty<string>("session"));
|
|
||||||
if (sessionId == "default") {
|
|
||||||
SetProperty<string>("session", dds::env_prop<dds::dds_session_id>());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto control = GetProperty<string>("control");
|
|
||||||
if (control == "static") {
|
|
||||||
LOG(error) << "DDS Plugin: static mode is not supported";
|
|
||||||
throw invalid_argument("DDS Plugin: static mode is not supported");
|
|
||||||
} else if (control == "dynamic" || control == "external" || control == "interactive") {
|
|
||||||
LOG(debug) << "Running DDS controller: external";
|
|
||||||
} else {
|
|
||||||
LOG(error) << "Unrecognized control mode '" << control << "' requested. " << "Ignoring and starting in external control mode.";
|
|
||||||
}
|
|
||||||
|
|
||||||
SubscribeForCustomCommands();
|
|
||||||
SubscribeForConnectingChannels();
|
|
||||||
|
|
||||||
// subscribe to device state changes, pushing new state changes into the event queue
|
|
||||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
|
||||||
switch (newState) {
|
|
||||||
case DeviceState::Bound: {
|
|
||||||
// Receive addresses of connecting channels from DDS
|
|
||||||
// and propagate addresses of bound channels to DDS.
|
|
||||||
FillChannelContainers();
|
|
||||||
|
|
||||||
// allow updates from key value after channel containers are filled
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lk(fUpdateMutex);
|
|
||||||
fUpdatesAllowed = true;
|
|
||||||
}
|
|
||||||
fUpdateCondition.notify_one();
|
|
||||||
|
|
||||||
// publish bound addresses via DDS at keys corresponding to the channel
|
|
||||||
// prefixes, e.g. 'data' in data[i]
|
|
||||||
PublishBoundChannels();
|
|
||||||
} break;
|
|
||||||
case DeviceState::ResettingDevice: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lk(fUpdateMutex);
|
|
||||||
fUpdatesAllowed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EmptyChannelContainers();
|
|
||||||
} break;
|
|
||||||
case DeviceState::Exiting: {
|
|
||||||
if (!fControllerThread.joinable()) {
|
|
||||||
fControllerThread = thread(&DDS::WaitForExitingAck, this);
|
|
||||||
}
|
|
||||||
fWorkGuard.reset();
|
|
||||||
fDeviceTerminationRequested = true;
|
|
||||||
UnsubscribeFromDeviceStateChange();
|
|
||||||
ReleaseDeviceControl();
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace sdk::cmd;
|
|
||||||
auto now = chrono::steady_clock::now();
|
|
||||||
string id = GetProperty<string>("id");
|
|
||||||
fLastState = fCurrentState;
|
|
||||||
fCurrentState = newState;
|
|
||||||
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
for (auto it = fStateChangeSubscribers.cbegin(); it != fStateChangeSubscribers.end();) {
|
|
||||||
// if a subscriber did not send a heartbeat in more than 3 times the promised interval,
|
|
||||||
// remove it from the subscriber list
|
|
||||||
if (chrono::duration<double>(now - it->second.first).count() > 3 * it->second.second) {
|
|
||||||
LOG(warn) << "Controller '" << it->first
|
|
||||||
<< "' did not send heartbeats since over 3 intervals ("
|
|
||||||
<< 3 * it->second.second << " ms), removing it.";
|
|
||||||
fStateChangeSubscribers.erase(it++);
|
|
||||||
} else {
|
|
||||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << it->first;
|
|
||||||
Cmds cmds(make<StateChange>(id, fDDSTaskId, fLastState, fCurrentState));
|
|
||||||
fDDS.Send(cmds.Serialize(), to_string(it->first));
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
StartWorkerThread();
|
|
||||||
|
|
||||||
fDDS.Start();
|
|
||||||
} catch (PluginServices::DeviceControlError& e) {
|
|
||||||
LOG(debug) << e.what();
|
|
||||||
} catch (exception& e) {
|
|
||||||
LOG(error) << "Error in plugin initialization: " << e.what();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DDS::EmptyChannelContainers()
|
|
||||||
{
|
|
||||||
fBindingChans.clear();
|
|
||||||
fConnectingChans.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::StartWorkerThread() -> void
|
|
||||||
{
|
|
||||||
fWorkerThread = thread([this]() {
|
|
||||||
fWorkerQueue.run();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::WaitForExitingAck() -> void
|
|
||||||
{
|
|
||||||
unique_lock<mutex> lock(fStateChangeSubscriberMutex);
|
|
||||||
auto timeout = GetProperty<unsigned int>("wait-for-exiting-ack-timeout");
|
|
||||||
fExitingAcked.wait_for(lock, chrono::milliseconds(timeout), [this]() {
|
|
||||||
return fExitingAckedByLastExternalController || fStateChangeSubscribers.empty();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::FillChannelContainers() -> void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
unordered_map<string, int> channelInfo(GetChannelInfo());
|
|
||||||
|
|
||||||
// fill binding and connecting chans
|
|
||||||
for (const auto& c : channelInfo) {
|
|
||||||
string methodKey{"chans." + c.first + "." + to_string(c.second - 1) + ".method"};
|
|
||||||
if (GetProperty<string>(methodKey) == "bind") {
|
|
||||||
fBindingChans.insert(make_pair(c.first, vector<string>()));
|
|
||||||
for (int i = 0; i < c.second; ++i) {
|
|
||||||
fBindingChans.at(c.first).push_back(GetProperty<string>(string{"chans." + c.first + "." + to_string(i) + ".address"}));
|
|
||||||
}
|
|
||||||
} else if (GetProperty<string>(methodKey) == "connect") {
|
|
||||||
fConnectingChans.insert(make_pair(c.first, DDSConfig()));
|
|
||||||
LOG(debug) << "preparing to connect: " << c.first << " with " << c.second << " sub-channels.";
|
|
||||||
fConnectingChans.at(c.first).fNumSubChannels = c.second;
|
|
||||||
} else {
|
|
||||||
LOG(error) << "Cannot update address configuration. Channel method (bind/connect) not specified.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// save properties that will have multiple values arriving (with only some of them to be used)
|
|
||||||
vector<string> iValues;
|
|
||||||
if (PropertyExists("dds-i")) {
|
|
||||||
iValues = GetProperty<vector<string>>("dds-i");
|
|
||||||
}
|
|
||||||
vector<string> inValues;
|
|
||||||
if (PropertyExists("dds-i-n")) {
|
|
||||||
inValues = GetProperty<vector<string>>("dds-i-n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& vi : iValues) {
|
|
||||||
size_t pos = vi.find(":");
|
|
||||||
string chanName = vi.substr(0, pos);
|
|
||||||
|
|
||||||
// check if provided name is a valid channel name
|
|
||||||
if (fConnectingChans.find(chanName) == fConnectingChans.end()) {
|
|
||||||
throw invalid_argument(ToString("channel provided to dds-i is not an actual connecting channel of this device: ", chanName));
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = stoi(vi.substr(pos + 1));
|
|
||||||
LOG(debug) << "dds-i: adding " << chanName << " -> i of " << i;
|
|
||||||
fI.insert(make_pair(chanName, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& vi : inValues) {
|
|
||||||
size_t pos = vi.find(":");
|
|
||||||
string chanName = vi.substr(0, pos);
|
|
||||||
|
|
||||||
// check if provided name is a valid channel name
|
|
||||||
if (fConnectingChans.find(chanName) == fConnectingChans.end()) {
|
|
||||||
throw invalid_argument(ToString("channel provided to dds-i-n is not an actual connecting channel of this device: ", chanName));
|
|
||||||
}
|
|
||||||
|
|
||||||
string i_n = vi.substr(pos + 1);
|
|
||||||
pos = i_n.find("-");
|
|
||||||
int i = stoi(i_n.substr(0, pos));
|
|
||||||
int n = stoi(i_n.substr(pos + 1));
|
|
||||||
LOG(debug) << "dds-i-n: adding " << chanName << " -> i: " << i << " n: " << n;
|
|
||||||
fIofN.insert(make_pair(chanName, IofN(i, n)));
|
|
||||||
}
|
|
||||||
} catch (const exception& e) {
|
|
||||||
LOG(error) << "Error filling channel containers: " << e.what();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::SubscribeForConnectingChannels() -> void
|
|
||||||
{
|
|
||||||
LOG(debug) << "Subscribing for DDS properties.";
|
|
||||||
|
|
||||||
fDDS.SubscribeKeyValue([&] (const string& key, const string& value, uint64_t senderTaskID) {
|
|
||||||
LOG(debug) << "Received property: key=" << key << ", value=" << value << ", senderTaskID=" << senderTaskID;
|
|
||||||
|
|
||||||
if (key.compare(0, 8, "fmqchan_") != 0) {
|
|
||||||
LOG(debug) << "property update is not a channel info update: " << key;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
string channelName = key.substr(8);
|
|
||||||
LOG(info) << "Update for channel name: " << channelName;
|
|
||||||
|
|
||||||
asio::post(fWorkerQueue, [=]() {
|
|
||||||
try {
|
|
||||||
{
|
|
||||||
unique_lock<mutex> lk(fUpdateMutex);
|
|
||||||
fUpdateCondition.wait(lk, [&]{ return fUpdatesAllowed; });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fConnectingChans.find(channelName) == fConnectingChans.end()) {
|
|
||||||
LOG(error) << "Received an update for a connecting channel, but either no channel with given channel name exists or it has already been configured: '" << channelName << "', ignoring...";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string val = value;
|
|
||||||
// check if it is to handle as one out of multiple values
|
|
||||||
auto it = fIofN.find(channelName);
|
|
||||||
if (it != fIofN.end()) {
|
|
||||||
it->second.fEntries.push_back(value);
|
|
||||||
if (it->second.fEntries.size() == it->second.fN) {
|
|
||||||
sort(it->second.fEntries.begin(), it->second.fEntries.end());
|
|
||||||
val = it->second.fEntries.at(it->second.fI);
|
|
||||||
} else {
|
|
||||||
LOG(debug) << "received " << it->second.fEntries.size() << " values for " << channelName << ", expecting total of " << it->second.fN;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<string> connectionStrings;
|
|
||||||
boost::algorithm::split(connectionStrings, val, boost::algorithm::is_any_of(","));
|
|
||||||
if (connectionStrings.size() > 1) { // multiple bound channels received
|
|
||||||
auto it2 = fI.find(channelName);
|
|
||||||
if (it2 != fI.end()) {
|
|
||||||
LOG(debug) << "adding connecting channel " << channelName << " : " << connectionStrings.at(it2->second);
|
|
||||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, connectionStrings.at(it2->second).c_str()});
|
|
||||||
} else {
|
|
||||||
LOG(error) << "multiple bound channels received, but no task index specified, only assigning the first";
|
|
||||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, connectionStrings.at(0).c_str()});
|
|
||||||
}
|
|
||||||
} else { // only one bound channel received
|
|
||||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, val.c_str()});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& mi : fConnectingChans) {
|
|
||||||
if (mi.second.fNumSubChannels == mi.second.fDDSValues.size()) {
|
|
||||||
int i = 0;
|
|
||||||
for (const auto& e : mi.second.fDDSValues) {
|
|
||||||
auto result = UpdateProperty<string>(string{"chans." + mi.first + "." + to_string(i) + ".address"}, e.second);
|
|
||||||
if (!result) {
|
|
||||||
LOG(error) << "UpdateProperty failed for: " << "chans." << mi.first << "." << to_string(i) << ".address" << " - property does not exist";
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const exception& e) {
|
|
||||||
LOG(error) << "Error handling DDS property: key=" << key << ", value=" << value << ", senderTaskID=" << senderTaskID << ": " << e.what();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::PublishBoundChannels() -> void
|
|
||||||
{
|
|
||||||
for (const auto& chan : fBindingChans) {
|
|
||||||
string joined = boost::algorithm::join(chan.second, ",");
|
|
||||||
LOG(debug) << "Publishing bound addresses (" << chan.second.size() << ") of channel '" << chan.first << "' to DDS under '" << "fmqchan_" + chan.first << "' property name.";
|
|
||||||
fDDS.PutValue("fmqchan_" + chan.first, joined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::SubscribeForCustomCommands() -> void
|
|
||||||
{
|
|
||||||
LOG(debug) << "Subscribing for DDS custom commands.";
|
|
||||||
|
|
||||||
string id = GetProperty<string>("id");
|
|
||||||
|
|
||||||
fDDS.SubscribeCustomCmd([id, this](const string& cmdStr, const string& cond, uint64_t senderId) {
|
|
||||||
// LOG(info) << "Received command: '" << cmdStr << "' from " << senderId;
|
|
||||||
sdk::cmd::Cmds inCmds;
|
|
||||||
inCmds.Deserialize(cmdStr);
|
|
||||||
for (const auto& cmd : inCmds) {
|
|
||||||
HandleCmd(id, *cmd, cond, senderId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::HandleCmd(const string& id, sdk::cmd::Cmd& cmd, const string& cond, uint64_t senderId) -> void
|
|
||||||
{
|
|
||||||
using namespace fair::mq::sdk;
|
|
||||||
using namespace fair::mq::sdk::cmd;
|
|
||||||
// LOG(info) << "Received command type: '" << cmd.GetType() << "' from " << senderId;
|
|
||||||
switch (cmd.GetType()) {
|
|
||||||
case Type::check_state: {
|
|
||||||
fDDS.Send(Cmds(make<CurrentState>(id, GetCurrentDeviceState())).Serialize(), to_string(senderId));
|
|
||||||
} break;
|
|
||||||
case Type::change_state: {
|
|
||||||
Transition transition = static_cast<ChangeState&>(cmd).GetTransition();
|
|
||||||
if (ChangeDeviceState(transition)) {
|
|
||||||
Cmds outCmds(make<TransitionStatus>(id, fDDSTaskId, Result::Ok, transition, GetCurrentDeviceState()));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
} else {
|
|
||||||
Cmds outCmds(make<TransitionStatus>(id, fDDSTaskId, Result::Failure, transition, GetCurrentDeviceState()));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fLastExternalController = senderId;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case Type::dump_config: {
|
|
||||||
stringstream ss;
|
|
||||||
for (const auto& pKey : GetPropertyKeys()) {
|
|
||||||
ss << id << ": " << pKey << " -> " << GetPropertyAsString(pKey) << "\n";
|
|
||||||
}
|
|
||||||
Cmds outCmds(make<Config>(id, ss.str()));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
} break;
|
|
||||||
case Type::state_change_exiting_received: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
if (fLastExternalController == senderId) {
|
|
||||||
fExitingAckedByLastExternalController = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fExitingAcked.notify_one();
|
|
||||||
} break;
|
|
||||||
case Type::subscribe_to_state_change: {
|
|
||||||
auto _cmd = static_cast<cmd::SubscribeToStateChange&>(cmd);
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fStateChangeSubscribers.emplace(senderId, make_pair(chrono::steady_clock::now(), _cmd.GetInterval()));
|
|
||||||
|
|
||||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << senderId;
|
|
||||||
|
|
||||||
Cmds outCmds(make<StateChangeSubscription>(id, fDDSTaskId, Result::Ok),
|
|
||||||
make<StateChange>(id, fDDSTaskId, fLastState, fCurrentState));
|
|
||||||
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
} break;
|
|
||||||
case Type::subscription_heartbeat: {
|
|
||||||
try {
|
|
||||||
auto _cmd = static_cast<cmd::SubscriptionHeartbeat&>(cmd);
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fStateChangeSubscribers.at(senderId) = make_pair(chrono::steady_clock::now(), _cmd.GetInterval());
|
|
||||||
} catch(out_of_range& oor) {
|
|
||||||
LOG(warn) << "Received subscription heartbeat from an unknown controller with id '" << senderId << "'";
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case Type::unsubscribe_from_state_change: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fStateChangeSubscribers.erase(senderId);
|
|
||||||
}
|
|
||||||
Cmds outCmds(make<StateChangeUnsubscription>(id, fDDSTaskId, Result::Ok));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
} break;
|
|
||||||
case Type::get_properties: {
|
|
||||||
auto _cmd = static_cast<cmd::GetProperties&>(cmd);
|
|
||||||
auto const request_id(_cmd.GetRequestId());
|
|
||||||
auto result(Result::Ok);
|
|
||||||
vector<pair<string, string>> props;
|
|
||||||
try {
|
|
||||||
for (auto const& prop : GetPropertiesAsString(_cmd.GetQuery())) {
|
|
||||||
props.push_back({prop.first, prop.second});
|
|
||||||
}
|
|
||||||
} catch (exception const& e) {
|
|
||||||
LOG(warn) << "Getting properties (request id: " << request_id << ") failed: " << e.what();
|
|
||||||
result = Result::Failure;
|
|
||||||
}
|
|
||||||
Cmds const outCmds(make<cmd::Properties>(id, request_id, result, props));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
} break;
|
|
||||||
case Type::set_properties: {
|
|
||||||
auto _cmd(static_cast<cmd::SetProperties&>(cmd));
|
|
||||||
auto const request_id(_cmd.GetRequestId());
|
|
||||||
auto result(Result::Ok);
|
|
||||||
try {
|
|
||||||
fair::mq::Properties props;
|
|
||||||
for (auto const& prop : _cmd.GetProps()) {
|
|
||||||
props.insert({prop.first, fair::mq::Property(prop.second)});
|
|
||||||
}
|
|
||||||
// TODO Handle builtin keys with different value type than string
|
|
||||||
SetProperties(props);
|
|
||||||
} catch (exception const& e) {
|
|
||||||
LOG(warn) << "Setting properties (request id: " << request_id << ") failed: " << e.what();
|
|
||||||
result = Result::Failure;
|
|
||||||
}
|
|
||||||
Cmds const outCmds(make<PropertiesSet>(id, request_id, result));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
LOG(warn) << "Unexpected/unknown command received: " << cmd.GetType();
|
|
||||||
LOG(warn) << "Origin: " << senderId;
|
|
||||||
LOG(warn) << "Destination: " << cond;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DDS::~DDS()
|
|
||||||
{
|
|
||||||
UnsubscribeFromDeviceStateChange();
|
|
||||||
ReleaseDeviceControl();
|
|
||||||
|
|
||||||
if (fControllerThread.joinable()) {
|
|
||||||
fControllerThread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
fWorkGuard.reset();
|
|
||||||
if (fWorkerThread.joinable()) {
|
|
||||||
fWorkerThread.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fair::mq::plugins
|
|
|
@ -1,199 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_PLUGINS_DDS
|
|
||||||
#define FAIR_MQ_PLUGINS_DDS
|
|
||||||
|
|
||||||
#include <fairmq/Plugin.h>
|
|
||||||
#include <fairmq/StateQueue.h>
|
|
||||||
#include <fairmq/Version.h>
|
|
||||||
#include <fairmq/sdk/commands/Commands.h>
|
|
||||||
|
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <dds/dds.h>
|
|
||||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
|
|
||||||
#include <asio/executor.hpp>
|
|
||||||
#include <asio/executor_work_guard.hpp>
|
|
||||||
#include <asio/io_context.hpp>
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <chrono>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <mutex>
|
|
||||||
#include <string>
|
|
||||||
#include <atomic>
|
|
||||||
#include <thread>
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility> // pair
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace fair::mq::plugins
|
|
||||||
{
|
|
||||||
|
|
||||||
struct DDSConfig
|
|
||||||
{
|
|
||||||
// container of sub channel addresses
|
|
||||||
unsigned int fNumSubChannels;
|
|
||||||
// dds values for the channel
|
|
||||||
std::map<uint64_t, std::string> fDDSValues;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DDSSubscription
|
|
||||||
{
|
|
||||||
DDSSubscription()
|
|
||||||
: fDDSCustomCmd(fService)
|
|
||||||
, fDDSKeyValue(fService)
|
|
||||||
{
|
|
||||||
LOG(debug) << "$DDS_TASK_PATH: " << dds::env_prop<dds::task_path>();
|
|
||||||
LOG(debug) << "$DDS_GROUP_NAME: " << dds::env_prop<dds::group_name>();
|
|
||||||
LOG(debug) << "$DDS_COLLECTION_NAME: " << dds::env_prop<dds::collection_name>();
|
|
||||||
LOG(debug) << "$DDS_TASK_NAME: " << dds::env_prop<dds::task_name>();
|
|
||||||
LOG(debug) << "$DDS_TASK_INDEX: " << dds::env_prop<dds::task_index>();
|
|
||||||
LOG(debug) << "$DDS_COLLECTION_INDEX: " << dds::env_prop<dds::collection_index>();
|
|
||||||
LOG(debug) << "$DDS_TASK_ID: " << dds::env_prop<dds::task_id>();
|
|
||||||
LOG(debug) << "$DDS_LOCATION: " << dds::env_prop<dds::dds_location>();
|
|
||||||
std::string dds_session_id(dds::env_prop<dds::dds_session_id>());
|
|
||||||
LOG(debug) << "$DDS_SESSION_ID: " << dds_session_id;
|
|
||||||
|
|
||||||
// subscribe for DDS service errors.
|
|
||||||
fService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& errorMsg) {
|
|
||||||
LOG(error) << "DDS Error received: error code: " << errorCode << ", error message: " << errorMsg;
|
|
||||||
});
|
|
||||||
|
|
||||||
// fDDSCustomCmd.subscribe([](const std::string& cmd, const std::string& cond, uint64_t senderId) {
|
|
||||||
// LOG(debug) << "cmd: " << cmd << ", cond: " << cond << ", senderId: " << senderId;
|
|
||||||
// });
|
|
||||||
assert(!dds_session_id.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Start() -> void {
|
|
||||||
fService.start(dds::env_prop<dds::dds_session_id>());
|
|
||||||
}
|
|
||||||
|
|
||||||
~DDSSubscription() {
|
|
||||||
fDDSKeyValue.unsubscribe();
|
|
||||||
fDDSCustomCmd.unsubscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
auto SubscribeCustomCmd(Args&&... args) -> void
|
|
||||||
{
|
|
||||||
fDDSCustomCmd.subscribe(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
auto SubscribeKeyValue(Args&&... args) -> void
|
|
||||||
{
|
|
||||||
fDDSKeyValue.subscribe(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
auto Send(Args&&... args) -> void
|
|
||||||
{
|
|
||||||
fDDSCustomCmd.send(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
auto PutValue(Args&&... args) -> void
|
|
||||||
{
|
|
||||||
fDDSKeyValue.putValue(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
dds::intercom_api::CIntercomService fService;
|
|
||||||
dds::intercom_api::CCustomCmd fDDSCustomCmd;
|
|
||||||
dds::intercom_api::CKeyValue fDDSKeyValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IofN
|
|
||||||
{
|
|
||||||
IofN(int i, int n)
|
|
||||||
: fI(i)
|
|
||||||
, fN(n)
|
|
||||||
{}
|
|
||||||
|
|
||||||
unsigned int fI;
|
|
||||||
unsigned int fN;
|
|
||||||
std::vector<std::string> fEntries;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DDS : public Plugin
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DDS(const std::string& name, const Plugin::Version version, const std::string& maintainer, const std::string& homepage, PluginServices* pluginServices);
|
|
||||||
|
|
||||||
~DDS();
|
|
||||||
|
|
||||||
private:
|
|
||||||
auto WaitForExitingAck() -> void;
|
|
||||||
auto StartWorkerThread() -> void;
|
|
||||||
|
|
||||||
auto FillChannelContainers() -> void;
|
|
||||||
auto EmptyChannelContainers() -> void;
|
|
||||||
|
|
||||||
auto SubscribeForConnectingChannels() -> void;
|
|
||||||
auto PublishBoundChannels() -> void;
|
|
||||||
auto SubscribeForCustomCommands() -> void;
|
|
||||||
auto HandleCmd(const std::string& id, sdk::cmd::Cmd& cmd, const std::string& cond, uint64_t senderId) -> void;
|
|
||||||
|
|
||||||
DDSSubscription fDDS;
|
|
||||||
size_t fDDSTaskId;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::vector<std::string>> fBindingChans;
|
|
||||||
std::unordered_map<std::string, DDSConfig> fConnectingChans;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, int> fI;
|
|
||||||
std::unordered_map<std::string, IofN> fIofN;
|
|
||||||
|
|
||||||
std::thread fControllerThread;
|
|
||||||
DeviceState fCurrentState, fLastState;
|
|
||||||
|
|
||||||
std::atomic<bool> fDeviceTerminationRequested;
|
|
||||||
|
|
||||||
std::unordered_map<uint64_t, std::pair<std::chrono::steady_clock::time_point, int64_t>> fStateChangeSubscribers;
|
|
||||||
uint64_t fLastExternalController;
|
|
||||||
bool fExitingAckedByLastExternalController;
|
|
||||||
std::condition_variable fExitingAcked;
|
|
||||||
std::mutex fStateChangeSubscriberMutex;
|
|
||||||
|
|
||||||
bool fUpdatesAllowed;
|
|
||||||
std::mutex fUpdateMutex;
|
|
||||||
std::condition_variable fUpdateCondition;
|
|
||||||
|
|
||||||
std::thread fWorkerThread;
|
|
||||||
asio::io_context fWorkerQueue;
|
|
||||||
asio::executor_work_guard<asio::executor> fWorkGuard;
|
|
||||||
};
|
|
||||||
|
|
||||||
Plugin::ProgOptions DDSProgramOptions()
|
|
||||||
{
|
|
||||||
boost::program_options::options_description options{"DDS Plugin"};
|
|
||||||
options.add_options()
|
|
||||||
("dds-i", boost::program_options::value<std::vector<std::string>>()->multitoken()->composing(), "Task index for chosing connection target (single channel n to m). When all values come via same update.")
|
|
||||||
("dds-i-n", boost::program_options::value<std::vector<std::string>>()->multitoken()->composing(), "Task index for chosing connection target (one out of n values to take). When values come as independent updates.")
|
|
||||||
("wait-for-exiting-ack-timeout", boost::program_options::value<unsigned int>()->default_value(1000), "Wait timeout for EXITING state-change acknowledgement by external controller in milliseconds.");
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
REGISTER_FAIRMQ_PLUGIN(
|
|
||||||
DDS, // Class name
|
|
||||||
dds, // Plugin name (string, lower case chars only)
|
|
||||||
(Plugin::Version{FAIRMQ_VERSION_MAJOR,
|
|
||||||
FAIRMQ_VERSION_MINOR,
|
|
||||||
FAIRMQ_VERSION_PATCH}), // Version
|
|
||||||
"FairRootGroup <fairroot@gsi.de>", // Maintainer
|
|
||||||
"https://github.com/FairRootGroup/FairMQ", // Homepage
|
|
||||||
DDSProgramOptions // custom program options for the plugin
|
|
||||||
)
|
|
||||||
|
|
||||||
} // namespace fair::mq::plugins
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_PLUGINS_DDS */
|
|
|
@ -1,5 +1,5 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
# Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||||
# #
|
# #
|
||||||
# This software is distributed under the terms of the #
|
# This software is distributed under the terms of the #
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||||
|
@ -14,7 +14,7 @@ add_library(${plugin} SHARED
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/PMIx.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/PMIx.hpp
|
||||||
)
|
)
|
||||||
target_compile_features(${plugin} PUBLIC cxx_std_17)
|
target_compile_features(${plugin} PUBLIC cxx_std_17)
|
||||||
target_link_libraries(${plugin} PUBLIC FairMQ PMIx::libpmix PRIVATE Commands)
|
target_link_libraries(${plugin} PUBLIC FairMQ PMIx::libpmix)
|
||||||
target_include_directories(${plugin} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
target_include_directories(${plugin} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
set_target_properties(${plugin} PROPERTIES
|
set_target_properties(${plugin} PROPERTIES
|
||||||
CXX_VISIBILITY_PRESET hidden
|
CXX_VISIBILITY_PRESET hidden
|
||||||
|
@ -24,7 +24,7 @@ set_target_properties(${plugin} PROPERTIES
|
||||||
|
|
||||||
set(exe fairmq-pmix-command-ui)
|
set(exe fairmq-pmix-command-ui)
|
||||||
add_executable(${exe} ${CMAKE_CURRENT_SOURCE_DIR}/runPMIxCommandUI.cxx)
|
add_executable(${exe} ${CMAKE_CURRENT_SOURCE_DIR}/runPMIxCommandUI.cxx)
|
||||||
target_link_libraries(${exe} FairMQ Commands StateMachine PMIx::libpmix)
|
target_link_libraries(${exe} FairMQ StateMachine PMIx::libpmix)
|
||||||
target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
install(TARGETS ${plugin} ${exe}
|
install(TARGETS ${plugin} ${exe}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include "PMIxPlugin.h"
|
#include "PMIxPlugin.h"
|
||||||
|
|
||||||
#include <fairmq/sdk/commands/Commands.h>
|
|
||||||
#include <fairmq/tools/Strings.h>
|
#include <fairmq/tools/Strings.h>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -16,7 +15,6 @@
|
||||||
#include <cstdint> // UINT32_MAX
|
#include <cstdint> // UINT32_MAX
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace fair::mq::sdk::cmd;
|
|
||||||
|
|
||||||
namespace fair::mq::plugins
|
namespace fair::mq::plugins
|
||||||
{
|
{
|
||||||
|
@ -31,8 +29,7 @@ PMIxPlugin::PMIxPlugin(const string& name,
|
||||||
, fPid(getpid())
|
, fPid(getpid())
|
||||||
, fPMIxClient(tools::ToString("PMIx client(pid=", fPid, ") "))
|
, fPMIxClient(tools::ToString("PMIx client(pid=", fPid, ") "))
|
||||||
, fDeviceId(string(fProcess.nspace) + "_" + to_string(fProcess.rank))
|
, fDeviceId(string(fProcess.nspace) + "_" + to_string(fProcess.rank))
|
||||||
, fCommands(fProcess)
|
// , fLastExternalController(UINT32_MAX)
|
||||||
, fLastExternalController(UINT32_MAX)
|
|
||||||
, fExitingAckedByLastExternalController(false)
|
, fExitingAckedByLastExternalController(false)
|
||||||
, fCurrentState(DeviceState::Idle)
|
, fCurrentState(DeviceState::Idle)
|
||||||
, fLastState(DeviceState::Idle)
|
, fLastState(DeviceState::Idle)
|
||||||
|
@ -42,12 +39,6 @@ PMIxPlugin::PMIxPlugin(const string& name,
|
||||||
SetProperty<string>("id", fDeviceId);
|
SetProperty<string>("id", fDeviceId);
|
||||||
|
|
||||||
Fence("pmix::init");
|
Fence("pmix::init");
|
||||||
SubscribeForCommands();
|
|
||||||
Fence("subscribed");
|
|
||||||
|
|
||||||
// fCommands.Send("test1");
|
|
||||||
// fCommands.Send("test2", 0);
|
|
||||||
// fCommands.Send("test3", 0);
|
|
||||||
|
|
||||||
// LOG(info) << "PMIX_EXTERNAL_ERR_BASE: " << PMIX_EXTERNAL_ERR_BASE;
|
// LOG(info) << "PMIX_EXTERNAL_ERR_BASE: " << PMIX_EXTERNAL_ERR_BASE;
|
||||||
|
|
||||||
|
@ -101,11 +92,9 @@ PMIxPlugin::PMIxPlugin(const string& name,
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||||
fLastState = fCurrentState;
|
fLastState = fCurrentState;
|
||||||
fCurrentState = newState;
|
fCurrentState = newState;
|
||||||
for (auto subscriberId : fStateChangeSubscribers) {
|
// for (auto subscriberId : fStateChangeSubscribers) {
|
||||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << newState << " to " << subscriberId;
|
// LOG(debug) << "Publishing state-change: " << fLastState << "->" << newState << " to " << subscriberId;
|
||||||
Cmds cmds(make<StateChange>(fDeviceId, 0, fLastState, fCurrentState));
|
// }
|
||||||
fCommands.Send(cmds.Serialize(Format::JSON), static_cast<pmix::rank>(subscriberId));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +102,6 @@ PMIxPlugin::~PMIxPlugin()
|
||||||
{
|
{
|
||||||
LOG(debug) << "Destroying PMIxPlugin";
|
LOG(debug) << "Destroying PMIxPlugin";
|
||||||
ReleaseDeviceControl();
|
ReleaseDeviceControl();
|
||||||
fCommands.Unsubscribe();
|
|
||||||
while (pmix::initialized()) {
|
while (pmix::initialized()) {
|
||||||
try {
|
try {
|
||||||
pmix::finalize();
|
pmix::finalize();
|
||||||
|
@ -124,92 +112,6 @@ PMIxPlugin::~PMIxPlugin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PMIxPlugin::SubscribeForCommands() -> void
|
|
||||||
{
|
|
||||||
fCommands.Subscribe([this](const string& cmdStr, const pmix::proc& sender) {
|
|
||||||
// LOG(info) << "PMIx Plugin received message: '" << cmdStr << "', from " << sender;
|
|
||||||
|
|
||||||
Cmds inCmds;
|
|
||||||
inCmds.Deserialize(cmdStr, Format::JSON);
|
|
||||||
|
|
||||||
for (const auto& cmd : inCmds) {
|
|
||||||
LOG(info) << "Received command type: '" << cmd->GetType() << "' from " << sender;
|
|
||||||
switch (cmd->GetType()) {
|
|
||||||
case Type::check_state:
|
|
||||||
fCommands.Send(Cmds(make<CurrentState>(fDeviceId, GetCurrentDeviceState()))
|
|
||||||
.Serialize(Format::JSON),
|
|
||||||
{sender});
|
|
||||||
break;
|
|
||||||
case Type::change_state: {
|
|
||||||
Transition transition = static_cast<ChangeState&>(*cmd).GetTransition();
|
|
||||||
if (ChangeDeviceState(transition)) {
|
|
||||||
fCommands.Send(
|
|
||||||
Cmds(make<TransitionStatus>(fDeviceId, 0, Result::Ok, transition, GetCurrentDeviceState()))
|
|
||||||
.Serialize(Format::JSON),
|
|
||||||
{sender});
|
|
||||||
} else {
|
|
||||||
fCommands.Send(
|
|
||||||
Cmds(make<TransitionStatus>(fDeviceId, 0, Result::Failure, transition, GetCurrentDeviceState()))
|
|
||||||
.Serialize(Format::JSON),
|
|
||||||
{sender});
|
|
||||||
}
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fLastExternalController = sender.rank;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::subscribe_to_state_change: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fStateChangeSubscribers.insert(sender.rank);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState
|
|
||||||
<< " to " << sender;
|
|
||||||
Cmds outCmds(make<StateChangeSubscription>(fDeviceId, fProcess.rank, Result::Ok),
|
|
||||||
make<StateChange>(fDeviceId, 0, fLastState, fCurrentState));
|
|
||||||
fCommands.Send(outCmds.Serialize(Format::JSON), {sender});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::unsubscribe_from_state_change: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fStateChangeSubscribers.erase(sender.rank);
|
|
||||||
}
|
|
||||||
fCommands.Send(Cmds(make<StateChangeUnsubscription>(fDeviceId, fProcess.rank, Result::Ok))
|
|
||||||
.Serialize(Format::JSON),
|
|
||||||
{sender});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::state_change_exiting_received: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
if (fLastExternalController == sender.rank) {
|
|
||||||
fExitingAckedByLastExternalController = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fExitingAcked.notify_one();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::dump_config: {
|
|
||||||
stringstream ss;
|
|
||||||
for (const auto& k: GetPropertyKeys()) {
|
|
||||||
ss << fDeviceId << ": " << k << " -> " << GetPropertyAsString(k) << "\n";
|
|
||||||
}
|
|
||||||
fCommands.Send(Cmds(make<Config>(fDeviceId, ss.str())).Serialize(Format::JSON),
|
|
||||||
{sender});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG(warn) << "Unexpected/unknown command received: " << cmdStr;
|
|
||||||
LOG(warn) << "Origin: " << sender;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto PMIxPlugin::Init() -> pmix::proc
|
auto PMIxPlugin::Init() -> pmix::proc
|
||||||
{
|
{
|
||||||
if (!pmix::initialized()) {
|
if (!pmix::initialized()) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
@ -44,10 +44,9 @@ class PMIxPlugin : public Plugin
|
||||||
pid_t fPid;
|
pid_t fPid;
|
||||||
std::string fPMIxClient;
|
std::string fPMIxClient;
|
||||||
std::string fDeviceId;
|
std::string fDeviceId;
|
||||||
pmix::Commands fCommands;
|
|
||||||
|
|
||||||
std::set<uint32_t> fStateChangeSubscribers;
|
std::set<uint32_t> fStateChangeSubscribers;
|
||||||
uint32_t fLastExternalController;
|
// uint32_t fLastExternalController;
|
||||||
bool fExitingAckedByLastExternalController;
|
bool fExitingAckedByLastExternalController;
|
||||||
std::condition_variable fExitingAcked;
|
std::condition_variable fExitingAcked;
|
||||||
std::mutex fStateChangeSubscriberMutex;
|
std::mutex fStateChangeSubscriberMutex;
|
||||||
|
@ -61,7 +60,6 @@ class PMIxPlugin : public Plugin
|
||||||
auto Fence(const std::string& label) -> void;
|
auto Fence(const std::string& label) -> void;
|
||||||
auto Lookup() -> void;
|
auto Lookup() -> void;
|
||||||
|
|
||||||
auto SubscribeForCommands() -> void;
|
|
||||||
auto WaitForExitingAck() -> void;
|
auto WaitForExitingAck() -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2014-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
* copied verbatim in the file "LICENSE" *
|
* copied verbatim in the file "LICENSE" *
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include <fairmq/sdk/commands/Commands.h>
|
|
||||||
#include <fairmq/States.h>
|
#include <fairmq/States.h>
|
||||||
|
|
||||||
#include <fairlogger/Logger.h>
|
#include <fairlogger/Logger.h>
|
||||||
|
@ -29,7 +28,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace fair::mq::sdk::cmd;
|
|
||||||
namespace bpo = boost::program_options;
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
const std::map<fair::mq::Transition, fair::mq::State> expected =
|
const std::map<fair::mq::Transition, fair::mq::State> expected =
|
||||||
|
@ -46,23 +44,6 @@ const std::map<fair::mq::Transition, fair::mq::State> expected =
|
||||||
{ fair::mq::Transition::End, fair::mq::State::Exiting }
|
{ fair::mq::Transition::End, fair::mq::State::Exiting }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StateSubscription
|
|
||||||
{
|
|
||||||
pmix::Commands& fCommands;
|
|
||||||
|
|
||||||
explicit StateSubscription(pmix::Commands& commands)
|
|
||||||
: fCommands(commands)
|
|
||||||
{
|
|
||||||
fCommands.Send(Cmds(make<SubscribeToStateChange>(600000)).Serialize(Format::JSON));
|
|
||||||
}
|
|
||||||
|
|
||||||
~StateSubscription()
|
|
||||||
{
|
|
||||||
fCommands.Send(Cmds(make<UnsubscribeFromStateChange>()).Serialize(Format::JSON));
|
|
||||||
this_thread::sleep_for(chrono::milliseconds(100)); // give PMIx a chance to complete request
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MiniTopo
|
struct MiniTopo
|
||||||
{
|
{
|
||||||
explicit MiniTopo(unsigned int n)
|
explicit MiniTopo(unsigned int n)
|
||||||
|
@ -141,74 +122,6 @@ int main(int argc, char* argv[])
|
||||||
LOG(warn) << "pmix::fence() [pmix::init] OK";
|
LOG(warn) << "pmix::fence() [pmix::init] OK";
|
||||||
|
|
||||||
MiniTopo topo(numDevices);
|
MiniTopo topo(numDevices);
|
||||||
pmix::Commands commands(process);
|
|
||||||
|
|
||||||
commands.Subscribe([&](const string& msg, const pmix::proc& sender) {
|
|
||||||
// LOG(info) << "Received '" << msg << "' from " << sender;
|
|
||||||
Cmds cmds;
|
|
||||||
cmds.Deserialize(msg, Format::JSON);
|
|
||||||
// cout << "Received " << cmds.Size() << " command(s) with total size of " << msg.length() << " bytes: " << endl;
|
|
||||||
for (const auto& cmd : cmds) {
|
|
||||||
// cout << " > " << cmd->GetType() << endl;
|
|
||||||
switch (cmd->GetType()) {
|
|
||||||
case Type::state_change: {
|
|
||||||
cout << "Received state_change from " << static_cast<StateChange&>(*cmd).GetDeviceId() << ": " << static_cast<StateChange&>(*cmd).GetLastState() << "->" << static_cast<StateChange&>(*cmd).GetCurrentState() << endl;
|
|
||||||
topo.Update(sender.rank, static_cast<StateChange&>(*cmd).GetCurrentState());
|
|
||||||
if (static_cast<StateChange&>(*cmd).GetCurrentState() == fair::mq::State::Exiting) {
|
|
||||||
commands.Send(Cmds(make<StateChangeExitingReceived>()).Serialize(Format::JSON), {sender});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::state_change_subscription:
|
|
||||||
if (static_cast<StateChangeSubscription&>(*cmd).GetResult() != Result::Ok) {
|
|
||||||
cout << "State change subscription failed for " << static_cast<StateChangeSubscription&>(*cmd).GetDeviceId() << endl;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::state_change_unsubscription:
|
|
||||||
if (static_cast<StateChangeUnsubscription&>(*cmd).GetResult() != Result::Ok) {
|
|
||||||
cout << "State change unsubscription failed for " << static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId() << endl;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::transition_status: {
|
|
||||||
if (static_cast<TransitionStatus&>(*cmd).GetResult() == Result::Ok) {
|
|
||||||
cout << "Device " << static_cast<TransitionStatus&>(*cmd).GetDeviceId() << " started to transition with " << static_cast<TransitionStatus&>(*cmd).GetTransition() << endl;
|
|
||||||
} else {
|
|
||||||
cout << "Device " << static_cast<TransitionStatus&>(*cmd).GetDeviceId() << " cannot transition with " << static_cast<TransitionStatus&>(*cmd).GetTransition() << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::current_state:
|
|
||||||
cout << "Device " << static_cast<CurrentState&>(*cmd).GetDeviceId() << " is in " << static_cast<CurrentState&>(*cmd).GetCurrentState() << " state" << endl;
|
|
||||||
break;
|
|
||||||
case Type::config:
|
|
||||||
cout << "Received config for device " << static_cast<Config&>(*cmd).GetDeviceId() << ":\n" << static_cast<Config&>(*cmd).GetConfig() << endl;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cout << "Unexpected/unknown command received: " << cmd->GetType() << endl;
|
|
||||||
cout << "Origin: " << sender << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
pmix::fence({all});
|
|
||||||
LOG(warn) << "pmix::fence() [subscribed] OK";
|
|
||||||
|
|
||||||
StateSubscription stateSubscription(commands);
|
|
||||||
|
|
||||||
for (auto transition : { fair::mq::Transition::InitDevice,
|
|
||||||
fair::mq::Transition::CompleteInit,
|
|
||||||
fair::mq::Transition::Bind,
|
|
||||||
fair::mq::Transition::Connect,
|
|
||||||
fair::mq::Transition::InitTask,
|
|
||||||
fair::mq::Transition::Run,
|
|
||||||
fair::mq::Transition::Stop,
|
|
||||||
fair::mq::Transition::ResetTask,
|
|
||||||
fair::mq::Transition::ResetDevice,
|
|
||||||
fair::mq::Transition::End }) {
|
|
||||||
commands.Send(Cmds(make<ChangeState>(transition)).Serialize(Format::JSON));
|
|
||||||
topo.WaitFor(expected.at(transition));
|
|
||||||
}
|
|
||||||
} catch (exception& e) {
|
} catch (exception& e) {
|
||||||
LOG(error) << "Error: " << e.what();
|
LOG(error) << "Error: " << e.what();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
|
@ -1,223 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_ASIOASYNCOP_H
|
|
||||||
#define FAIR_MQ_SDK_ASIOASYNCOP_H
|
|
||||||
|
|
||||||
#include <asio/associated_allocator.hpp>
|
|
||||||
#include <asio/associated_executor.hpp>
|
|
||||||
#include <asio/executor_work_guard.hpp>
|
|
||||||
#include <asio/dispatch.hpp>
|
|
||||||
#include <asio/system_executor.hpp>
|
|
||||||
#include <chrono>
|
|
||||||
#include <exception>
|
|
||||||
#include <fairmq/sdk/Error.h>
|
|
||||||
#include <fairmq/sdk/Traits.h>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <system_error>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <fairlogger/Logger.h>
|
|
||||||
#ifndef FAIR_LOG
|
|
||||||
#define FAIR_LOG LOG
|
|
||||||
#endif /* ifndef FAIR_LOG */
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename... SignatureArgTypes>
|
|
||||||
struct AsioAsyncOpImplBase
|
|
||||||
{
|
|
||||||
virtual auto Complete(std::error_code, SignatureArgTypes...) -> void = 0;
|
|
||||||
virtual auto IsCompleted() const -> bool = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @tparam Executor1 Associated I/O executor, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.associated_i_o_executor
|
|
||||||
* @tparam Allocator1 Default allocation strategy, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.allocation_of_intermediate_storage
|
|
||||||
*/
|
|
||||||
template<typename Executor1, typename Allocator1, typename Handler, typename... SignatureArgTypes>
|
|
||||||
struct AsioAsyncOpImpl : AsioAsyncOpImplBase<SignatureArgTypes...>
|
|
||||||
{
|
|
||||||
/// See https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.allocation_of_intermediate_storage
|
|
||||||
using Allocator2 = typename asio::associated_allocator<Handler, Allocator1>::type;
|
|
||||||
|
|
||||||
/// See https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.associated_completion_handler_executor
|
|
||||||
using Executor2 = typename asio::associated_executor<Handler, Executor1>::type;
|
|
||||||
|
|
||||||
/// Ctor
|
|
||||||
AsioAsyncOpImpl(const Executor1& ex1, Allocator1 alloc1, Handler&& handler)
|
|
||||||
: fWork1(ex1)
|
|
||||||
, fWork2(asio::get_associated_executor(handler, ex1))
|
|
||||||
, fHandler(std::move(handler))
|
|
||||||
, fAlloc1(std::move(alloc1))
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto GetAlloc2() const -> Allocator2 { return asio::get_associated_allocator(fHandler, fAlloc1); }
|
|
||||||
auto GetEx2() const -> Executor2 { return asio::get_associated_executor(fWork2); }
|
|
||||||
|
|
||||||
auto Complete(std::error_code ec, SignatureArgTypes... args) -> void override
|
|
||||||
{
|
|
||||||
if (IsCompleted()) {
|
|
||||||
throw RuntimeError("Async operation already completed");
|
|
||||||
}
|
|
||||||
|
|
||||||
asio::dispatch(GetEx2(),
|
|
||||||
[=, handler = std::move(fHandler)]() mutable {
|
|
||||||
try {
|
|
||||||
handler(ec, args...);
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
FAIR_LOG(error) << "Uncaught exception in AsioAsyncOp completion handler: " << e.what();
|
|
||||||
} catch (...) {
|
|
||||||
FAIR_LOG(error) << "Unknown uncaught exception in AsioAsyncOp completion handler.";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fWork1.reset();
|
|
||||||
fWork2.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto IsCompleted() const -> bool override
|
|
||||||
{
|
|
||||||
return !fWork1.owns_work() && !fWork2.owns_work();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// See https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.outstanding_work
|
|
||||||
asio::executor_work_guard<Executor1> fWork1;
|
|
||||||
asio::executor_work_guard<Executor2> fWork2;
|
|
||||||
Handler fHandler;
|
|
||||||
Allocator1 fAlloc1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class AsioAsyncOp AsioAsyncOp.h <fairmq/sdk/AsioAsyncOp.h>
|
|
||||||
* @tparam Executor Associated I/O executor, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.associated_i_o_executor
|
|
||||||
* @tparam Allocator Default allocation strategy, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.allocation_of_intermediate_storage
|
|
||||||
* @tparam CompletionSignature
|
|
||||||
* @brief Interface for Asio-compliant asynchronous operation, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html
|
|
||||||
*
|
|
||||||
* @par Thread Safety
|
|
||||||
* @e Distinct @e objects: Safe.@n
|
|
||||||
* @e Shared @e objects: Unsafe.
|
|
||||||
*
|
|
||||||
* primary template
|
|
||||||
*/
|
|
||||||
template<typename Executor, typename Allocator, typename CompletionSignature>
|
|
||||||
struct AsioAsyncOp
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @tparam Executor See primary template
|
|
||||||
* @tparam Allocator See primary template
|
|
||||||
* @tparam SignatureReturnType Return type of CompletionSignature, see primary template
|
|
||||||
* @tparam SignatureFirstArgType Type of first argument of CompletionSignature, see primary template
|
|
||||||
* @tparam SignatureArgTypes Types of the rest of arguments of CompletionSignature
|
|
||||||
*
|
|
||||||
* partial specialization to deconstruct CompletionSignature
|
|
||||||
*/
|
|
||||||
template<typename Executor,
|
|
||||||
typename Allocator,
|
|
||||||
typename SignatureReturnType,
|
|
||||||
typename SignatureFirstArgType,
|
|
||||||
typename... SignatureArgTypes>
|
|
||||||
struct AsioAsyncOp<Executor,
|
|
||||||
Allocator,
|
|
||||||
SignatureReturnType(SignatureFirstArgType, SignatureArgTypes...)>
|
|
||||||
{
|
|
||||||
static_assert(std::is_void<SignatureReturnType>::value,
|
|
||||||
"return value of CompletionSignature must be void");
|
|
||||||
static_assert(std::is_same<SignatureFirstArgType, std::error_code>::value,
|
|
||||||
"first argument of CompletionSignature must be std::error_code");
|
|
||||||
using Duration = std::chrono::milliseconds;
|
|
||||||
|
|
||||||
private:
|
|
||||||
using Impl = AsioAsyncOpImplBase<SignatureArgTypes...>;
|
|
||||||
using ImplPtr = std::unique_ptr<Impl, std::function<void(Impl*)>>;
|
|
||||||
ImplPtr fImpl;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// Default Ctor
|
|
||||||
AsioAsyncOp()
|
|
||||||
: fImpl(nullptr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/// Ctor with handler
|
|
||||||
template<typename Handler>
|
|
||||||
AsioAsyncOp(Executor ex1, Allocator alloc1, Handler&& handler)
|
|
||||||
: AsioAsyncOp()
|
|
||||||
{
|
|
||||||
// Async operation type to be allocated and constructed
|
|
||||||
using Op = AsioAsyncOpImpl<Executor, Allocator, Handler, SignatureArgTypes...>;
|
|
||||||
|
|
||||||
// Create allocator for concrete op type
|
|
||||||
// Allocator2, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.allocation_of_intermediate_storage
|
|
||||||
using OpAllocator =
|
|
||||||
typename std::allocator_traits<typename Op::Allocator2>::template rebind_alloc<Op>;
|
|
||||||
OpAllocator opAlloc;
|
|
||||||
|
|
||||||
// Allocate memory
|
|
||||||
auto mem(std::allocator_traits<OpAllocator>::allocate(opAlloc, 1));
|
|
||||||
|
|
||||||
// Construct object
|
|
||||||
auto ptr(new (mem) Op(std::move(ex1),
|
|
||||||
std::move(alloc1),
|
|
||||||
std::forward<Handler>(handler)));
|
|
||||||
|
|
||||||
// Assign ownership to this object
|
|
||||||
fImpl = ImplPtr(ptr, [opAlloc](Impl* p) mutable {
|
|
||||||
std::allocator_traits<OpAllocator>::deallocate(opAlloc, static_cast<Op*>(p), 1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ctor with handler #2
|
|
||||||
template<typename Handler>
|
|
||||||
AsioAsyncOp(Executor ex1, Handler&& handler)
|
|
||||||
: AsioAsyncOp(std::move(ex1), Allocator(), std::forward<Handler>(handler))
|
|
||||||
{}
|
|
||||||
|
|
||||||
/// Ctor with handler #3
|
|
||||||
template<typename Handler>
|
|
||||||
explicit AsioAsyncOp(Handler&& handler)
|
|
||||||
: AsioAsyncOp(asio::system_executor(), std::forward<Handler>(handler))
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto IsCompleted() -> bool { return (fImpl == nullptr) || fImpl->IsCompleted(); }
|
|
||||||
|
|
||||||
auto Complete(std::error_code ec, SignatureArgTypes... args) -> void
|
|
||||||
{
|
|
||||||
if(IsCompleted()) {
|
|
||||||
throw RuntimeError("Async operation already completed");
|
|
||||||
}
|
|
||||||
|
|
||||||
fImpl->Complete(ec, args...);
|
|
||||||
fImpl.reset(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Complete(SignatureArgTypes... args) -> void
|
|
||||||
{
|
|
||||||
Complete(std::error_code(), args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Cancel(SignatureArgTypes... args) -> void
|
|
||||||
{
|
|
||||||
Complete(MakeErrorCode(ErrorCode::OperationCanceled), args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Timeout(SignatureArgTypes... args) -> void
|
|
||||||
{
|
|
||||||
Complete(MakeErrorCode(ErrorCode::OperationTimeout), args...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_ASIOASYNCOP_H */
|
|
|
@ -1,73 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_ASIOBASE_H
|
|
||||||
#define FAIR_MQ_SDK_ASIOBASE_H
|
|
||||||
|
|
||||||
#include <asio/any_io_executor.hpp>
|
|
||||||
#include <fairmq/sdk/Traits.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
using DefaultExecutor = asio::any_io_executor;
|
|
||||||
using DefaultAllocator = std::allocator<int>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class AsioBase AsioBase.h <fairmq/sdk/AsioBase.h>
|
|
||||||
* @tparam Executor Associated I/O executor
|
|
||||||
* @tparam Allocator Associated default allocator
|
|
||||||
* @brief Base for creating Asio-enabled I/O objects
|
|
||||||
*
|
|
||||||
* @par Thread Safety
|
|
||||||
* @e Distinct @e objects: Safe.@n
|
|
||||||
* @e Shared @e objects: Unsafe.
|
|
||||||
*/
|
|
||||||
template<typename Executor, typename Allocator>
|
|
||||||
class AsioBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Member type of associated I/O executor
|
|
||||||
using ExecutorType = Executor;
|
|
||||||
/// Get associated I/O executor
|
|
||||||
auto GetExecutor() const noexcept -> ExecutorType { return fExecutor; }
|
|
||||||
|
|
||||||
/// Member type of associated default allocator
|
|
||||||
using AllocatorType = Allocator;
|
|
||||||
/// Get associated default allocator
|
|
||||||
auto GetAllocator() const noexcept -> AllocatorType { return fAllocator; }
|
|
||||||
|
|
||||||
/// NO default ctor
|
|
||||||
AsioBase() = delete;
|
|
||||||
|
|
||||||
/// Construct with associated I/O executor
|
|
||||||
explicit AsioBase(Executor ex, Allocator alloc)
|
|
||||||
: fExecutor(std::move(ex))
|
|
||||||
, fAllocator(std::move(alloc))
|
|
||||||
{}
|
|
||||||
|
|
||||||
/// NOT copyable
|
|
||||||
AsioBase(const AsioBase&) = delete;
|
|
||||||
AsioBase& operator=(const AsioBase&) = delete;
|
|
||||||
|
|
||||||
/// movable
|
|
||||||
AsioBase(AsioBase&&) noexcept = default;
|
|
||||||
AsioBase& operator=(AsioBase&&) noexcept = default;
|
|
||||||
|
|
||||||
~AsioBase() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ExecutorType fExecutor;
|
|
||||||
AllocatorType fAllocator;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_ASIOBASE_H */
|
|
|
@ -1,117 +0,0 @@
|
||||||
################################################################################
|
|
||||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
|
||||||
# #
|
|
||||||
# This software is distributed under the terms of the #
|
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
|
||||||
# copied verbatim in the file "LICENSE" #
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
if(BUILD_TIDY_TOOL)
|
|
||||||
include(FairMQTidy)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#################
|
|
||||||
# libFairMQ_SDK #
|
|
||||||
#################
|
|
||||||
configure_file(DDSInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/DDSInfo.h @ONLY)
|
|
||||||
|
|
||||||
set(target SDK)
|
|
||||||
|
|
||||||
set(SDK_PUBLIC_HEADER_FILES
|
|
||||||
../SDK.h
|
|
||||||
AsioAsyncOp.h
|
|
||||||
AsioBase.h
|
|
||||||
DDSAgent.h
|
|
||||||
DDSCollection.h
|
|
||||||
DDSEnvironment.h
|
|
||||||
DDSSession.h
|
|
||||||
DDSTask.h
|
|
||||||
DDSTopology.h
|
|
||||||
Error.h
|
|
||||||
Topology.h
|
|
||||||
Traits.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SDK_PRIVATE_HEADER_FILES
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/DDSInfo.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SDK_SOURCE_FILES
|
|
||||||
DDSEnvironment.cxx
|
|
||||||
DDSSession.cxx
|
|
||||||
DDSTopology.cxx
|
|
||||||
Topology.cxx
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(${target}
|
|
||||||
${SDK_SOURCE_FILES}
|
|
||||||
${SDK_PUBLIC_HEADER_FILES} # for IDE integration
|
|
||||||
${SDK_PRIVATE_HEADER_FILES} # for IDE integration
|
|
||||||
)
|
|
||||||
target_compile_features(${target} PUBLIC cxx_std_17)
|
|
||||||
set_target_properties(${target} PROPERTIES LABELS coverage)
|
|
||||||
target_include_directories(${target}
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
|
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
|
||||||
)
|
|
||||||
target_link_libraries(${target}
|
|
||||||
PUBLIC
|
|
||||||
asio::asio
|
|
||||||
Boost::boost
|
|
||||||
Boost::filesystem
|
|
||||||
FairLogger::FairLogger
|
|
||||||
Threads::Threads
|
|
||||||
Tools
|
|
||||||
StateMachine
|
|
||||||
Commands
|
|
||||||
|
|
||||||
PRIVATE
|
|
||||||
DDS::dds_intercom_lib
|
|
||||||
DDS::dds_tools_lib
|
|
||||||
DDS::dds_topology_lib
|
|
||||||
)
|
|
||||||
set_target_properties(${target} PROPERTIES
|
|
||||||
VERSION ${PROJECT_VERSION}
|
|
||||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
|
||||||
OUTPUT_NAME FairMQ_${target}
|
|
||||||
)
|
|
||||||
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
|
|
||||||
fairmq_target_tidy(TARGET ${target})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
###############
|
|
||||||
# executables #
|
|
||||||
###############
|
|
||||||
add_executable(fairmq-dds-command-ui ${CMAKE_CURRENT_SOURCE_DIR}/runDDSCommandUI.cxx)
|
|
||||||
target_link_libraries(fairmq-dds-command-ui
|
|
||||||
FairMQ
|
|
||||||
Commands
|
|
||||||
SDK
|
|
||||||
StateMachine
|
|
||||||
)
|
|
||||||
|
|
||||||
install(
|
|
||||||
TARGETS
|
|
||||||
SDK
|
|
||||||
fairmq-dds-command-ui
|
|
||||||
|
|
||||||
EXPORT ${PROJECT_EXPORT_SET}
|
|
||||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
|
||||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
|
||||||
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
# preserve relative path and prepend fairmq
|
|
||||||
foreach(HEADER IN LISTS SDK_PUBLIC_HEADER_FILES)
|
|
||||||
get_filename_component(_path ${HEADER} DIRECTORY)
|
|
||||||
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/sdk/${_path} _destination)
|
|
||||||
install(FILES ${HEADER}
|
|
||||||
DESTINATION ${_destination}
|
|
||||||
)
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/DDSInfo.h
|
|
||||||
DESTINATION ${PROJECT_INSTALL_INCDIR}/sdk
|
|
||||||
)
|
|
|
@ -1,78 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_DDSSAGENT_H
|
|
||||||
#define FAIR_MQ_SDK_DDSSAGENT_H
|
|
||||||
|
|
||||||
#include <fairmq/sdk/DDSSession.h>
|
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
#include <string>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class DDSAgent <fairmq/sdk/DDSAgent.h>
|
|
||||||
* @brief Represents a DDS agent
|
|
||||||
*/
|
|
||||||
class DDSAgent
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Id = uint64_t;
|
|
||||||
using Pid = uint32_t;
|
|
||||||
|
|
||||||
explicit DDSAgent(DDSSession session,
|
|
||||||
Id id,
|
|
||||||
Pid pid,
|
|
||||||
std::string path,
|
|
||||||
std::string host,
|
|
||||||
std::chrono::milliseconds startupTime,
|
|
||||||
std::string username)
|
|
||||||
: fSession(std::move(session))
|
|
||||||
, fId(id)
|
|
||||||
, fPid(pid)
|
|
||||||
, fDDSPath(std::move(path))
|
|
||||||
, fHost(std::move(host))
|
|
||||||
, fStartupTime(startupTime)
|
|
||||||
, fUsername(std::move(username))
|
|
||||||
{}
|
|
||||||
|
|
||||||
DDSSession GetSession() const { return fSession; }
|
|
||||||
Id GetId() const { return fId; }
|
|
||||||
Pid GetPid() const { return fPid; }
|
|
||||||
std::string GetHost() const { return fHost; }
|
|
||||||
std::string GetDDSPath() const { return fDDSPath; }
|
|
||||||
std::chrono::milliseconds GetStartupTime() const { return fStartupTime; }
|
|
||||||
std::string GetUsername() const { return fUsername; }
|
|
||||||
|
|
||||||
friend auto operator<<(std::ostream& os, const DDSAgent& agent) -> std::ostream&
|
|
||||||
{
|
|
||||||
return os << "DDSAgent id: " << agent.fId
|
|
||||||
<< ", pid: " << agent.fPid
|
|
||||||
<< ", path: " << agent.fDDSPath
|
|
||||||
<< ", host: " << agent.fHost
|
|
||||||
<< ", startupTime: " << agent.fStartupTime.count()
|
|
||||||
<< ", username: " << agent.fUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
DDSSession fSession;
|
|
||||||
Id fId;
|
|
||||||
Pid fPid;
|
|
||||||
std::string fDDSPath;
|
|
||||||
std::string fHost;
|
|
||||||
std::chrono::milliseconds fStartupTime;
|
|
||||||
std::string fUsername;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_DDSSAGENT_H */
|
|
|
@ -1,46 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_DDSCOLLECTION_H
|
|
||||||
#define FAIR_MQ_SDK_DDSCOLLECTION_H
|
|
||||||
|
|
||||||
// #include <fairmq/sdk/DDSAgent.h>
|
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class DDSCollection <fairmq/sdk/DDSCollection.h>
|
|
||||||
* @brief Represents a DDS collection
|
|
||||||
*/
|
|
||||||
class DDSCollection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Id = std::uint64_t;
|
|
||||||
|
|
||||||
explicit DDSCollection(Id id)
|
|
||||||
: fId(id)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Id GetId() const { return fId; }
|
|
||||||
|
|
||||||
friend auto operator<<(std::ostream& os, const DDSCollection& collection) -> std::ostream&
|
|
||||||
{
|
|
||||||
return os << "DDSCollection id: " << collection.fId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Id fId;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_DDSCOLLECTION_H */
|
|
|
@ -1,86 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "DDSEnvironment.h"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <dds/dds.h>
|
|
||||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <fairlogger/Logger.h>
|
|
||||||
#include <fairmq/tools/InstanceLimit.h>
|
|
||||||
#include <fairmq/sdk/DDSInfo.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
struct DDSEnvironment::Impl
|
|
||||||
{
|
|
||||||
explicit Impl(Path configHome)
|
|
||||||
: fLocation(DDSInstallPrefix)
|
|
||||||
, fConfigHome(std::move(configHome))
|
|
||||||
{
|
|
||||||
SetupPath();
|
|
||||||
SetupConfigHome();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SetupConfigHome() -> void
|
|
||||||
{
|
|
||||||
if (fConfigHome.empty()) {
|
|
||||||
fConfigHome = GetEnv("HOME");
|
|
||||||
} else {
|
|
||||||
setenv("HOME", fConfigHome.c_str(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SetupPath() -> void
|
|
||||||
{
|
|
||||||
std::string path(GetEnv("PATH"));
|
|
||||||
Path ddsExecDir = (fLocation == DDSInstallPrefix) ? DDSExecutableDir : fLocation / Path("bin");
|
|
||||||
path = ddsExecDir.string() + std::string(":") + path;
|
|
||||||
setenv("PATH", path.c_str(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto GetEnv(const std::string& key) const -> std::string
|
|
||||||
{
|
|
||||||
auto value = std::getenv(key.c_str());
|
|
||||||
if (value) {
|
|
||||||
return {value};
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Tag {};
|
|
||||||
friend auto operator<<(std::ostream& os, Tag) -> std::ostream& { return os << "DDSEnvironment"; }
|
|
||||||
tools::InstanceLimiter<Tag, 1> fCount;
|
|
||||||
|
|
||||||
Path fLocation;
|
|
||||||
Path fConfigHome;
|
|
||||||
};
|
|
||||||
|
|
||||||
DDSEnvironment::DDSEnvironment()
|
|
||||||
: DDSEnvironment(Path())
|
|
||||||
{}
|
|
||||||
|
|
||||||
DDSEnvironment::DDSEnvironment(Path configHome)
|
|
||||||
: fImpl(std::make_shared<Impl>(std::move(configHome)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto DDSEnvironment::GetLocation() const -> Path { return fImpl->fLocation; }
|
|
||||||
|
|
||||||
auto DDSEnvironment::GetConfigHome() const -> Path { return fImpl->fConfigHome; }
|
|
||||||
|
|
||||||
auto operator<<(std::ostream& os, DDSEnvironment env) -> std::ostream&
|
|
||||||
{
|
|
||||||
return os << "$DDS_LOCATION: " << env.GetLocation() << ", "
|
|
||||||
<< "$DDS_CONFIG_HOME: " << env.GetConfigHome() / DDSEnvironment::Path(".DDS");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
|
@ -1,44 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_DDSENVIRONMENT_H
|
|
||||||
#define FAIR_MQ_SDK_DDSENVIRONMENT_H
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class DDSEnvironment DDSSession.h <fairmq/sdk/DDSSession.h>
|
|
||||||
* @brief Sets up the DDS environment (object helper)
|
|
||||||
*/
|
|
||||||
class DDSEnvironment
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Path = boost::filesystem::path;
|
|
||||||
|
|
||||||
DDSEnvironment();
|
|
||||||
explicit DDSEnvironment(Path);
|
|
||||||
|
|
||||||
auto GetLocation() const -> Path;
|
|
||||||
auto GetConfigHome() const -> Path;
|
|
||||||
|
|
||||||
friend auto operator<<(std::ostream& os, DDSEnvironment env) -> std::ostream&;
|
|
||||||
private:
|
|
||||||
struct Impl;
|
|
||||||
std::shared_ptr<Impl> fImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
using DDSEnv = DDSEnvironment;
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_DDSENVIRONMENT_H */
|
|
|
@ -1,29 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_DDSINFO_H
|
|
||||||
#define FAIR_MQ_SDK_DDSINFO_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace dds::tools_api { class CSession; }
|
|
||||||
namespace dds::topology_api { class CTopology; }
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
const std::string DDSVersion("@DDS_VERSION@");
|
|
||||||
const std::string DDSInstallPrefix("@DDS_INSTALL_PREFIX@");
|
|
||||||
const std::string DDSExecutableDir("@DDS_BINDIR@");
|
|
||||||
const std::string DDSIncludeDir("@DDS_INCDIR@");
|
|
||||||
const std::string DDSLibraryDir("@DDS_LIBDIR@");
|
|
||||||
const std::string DDSPluginDir("@DDS_PLUGINDIR@");
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_DDSINFO_H */
|
|
|
@ -1,389 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "DDSSession.h"
|
|
||||||
|
|
||||||
#include <boost/process.hpp>
|
|
||||||
#include <boost/uuid/uuid_io.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstdlib>
|
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <dds/dds.h>
|
|
||||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <fairlogger/Logger.h>
|
|
||||||
#include <fairmq/sdk/DDSAgent.h>
|
|
||||||
#include <fairmq/sdk/DDSEnvironment.h>
|
|
||||||
#include <fairmq/sdk/DDSTopology.h>
|
|
||||||
#include <fairmq/tools/Semaphore.h>
|
|
||||||
#include <fairmq/tools/Strings.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include <sstream>
|
|
||||||
#include <thread>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
auto operator<<(std::ostream& os, DDSRMSPlugin plugin) -> std::ostream&
|
|
||||||
{
|
|
||||||
switch (plugin) {
|
|
||||||
case DDSRMSPlugin::ssh:
|
|
||||||
return os << "ssh";
|
|
||||||
case DDSRMSPlugin::localhost:
|
|
||||||
return os << "localhost";
|
|
||||||
default:
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator>>(std::istream& is, DDSRMSPlugin& plugin) -> std::istream&
|
|
||||||
{
|
|
||||||
std::string value;
|
|
||||||
if (is >> value) {
|
|
||||||
if (value == "ssh") {
|
|
||||||
plugin = DDSRMSPlugin::ssh;
|
|
||||||
} else if (value == "localhost") {
|
|
||||||
plugin = DDSRMSPlugin::localhost;
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Unknown or unsupported DDSRMSPlugin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return is;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DDSSession::Impl
|
|
||||||
{
|
|
||||||
explicit Impl(DDSEnvironment env)
|
|
||||||
: fEnv(std::move(env))
|
|
||||||
, fRMSPlugin(DDSRMSPlugin::localhost)
|
|
||||||
, fSession(std::make_shared<dds::tools_api::CSession>())
|
|
||||||
, fDDSCustomCmd(fDDSService)
|
|
||||||
, fId(to_string(fSession->create()))
|
|
||||||
, fStopOnDestruction(false)
|
|
||||||
{
|
|
||||||
fDDSService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& msg) {
|
|
||||||
std::cerr << "DDS error, error code: " << errorCode << ", error message: " << msg << std::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit Impl(Id existing, DDSEnvironment env)
|
|
||||||
: fEnv(std::move(env))
|
|
||||||
, fRMSPlugin(DDSRMSPlugin::localhost)
|
|
||||||
, fSession(std::make_shared<dds::tools_api::CSession>())
|
|
||||||
, fDDSCustomCmd(fDDSService)
|
|
||||||
, fId(std::move(existing))
|
|
||||||
, fStopOnDestruction(false)
|
|
||||||
{
|
|
||||||
fSession->attach(fId);
|
|
||||||
|
|
||||||
fDDSService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& msg) {
|
|
||||||
std::cerr << "DDS error, error code: " << errorCode << ", error message: " << msg << std::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit Impl(std::shared_ptr<dds::tools_api::CSession> nativeSession, DDSEnv env)
|
|
||||||
: fEnv(std::move(env))
|
|
||||||
, fRMSPlugin(DDSRMSPlugin::localhost)
|
|
||||||
, fSession(std::move(nativeSession))
|
|
||||||
, fDDSCustomCmd(fDDSService)
|
|
||||||
, fId(to_string(fSession->getSessionID()))
|
|
||||||
, fStopOnDestruction(false)
|
|
||||||
{
|
|
||||||
// Sanity check
|
|
||||||
if (!fSession->IsRunning()) {
|
|
||||||
throw std::runtime_error("Given CSession must be running");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Impl()
|
|
||||||
{
|
|
||||||
if (fStopOnDestruction) {
|
|
||||||
fSession->shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Impl() = delete;
|
|
||||||
Impl(const Impl&) = delete;
|
|
||||||
Impl& operator=(const Impl&) = delete;
|
|
||||||
Impl(Impl&&) = delete;
|
|
||||||
Impl& operator=(Impl&&) = delete;
|
|
||||||
|
|
||||||
DDSEnvironment fEnv;
|
|
||||||
DDSRMSPlugin fRMSPlugin;
|
|
||||||
Path fRMSConfig;
|
|
||||||
std::shared_ptr<dds::tools_api::CSession> fSession;
|
|
||||||
dds::intercom_api::CIntercomService fDDSService;
|
|
||||||
dds::intercom_api::CCustomCmd fDDSCustomCmd;
|
|
||||||
Id fId;
|
|
||||||
bool fStopOnDestruction;
|
|
||||||
};
|
|
||||||
|
|
||||||
DDSSession::DDSSession(DDSEnvironment env)
|
|
||||||
: fImpl(std::make_shared<Impl>(std::move(env)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
DDSSession::DDSSession(Id existing, DDSEnvironment env)
|
|
||||||
: fImpl(std::make_shared<Impl>(std::move(existing), std::move(env)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
DDSSession::DDSSession(std::shared_ptr<dds::tools_api::CSession> nativeSession, DDSEnv env)
|
|
||||||
: fImpl(std::make_shared<Impl>(std::move(nativeSession), std::move(env)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto DDSSession::GetEnv() const -> DDSEnvironment { return fImpl->fEnv; }
|
|
||||||
|
|
||||||
auto DDSSession::IsRunning() const -> bool { return fImpl->fSession->IsRunning(); }
|
|
||||||
|
|
||||||
auto DDSSession::GetId() const -> Id { return fImpl->fId; }
|
|
||||||
|
|
||||||
auto DDSSession::Stop() -> void { return fImpl->fSession->shutdown(); }
|
|
||||||
|
|
||||||
auto DDSSession::GetRMSPlugin() const -> DDSRMSPlugin { return fImpl->fRMSPlugin; }
|
|
||||||
|
|
||||||
auto DDSSession::SetRMSPlugin(DDSRMSPlugin plugin) -> void { fImpl->fRMSPlugin = plugin; }
|
|
||||||
|
|
||||||
auto DDSSession::GetRMSConfig() const -> Path { return fImpl->fRMSConfig; }
|
|
||||||
|
|
||||||
auto DDSSession::SetRMSConfig(Path configFile) const -> void
|
|
||||||
{
|
|
||||||
fImpl->fRMSConfig = std::move(configFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::IsStoppedOnDestruction() const -> bool { return fImpl->fStopOnDestruction; }
|
|
||||||
|
|
||||||
auto DDSSession::StopOnDestruction(bool stop) -> void { fImpl->fStopOnDestruction = stop; }
|
|
||||||
|
|
||||||
auto DDSSession::SubmitAgents(Quantity agents) -> void
|
|
||||||
{
|
|
||||||
// Requesting to submit 0 agents is not meaningful
|
|
||||||
assert(agents > 0);
|
|
||||||
|
|
||||||
using namespace dds::tools_api;
|
|
||||||
|
|
||||||
SSubmitRequestData submitInfo;
|
|
||||||
submitInfo.m_rms = tools::ToString(GetRMSPlugin());
|
|
||||||
submitInfo.m_instances = 1;
|
|
||||||
submitInfo.m_slots = agents; // TODO new api: get slots from agents
|
|
||||||
submitInfo.m_config = GetRMSConfig().string();
|
|
||||||
|
|
||||||
tools::SharedSemaphore blocker;
|
|
||||||
auto submitRequest = SSubmitRequest::makeRequest(submitInfo);
|
|
||||||
submitRequest->setMessageCallback([](const SMessageResponseData& message){
|
|
||||||
LOG(debug) << message.m_msg;
|
|
||||||
});
|
|
||||||
submitRequest->setDoneCallback([agents, blocker]() mutable {
|
|
||||||
LOG(debug) << agents << " Agents submitted";
|
|
||||||
blocker.Signal();
|
|
||||||
});
|
|
||||||
|
|
||||||
fImpl->fSession->sendRequest<SSubmitRequest>(submitRequest);
|
|
||||||
blocker.Wait();
|
|
||||||
|
|
||||||
WaitForIdleAgents(agents);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::RequestAgentCount() -> AgentCount
|
|
||||||
{
|
|
||||||
using namespace dds::tools_api;
|
|
||||||
|
|
||||||
SAgentCountRequest::response_t res;
|
|
||||||
fImpl->fSession->syncSendRequest<SAgentCountRequest>(SAgentCountRequest::request_t(), res);
|
|
||||||
|
|
||||||
AgentCount count;
|
|
||||||
count.active = res.m_activeSlotsCount;
|
|
||||||
count.idle = res.m_idleSlotsCount;
|
|
||||||
count.executing = res.m_executingSlotsCount;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::RequestAgentInfo() -> std::vector<DDSAgent>
|
|
||||||
{
|
|
||||||
using namespace dds::tools_api;
|
|
||||||
|
|
||||||
SAgentInfoRequest::responseVector_t res;
|
|
||||||
fImpl->fSession->syncSendRequest<SAgentInfoRequest>(SAgentInfoRequest::request_t(), res);
|
|
||||||
|
|
||||||
std::vector<DDSAgent> agentInfo;
|
|
||||||
agentInfo.reserve(res.size());
|
|
||||||
for (const auto& a : res) {
|
|
||||||
agentInfo.emplace_back(
|
|
||||||
*this,
|
|
||||||
a.m_agentID,
|
|
||||||
a.m_agentPid,
|
|
||||||
a.m_DDSPath,
|
|
||||||
a.m_host,
|
|
||||||
a.m_startUpTime,
|
|
||||||
a.m_username
|
|
||||||
// a.m_nSlots
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return agentInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::RequestTaskInfo() -> std::vector<DDSTask>
|
|
||||||
{
|
|
||||||
using namespace dds::tools_api;
|
|
||||||
|
|
||||||
SAgentInfoRequest::responseVector_t res;
|
|
||||||
fImpl->fSession->syncSendRequest<SAgentInfoRequest>(SAgentInfoRequest::request_t(), res);
|
|
||||||
|
|
||||||
std::vector<DDSTask> taskInfo;
|
|
||||||
taskInfo.reserve(res.size());
|
|
||||||
for (auto& a : res) {
|
|
||||||
//taskInfo.emplace_back(a.m_taskID, 0);
|
|
||||||
(void)a;
|
|
||||||
taskInfo.emplace_back(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return taskInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::RequestCommanderInfo() -> CommanderInfo
|
|
||||||
{
|
|
||||||
using namespace dds::tools_api;
|
|
||||||
|
|
||||||
SCommanderInfoRequestData commanderInfo;
|
|
||||||
tools::SharedSemaphore blocker;
|
|
||||||
std::string error;
|
|
||||||
auto commanderInfoRequest = SCommanderInfoRequest::makeRequest(commanderInfo);
|
|
||||||
CommanderInfo info;
|
|
||||||
commanderInfoRequest->setResponseCallback([&info](const SCommanderInfoResponseData& _response) {
|
|
||||||
info.pid = _response.m_pid;
|
|
||||||
info.activeTopologyName = _response.m_activeTopologyName;
|
|
||||||
});
|
|
||||||
commanderInfoRequest->setMessageCallback([&](const SMessageResponseData& _message) {
|
|
||||||
if (_message.m_severity == dds::intercom_api::EMsgSeverity::error) {
|
|
||||||
error = _message.m_msg;
|
|
||||||
blocker.Signal();
|
|
||||||
} else {
|
|
||||||
LOG(debug) << _message.m_msg;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
commanderInfoRequest->setDoneCallback([blocker]() mutable { blocker.Signal(); });
|
|
||||||
fImpl->fSession->sendRequest<SCommanderInfoRequest>(commanderInfoRequest);
|
|
||||||
blocker.Wait();
|
|
||||||
|
|
||||||
if (!error.empty()) {
|
|
||||||
throw std::runtime_error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::WaitForExecutingAgents(Quantity minCount) -> void
|
|
||||||
{
|
|
||||||
auto count(RequestAgentCount());
|
|
||||||
int interval(8);
|
|
||||||
while (count.executing < minCount) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
|
|
||||||
interval = std::min(256, interval * 2);
|
|
||||||
count = RequestAgentCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::WaitForIdleAgents(Quantity minCount) -> void
|
|
||||||
{
|
|
||||||
auto count(RequestAgentCount());
|
|
||||||
int interval(8);
|
|
||||||
while (count.idle < minCount) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
|
|
||||||
interval = std::min(256, interval * 2);
|
|
||||||
count = RequestAgentCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::ActivateTopology(DDSTopology topo) -> void
|
|
||||||
{
|
|
||||||
using namespace dds::tools_api;
|
|
||||||
|
|
||||||
STopologyRequestData topologyInfo;
|
|
||||||
topologyInfo.m_updateType = STopologyRequestData::EUpdateType::ACTIVATE;
|
|
||||||
topologyInfo.m_topologyFile = topo.GetTopoFile().string();
|
|
||||||
|
|
||||||
tools::SharedSemaphore blocker;
|
|
||||||
auto topologyRequest = STopologyRequest::makeRequest(topologyInfo);
|
|
||||||
topologyRequest->setMessageCallback([](const SMessageResponseData& _message) {
|
|
||||||
LOG(debug) << _message.m_msg;
|
|
||||||
});
|
|
||||||
topologyRequest->setDoneCallback([blocker]() mutable { blocker.Signal(); });
|
|
||||||
fImpl->fSession->sendRequest<STopologyRequest>(topologyRequest);
|
|
||||||
blocker.Wait();
|
|
||||||
|
|
||||||
WaitForExecutingAgents(topo.GetNumRequiredAgents());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::ActivateTopology(const Path& topoFile) -> void
|
|
||||||
{
|
|
||||||
ActivateTopology(DDSTopology(topoFile, GetEnv()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DDSSession::StartDDSService() { fImpl->fDDSService.start(fImpl->fId); }
|
|
||||||
|
|
||||||
void DDSSession::SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)> cb)
|
|
||||||
{
|
|
||||||
fImpl->fDDSCustomCmd.subscribe(cb);
|
|
||||||
// fImpl->fDDSCustomCmd.subscribeOnReply([](const std::string& reply) {
|
|
||||||
// LOG(debug) << reply;
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
void DDSSession::UnsubscribeFromCommands()
|
|
||||||
{
|
|
||||||
fImpl->fDDSCustomCmd.unsubscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DDSSession::SendCommand(const std::string& cmd, const std::string& path /* = "" */) { fImpl->fDDSCustomCmd.send(cmd, path); }
|
|
||||||
|
|
||||||
void DDSSession::SendCommand(const std::string& cmd, DDSChannel::Id recipient)
|
|
||||||
{
|
|
||||||
fImpl->fDDSCustomCmd.send(cmd, std::to_string(recipient));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&
|
|
||||||
{
|
|
||||||
return os << "$DDS_SESSION_ID: " << session.GetId();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto getMostRecentRunningDDSSession(DDSEnv env) -> DDSSession
|
|
||||||
{
|
|
||||||
boost::process::ipstream pipeStream;
|
|
||||||
boost::process::child c("dds-session list all", boost::process::std_out > pipeStream);
|
|
||||||
std::string lastLine;
|
|
||||||
std::string currentLine;
|
|
||||||
|
|
||||||
while (pipeStream && std::getline(pipeStream, currentLine) && !currentLine.empty()) {
|
|
||||||
lastLine = currentLine;
|
|
||||||
}
|
|
||||||
c.wait();
|
|
||||||
std::string sessionId;
|
|
||||||
|
|
||||||
if (!lastLine.empty()) {
|
|
||||||
std::vector<std::string> words;
|
|
||||||
std::istringstream iss(lastLine);
|
|
||||||
for (std::string s; iss >> s;) {
|
|
||||||
if (s != "*") {
|
|
||||||
words.push_back(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (words.back() == "RUNNING") {
|
|
||||||
sessionId = words.front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionId.empty()) {
|
|
||||||
throw std::runtime_error("could not find most recent DDS session");
|
|
||||||
}
|
|
||||||
|
|
||||||
return DDSSession(DDSSession::Id(sessionId), std::move(env));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
|
@ -1,118 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_DDSSESSION_H
|
|
||||||
#define FAIR_MQ_SDK_DDSSESSION_H
|
|
||||||
|
|
||||||
#include <fairmq/sdk/DDSEnvironment.h>
|
|
||||||
#include <fairmq/sdk/DDSInfo.h>
|
|
||||||
#include <fairmq/sdk/DDSTask.h>
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <istream>
|
|
||||||
#include <memory>
|
|
||||||
#include <ostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <functional>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @enum DDSRMSPlugin DDSSession.h <fairmq/sdk/DDSSession.h>
|
|
||||||
* @brief Supported DDS resource management system plugins
|
|
||||||
*/
|
|
||||||
enum class DDSRMSPlugin
|
|
||||||
{
|
|
||||||
localhost,
|
|
||||||
ssh
|
|
||||||
};
|
|
||||||
auto operator<<(std::ostream& os, DDSRMSPlugin plugin) -> std::ostream&;
|
|
||||||
auto operator>>(std::istream& is, DDSRMSPlugin& plugin) -> std::istream&;
|
|
||||||
|
|
||||||
class DDSTopology;
|
|
||||||
class DDSAgent;
|
|
||||||
|
|
||||||
class DDSChannel
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Id = std::uint64_t;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class DDSSession DDSSession.h <fairmq/sdk/DDSSession.h>
|
|
||||||
* @brief Represents a DDS session
|
|
||||||
*/
|
|
||||||
class DDSSession
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Id = std::string;
|
|
||||||
using Quantity = std::uint32_t;
|
|
||||||
using Path = boost::filesystem::path;
|
|
||||||
|
|
||||||
explicit DDSSession(DDSEnvironment env = DDSEnvironment());
|
|
||||||
explicit DDSSession(Id existing, DDSEnvironment env = DDSEnvironment());
|
|
||||||
|
|
||||||
/// @brief Construct with already existing native DDS API objects
|
|
||||||
/// @param nativeSession Existing and initialized CSession (either via create() or attach())
|
|
||||||
/// @param env Optional DDSEnv
|
|
||||||
explicit DDSSession(std::shared_ptr<dds::tools_api::CSession> nativeSession, DDSEnv env = {});
|
|
||||||
|
|
||||||
auto GetEnv() const -> DDSEnvironment;
|
|
||||||
auto GetId() const -> Id;
|
|
||||||
auto GetRMSPlugin() const -> DDSRMSPlugin;
|
|
||||||
auto SetRMSPlugin(DDSRMSPlugin) -> void;
|
|
||||||
auto GetRMSConfig() const -> Path;
|
|
||||||
auto SetRMSConfig(Path) const -> void;
|
|
||||||
auto IsStoppedOnDestruction() const -> bool;
|
|
||||||
auto StopOnDestruction(bool stop = true) -> void;
|
|
||||||
auto IsRunning() const -> bool;
|
|
||||||
auto SubmitAgents(Quantity agents) -> void;
|
|
||||||
struct AgentCount {
|
|
||||||
Quantity idle = 0;
|
|
||||||
Quantity active = 0;
|
|
||||||
Quantity executing = 0;
|
|
||||||
};
|
|
||||||
auto RequestAgentCount() -> AgentCount;
|
|
||||||
auto RequestAgentInfo() -> std::vector<DDSAgent>;
|
|
||||||
auto RequestTaskInfo() -> std::vector<DDSTask>;
|
|
||||||
struct CommanderInfo {
|
|
||||||
int pid = -1;
|
|
||||||
std::string activeTopologyName;
|
|
||||||
};
|
|
||||||
auto RequestCommanderInfo() -> CommanderInfo;
|
|
||||||
auto WaitForIdleAgents(Quantity) -> void;
|
|
||||||
auto WaitForOnlyIdleAgents() -> void;
|
|
||||||
auto WaitForExecutingAgents(Quantity) -> void;
|
|
||||||
auto ActivateTopology(const Path& topoFile) -> void;
|
|
||||||
auto ActivateTopology(DDSTopology) -> void;
|
|
||||||
auto Stop() -> void;
|
|
||||||
|
|
||||||
void StartDDSService();
|
|
||||||
void SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)>);
|
|
||||||
void UnsubscribeFromCommands();
|
|
||||||
void SendCommand(const std::string&, const std::string& = "");
|
|
||||||
void SendCommand(const std::string&, DDSChannel::Id);
|
|
||||||
auto GetTaskId(DDSChannel::Id) const -> DDSTask::Id;
|
|
||||||
|
|
||||||
friend auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Impl;
|
|
||||||
std::shared_ptr<Impl> fImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto getMostRecentRunningDDSSession(DDSEnv env = {}) -> DDSSession;
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_DDSSESSION_H */
|
|
|
@ -1,49 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_DDSTASK_H
|
|
||||||
#define FAIR_MQ_SDK_DDSTASK_H
|
|
||||||
|
|
||||||
#include <fairmq/sdk/DDSCollection.h>
|
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class DDSTask <fairmq/sdk/DDSTask.h>
|
|
||||||
* @brief Represents a DDS task
|
|
||||||
*/
|
|
||||||
class DDSTask
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Id = std::uint64_t;
|
|
||||||
|
|
||||||
explicit DDSTask(Id id, Id collectionId)
|
|
||||||
: fId(id)
|
|
||||||
, fCollectionId(collectionId)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Id GetId() const { return fId; }
|
|
||||||
DDSCollection::Id GetCollectionId() const { return fCollectionId; }
|
|
||||||
|
|
||||||
friend auto operator<<(std::ostream& os, const DDSTask& task) -> std::ostream&
|
|
||||||
{
|
|
||||||
return os << "DDSTask id: " << task.fId << ", collection id: " << task.fCollectionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Id fId;
|
|
||||||
DDSCollection::Id fCollectionId;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_DDSTASK_H */
|
|
|
@ -1,116 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "DDSTopology.h"
|
|
||||||
|
|
||||||
#include <boost/range/iterator_range.hpp>
|
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <dds/dds.h>
|
|
||||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <fairlogger/Logger.h>
|
|
||||||
#include <fairmq/sdk/DDSEnvironment.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <sstream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
struct DDSTopology::Impl
|
|
||||||
{
|
|
||||||
explicit Impl(Path topoFile, DDSEnvironment env)
|
|
||||||
: fEnv(std::move(env))
|
|
||||||
, fTopoFile(std::move(topoFile))
|
|
||||||
, fTopo(fTopoFile.string())
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit Impl(dds::topology_api::CTopology nativeTopology, DDSEnvironment env)
|
|
||||||
: fEnv(std::move(env))
|
|
||||||
, fTopo(std::move(nativeTopology))
|
|
||||||
{}
|
|
||||||
|
|
||||||
DDSEnvironment fEnv;
|
|
||||||
Path fTopoFile;
|
|
||||||
dds::topology_api::CTopology fTopo;
|
|
||||||
};
|
|
||||||
|
|
||||||
DDSTopology::DDSTopology(Path topoFile, DDSEnvironment env)
|
|
||||||
: fImpl(std::make_shared<Impl>(std::move(topoFile), std::move(env)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
DDSTopology::DDSTopology(dds::topology_api::CTopology nativeTopology, DDSEnv env)
|
|
||||||
: fImpl(std::make_shared<Impl>(std::move(nativeTopology), std::move(env)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto DDSTopology::GetEnv() const -> DDSEnvironment { return fImpl->fEnv; }
|
|
||||||
|
|
||||||
auto DDSTopology::GetTopoFile() const -> Path
|
|
||||||
{
|
|
||||||
auto file(fImpl->fTopoFile);
|
|
||||||
if (file.string().empty()) {
|
|
||||||
throw std::runtime_error("DDS topology xml spec file unknown");
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSTopology::GetNumRequiredAgents() const -> std::size_t
|
|
||||||
{
|
|
||||||
return fImpl->fTopo.getRequiredNofAgents();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSTopology::GetTasks(const std::string& path /* = "" */) const -> std::vector<DDSTask>
|
|
||||||
{
|
|
||||||
std::vector<DDSTask> list;
|
|
||||||
|
|
||||||
dds::topology_api::STopoRuntimeTask::FilterIteratorPair_t itPair;
|
|
||||||
if (path.empty()) {
|
|
||||||
itPair = fImpl->fTopo.getRuntimeTaskIterator(nullptr); // passing nullptr will get all tasks
|
|
||||||
} else {
|
|
||||||
itPair = fImpl->fTopo.getRuntimeTaskIteratorMatchingPath(path);
|
|
||||||
}
|
|
||||||
auto tasks = boost::make_iterator_range(itPair.first, itPair.second);
|
|
||||||
|
|
||||||
for (const auto& task : tasks) {
|
|
||||||
// LOG(debug) << "Found task with id: " << task.first << ", "
|
|
||||||
// << "Path: " << task.second.m_taskPath << ", "
|
|
||||||
// << "Collection id: " << task.second.m_taskCollectionId << ", "
|
|
||||||
// << "Name: " << task.second.m_task->getName() << "_" << task.second.m_taskIndex;
|
|
||||||
list.emplace_back(task.first, task.second.m_taskCollectionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSTopology::GetCollections() const -> std::vector<DDSCollection>
|
|
||||||
{
|
|
||||||
std::vector<DDSCollection> list;
|
|
||||||
|
|
||||||
auto itPair = fImpl->fTopo.getRuntimeCollectionIterator(nullptr); // passing nullptr will get all collections
|
|
||||||
auto collections = boost::make_iterator_range(itPair.first, itPair.second);
|
|
||||||
|
|
||||||
for (const auto& c : collections) {
|
|
||||||
LOG(debug) << "Found collection with id: " << c.first << ", "
|
|
||||||
<< "Index: " << c.second.m_collectionIndex << ", "
|
|
||||||
<< "Path: " << c.second.m_collectionPath;
|
|
||||||
list.emplace_back(c.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSTopology::GetName() const -> std::string { return fImpl->fTopo.getName(); }
|
|
||||||
|
|
||||||
auto operator<<(std::ostream& os, const DDSTopology& t) -> std::ostream&
|
|
||||||
try {
|
|
||||||
return os << "DDS topology: " << t.GetName() << " (loaded from " << t.GetTopoFile() << ")";
|
|
||||||
} catch (std::runtime_error&) {
|
|
||||||
return os << "DDS topology: " << t.GetName();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
|
@ -1,75 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_DDSTOPOLOGY_H
|
|
||||||
#define FAIR_MQ_SDK_DDSTOPOLOGY_H
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <fairmq/sdk/DDSCollection.h>
|
|
||||||
#include <fairmq/sdk/DDSEnvironment.h>
|
|
||||||
#include <fairmq/sdk/DDSInfo.h>
|
|
||||||
#include <fairmq/sdk/DDSTask.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class DDSTopology DDSTopology.h <fairmq/sdk/DDSTopology.h>
|
|
||||||
* @brief Represents a DDS topology
|
|
||||||
*/
|
|
||||||
class DDSTopology
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Path = boost::filesystem::path;
|
|
||||||
|
|
||||||
DDSTopology() = delete;
|
|
||||||
|
|
||||||
/// @brief Construct from file
|
|
||||||
/// @param topoFile DDS topology xml file
|
|
||||||
/// @param env DDS environment
|
|
||||||
explicit DDSTopology(Path topoFile, DDSEnvironment env = DDSEnvironment());
|
|
||||||
|
|
||||||
/// @brief Construct with already existing native DDS API objects
|
|
||||||
/// @param nativeTopology Existing and initialized CTopology
|
|
||||||
/// @param env Optional DDSEnv
|
|
||||||
explicit DDSTopology(dds::topology_api::CTopology nativeTopology, DDSEnv env = {});
|
|
||||||
|
|
||||||
/// @brief Get associated DDS environment
|
|
||||||
auto GetEnv() const -> DDSEnvironment;
|
|
||||||
|
|
||||||
/// @brief Get path to DDS topology xml, if it is known
|
|
||||||
/// @throw std::runtime_error
|
|
||||||
auto GetTopoFile() const -> Path;
|
|
||||||
|
|
||||||
/// @brief Get number of required agents for this topology
|
|
||||||
auto GetNumRequiredAgents() const -> std::size_t;
|
|
||||||
|
|
||||||
/// @brief Get list of tasks in this topology, optionally matching provided path
|
|
||||||
auto GetTasks(const std::string& = "") const -> std::vector<DDSTask>;
|
|
||||||
|
|
||||||
/// @brief Get list of tasks in this topology
|
|
||||||
auto GetCollections() const -> std::vector<DDSCollection>;
|
|
||||||
|
|
||||||
/// @brief Get the name of the topology
|
|
||||||
auto GetName() const -> std::string;
|
|
||||||
|
|
||||||
friend auto operator<<(std::ostream&, const DDSTopology&) -> std::ostream&;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Impl;
|
|
||||||
std::shared_ptr<Impl> fImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
using DDSTopo = DDSTopology;
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_DDSTOPOLOGY_H */
|
|
|
@ -1,20 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_ERROR_H
|
|
||||||
#define FAIR_MQ_SDK_ERROR_H
|
|
||||||
|
|
||||||
#include <fairmq/Error.h>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk {
|
|
||||||
|
|
||||||
using RuntimeError = fair::mq::RuntimeError;
|
|
||||||
|
|
||||||
} /* namespace fair::mq::sdk */
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_ERROR_H */
|
|
|
@ -1,31 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "Topology.h"
|
|
||||||
|
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <dds/dds.h>
|
|
||||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
|
|
||||||
/// @brief Helper to (Re)Construct a FairMQ topology based on already existing native DDS API objects
|
|
||||||
/// @param nativeSession Existing and initialized CSession (either via create() or attach())
|
|
||||||
/// @param nativeTopo Existing CTopology that is activated on the given nativeSession
|
|
||||||
/// @param env Optional DDSEnv (needed primarily for unit testing)
|
|
||||||
/// @param blockUntilConnected if true, ctor will wait for all tasks to confirm subscriptions
|
|
||||||
auto MakeTopology(dds::topology_api::CTopology nativeTopo,
|
|
||||||
std::shared_ptr<dds::tools_api::CSession> nativeSession,
|
|
||||||
DDSEnv env,
|
|
||||||
bool blockUntilConnected) -> Topology
|
|
||||||
{
|
|
||||||
return {DDSTopo(std::move(nativeTopo), env), DDSSession(std::move(nativeSession), env), blockUntilConnected};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,48 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_TRAITS_H
|
|
||||||
#define FAIR_MQ_SDK_TRAITS_H
|
|
||||||
|
|
||||||
#include <asio/associated_allocator.hpp>
|
|
||||||
#include <asio/associated_executor.hpp>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace asio::detail {
|
|
||||||
|
|
||||||
/// Specialize to match our coding conventions
|
|
||||||
template<typename T, typename Executor>
|
|
||||||
struct associated_executor_impl<T,
|
|
||||||
Executor,
|
|
||||||
std::enable_if_t<is_executor<typename T::ExecutorType>::value>>
|
|
||||||
{
|
|
||||||
using type = typename T::ExecutorType;
|
|
||||||
|
|
||||||
static auto get(const T& obj, const Executor& /*ex = Executor()*/) noexcept -> type
|
|
||||||
{
|
|
||||||
return obj.GetExecutor();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Specialize to match our coding conventions
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
struct associated_allocator_impl<T,
|
|
||||||
Allocator,
|
|
||||||
std::enable_if_t<T::AllocatorType>>
|
|
||||||
{
|
|
||||||
using type = typename T::AllocatorType;
|
|
||||||
|
|
||||||
static auto get(const T& obj, const Allocator& /*alloc = Allocator()*/) noexcept -> type
|
|
||||||
{
|
|
||||||
return obj.GetAllocator();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* namespace asio::detail */
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_TRAITS_H */
|
|
|
@ -1,60 +0,0 @@
|
||||||
################################################################################
|
|
||||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
|
||||||
# #
|
|
||||||
# This software is distributed under the terms of the #
|
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
|
||||||
# copied verbatim in the file "LICENSE" #
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
set(target Commands)
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h
|
|
||||||
COMMAND $<TARGET_FILE:flatbuffers::flatc> -c -o ${CMAKE_CURRENT_BINARY_DIR} CommandsFormat.fbs
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat_generated.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
# JSON serialization needs to see the .fbs file at run time, save it as constexpr string instead of locating/opening it every time
|
|
||||||
file(STRINGS CommandsFormat.fbs tmp)
|
|
||||||
list(JOIN tmp "\n" commands_format_def_fbs)
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CommandsFormatDef.h.in ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormatDef.h)
|
|
||||||
|
|
||||||
add_library(${target} Commands.cxx Commands.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormatDef.h)
|
|
||||||
add_library(FairMQ::${target} ALIAS ${target})
|
|
||||||
|
|
||||||
set(_flatbuffers flatbuffers::flatbuffers_shared)
|
|
||||||
if(NOT TARGET flatbuffers::flatbuffers_shared AND TARGET flatbuffers::flatbuffers)
|
|
||||||
set(_flatbuffers flatbuffers::flatbuffers)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(${target}
|
|
||||||
PUBLIC
|
|
||||||
StateMachine
|
|
||||||
Tools
|
|
||||||
|
|
||||||
PRIVATE
|
|
||||||
${_flatbuffers}
|
|
||||||
)
|
|
||||||
target_compile_features(${target} PUBLIC cxx_std_17)
|
|
||||||
set_target_properties(${target} PROPERTIES
|
|
||||||
VERSION ${PROJECT_VERSION}
|
|
||||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
|
||||||
OUTPUT_NAME FairMQ${target}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(${target}
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
|
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
|
||||||
)
|
|
||||||
|
|
||||||
install(
|
|
||||||
TARGETS ${target}
|
|
||||||
EXPORT ${PROJECT_EXPORT_SET}
|
|
||||||
DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
install(FILES Commands.h
|
|
||||||
DESTINATION ${PROJECT_INSTALL_INCDIR}/sdk/commands
|
|
||||||
)
|
|
|
@ -1,479 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "Commands.h"
|
|
||||||
|
|
||||||
#include <fairmq/sdk/commands/CommandsFormatDef.h>
|
|
||||||
#include <fairmq/sdk/commands/CommandsFormat.h>
|
|
||||||
|
|
||||||
#include <flatbuffers/idl.h>
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace fair::mq::sdk::cmd
|
|
||||||
{
|
|
||||||
|
|
||||||
array<Result, 2> fbResultToResult =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
Result::Ok,
|
|
||||||
Result::Failure
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<FBResult, 2> resultToFBResult =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
FBResult::FBResult_Ok,
|
|
||||||
FBResult::FBResult_Failure
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<string, 2> resultNames =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"Ok",
|
|
||||||
"Failure"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<string, 17> typeNames =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"CheckState",
|
|
||||||
"ChangeState",
|
|
||||||
"DumpConfig",
|
|
||||||
"SubscribeToStateChange",
|
|
||||||
"UnsubscribeFromStateChange",
|
|
||||||
"StateChangeExitingReceived",
|
|
||||||
"GetProperties",
|
|
||||||
"SetProperties",
|
|
||||||
"SubscriptionHeartbeat",
|
|
||||||
|
|
||||||
"CurrentState",
|
|
||||||
"TransitionStatus",
|
|
||||||
"Config",
|
|
||||||
"StateChangeSubscription",
|
|
||||||
"StateChangeUnsubscription",
|
|
||||||
"StateChange",
|
|
||||||
"Properties",
|
|
||||||
"PropertiesSet"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<fair::mq::State, 16> fbStateToMQState =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
fair::mq::State::Undefined,
|
|
||||||
fair::mq::State::Ok,
|
|
||||||
fair::mq::State::Error,
|
|
||||||
fair::mq::State::Idle,
|
|
||||||
fair::mq::State::InitializingDevice,
|
|
||||||
fair::mq::State::Initialized,
|
|
||||||
fair::mq::State::Binding,
|
|
||||||
fair::mq::State::Bound,
|
|
||||||
fair::mq::State::Connecting,
|
|
||||||
fair::mq::State::DeviceReady,
|
|
||||||
fair::mq::State::InitializingTask,
|
|
||||||
fair::mq::State::Ready,
|
|
||||||
fair::mq::State::Running,
|
|
||||||
fair::mq::State::ResettingTask,
|
|
||||||
fair::mq::State::ResettingDevice,
|
|
||||||
fair::mq::State::Exiting
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<sdk::cmd::FBState, 16> mqStateToFBState =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
sdk::cmd::FBState_Undefined,
|
|
||||||
sdk::cmd::FBState_Ok,
|
|
||||||
sdk::cmd::FBState_Error,
|
|
||||||
sdk::cmd::FBState_Idle,
|
|
||||||
sdk::cmd::FBState_InitializingDevice,
|
|
||||||
sdk::cmd::FBState_Initialized,
|
|
||||||
sdk::cmd::FBState_Binding,
|
|
||||||
sdk::cmd::FBState_Bound,
|
|
||||||
sdk::cmd::FBState_Connecting,
|
|
||||||
sdk::cmd::FBState_DeviceReady,
|
|
||||||
sdk::cmd::FBState_InitializingTask,
|
|
||||||
sdk::cmd::FBState_Ready,
|
|
||||||
sdk::cmd::FBState_Running,
|
|
||||||
sdk::cmd::FBState_ResettingTask,
|
|
||||||
sdk::cmd::FBState_ResettingDevice,
|
|
||||||
sdk::cmd::FBState_Exiting
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<fair::mq::Transition, 12> fbTransitionToMQTransition =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
fair::mq::Transition::Auto,
|
|
||||||
fair::mq::Transition::InitDevice,
|
|
||||||
fair::mq::Transition::CompleteInit,
|
|
||||||
fair::mq::Transition::Bind,
|
|
||||||
fair::mq::Transition::Connect,
|
|
||||||
fair::mq::Transition::InitTask,
|
|
||||||
fair::mq::Transition::Run,
|
|
||||||
fair::mq::Transition::Stop,
|
|
||||||
fair::mq::Transition::ResetTask,
|
|
||||||
fair::mq::Transition::ResetDevice,
|
|
||||||
fair::mq::Transition::End,
|
|
||||||
fair::mq::Transition::ErrorFound
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<sdk::cmd::FBTransition, 12> mqTransitionToFBTransition =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
sdk::cmd::FBTransition_Auto,
|
|
||||||
sdk::cmd::FBTransition_InitDevice,
|
|
||||||
sdk::cmd::FBTransition_CompleteInit,
|
|
||||||
sdk::cmd::FBTransition_Bind,
|
|
||||||
sdk::cmd::FBTransition_Connect,
|
|
||||||
sdk::cmd::FBTransition_InitTask,
|
|
||||||
sdk::cmd::FBTransition_Run,
|
|
||||||
sdk::cmd::FBTransition_Stop,
|
|
||||||
sdk::cmd::FBTransition_ResetTask,
|
|
||||||
sdk::cmd::FBTransition_ResetDevice,
|
|
||||||
sdk::cmd::FBTransition_End,
|
|
||||||
sdk::cmd::FBTransition_ErrorFound
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<FBCmd, 17> typeToFBCmd =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
FBCmd::FBCmd_check_state,
|
|
||||||
FBCmd::FBCmd_change_state,
|
|
||||||
FBCmd::FBCmd_dump_config,
|
|
||||||
FBCmd::FBCmd_subscribe_to_state_change,
|
|
||||||
FBCmd::FBCmd_unsubscribe_from_state_change,
|
|
||||||
FBCmd::FBCmd_state_change_exiting_received,
|
|
||||||
FBCmd::FBCmd_get_properties,
|
|
||||||
FBCmd::FBCmd_set_properties,
|
|
||||||
FBCmd::FBCmd_subscription_heartbeat,
|
|
||||||
FBCmd::FBCmd_current_state,
|
|
||||||
FBCmd::FBCmd_transition_status,
|
|
||||||
FBCmd::FBCmd_config,
|
|
||||||
FBCmd::FBCmd_state_change_subscription,
|
|
||||||
FBCmd::FBCmd_state_change_unsubscription,
|
|
||||||
FBCmd::FBCmd_state_change,
|
|
||||||
FBCmd::FBCmd_properties,
|
|
||||||
FBCmd::FBCmd_properties_set
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
array<Type, 17> fbCmdToType =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
Type::check_state,
|
|
||||||
Type::change_state,
|
|
||||||
Type::dump_config,
|
|
||||||
Type::subscribe_to_state_change,
|
|
||||||
Type::unsubscribe_from_state_change,
|
|
||||||
Type::state_change_exiting_received,
|
|
||||||
Type::get_properties,
|
|
||||||
Type::set_properties,
|
|
||||||
Type::subscription_heartbeat,
|
|
||||||
Type::current_state,
|
|
||||||
Type::transition_status,
|
|
||||||
Type::config,
|
|
||||||
Type::state_change_subscription,
|
|
||||||
Type::state_change_unsubscription,
|
|
||||||
Type::state_change,
|
|
||||||
Type::properties,
|
|
||||||
Type::properties_set
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fair::mq::State GetMQState(const FBState state) { return fbStateToMQState.at(state); }
|
|
||||||
FBState GetFBState(const fair::mq::State state) { return mqStateToFBState.at(static_cast<int>(state)); }
|
|
||||||
fair::mq::Transition GetMQTransition(const FBTransition transition) { return fbTransitionToMQTransition.at(transition); }
|
|
||||||
FBTransition GetFBTransition(const fair::mq::Transition transition) { return mqTransitionToFBTransition.at(static_cast<int>(transition)); }
|
|
||||||
|
|
||||||
Result GetResult(const FBResult result) { return fbResultToResult.at(result); }
|
|
||||||
FBResult GetFBResult(const Result result) { return resultToFBResult.at(static_cast<int>(result)); }
|
|
||||||
string GetResultName(const Result result) { return resultNames.at(static_cast<int>(result)); }
|
|
||||||
string GetTypeName(const Type type) { return typeNames.at(static_cast<int>(type)); }
|
|
||||||
|
|
||||||
FBCmd GetFBCmd(const Type type) { return typeToFBCmd.at(static_cast<int>(type)); }
|
|
||||||
|
|
||||||
string Cmds::Serialize(const Format type) const
|
|
||||||
{
|
|
||||||
flatbuffers::FlatBufferBuilder fbb;
|
|
||||||
vector<flatbuffers::Offset<FBCommand>> commandOffsets;
|
|
||||||
|
|
||||||
for (auto& cmd : fCmds) {
|
|
||||||
flatbuffers::Offset<FBCommand> cmdOffset;
|
|
||||||
unique_ptr<FBCommandBuilder> cmdBuilder; // delay the creation of the builder, because child strings need to be constructed first (which are conditional)
|
|
||||||
|
|
||||||
switch (cmd->GetType()) {
|
|
||||||
case Type::check_state: {
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::change_state: {
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_transition(GetFBTransition(static_cast<ChangeState&>(*cmd).GetTransition()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::dump_config: {
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
break;
|
|
||||||
case Type::subscribe_to_state_change: {
|
|
||||||
auto _cmd = static_cast<SubscribeToStateChange&>(*cmd);
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_interval(_cmd.GetInterval());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::unsubscribe_from_state_change: {
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::state_change_exiting_received: {
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::get_properties: {
|
|
||||||
auto _cmd = static_cast<GetProperties&>(*cmd);
|
|
||||||
auto query = fbb.CreateString(_cmd.GetQuery());
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
|
||||||
cmdBuilder->add_property_query(query);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::set_properties: {
|
|
||||||
auto _cmd = static_cast<SetProperties&>(*cmd);
|
|
||||||
std::vector<flatbuffers::Offset<FBProperty>> propsVector;
|
|
||||||
for (auto const& e : _cmd.GetProps()) {
|
|
||||||
auto const key(fbb.CreateString(e.first));
|
|
||||||
auto const val(fbb.CreateString(e.second));
|
|
||||||
propsVector.push_back(CreateFBProperty(fbb, key, val));
|
|
||||||
}
|
|
||||||
auto props = fbb.CreateVector(propsVector);
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
|
||||||
cmdBuilder->add_properties(props);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::subscription_heartbeat: {
|
|
||||||
auto _cmd = static_cast<SubscriptionHeartbeat&>(*cmd);
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_interval(_cmd.GetInterval());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::current_state: {
|
|
||||||
auto _cmd = static_cast<CurrentState&>(*cmd);
|
|
||||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::transition_status: {
|
|
||||||
auto _cmd = static_cast<TransitionStatus&>(*cmd);
|
|
||||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
|
||||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
|
||||||
cmdBuilder->add_transition(GetFBTransition(_cmd.GetTransition()));
|
|
||||||
cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::config: {
|
|
||||||
auto _cmd = static_cast<Config&>(*cmd);
|
|
||||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
|
||||||
auto config = fbb.CreateString(_cmd.GetConfig());
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_config_string(config);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::state_change_subscription: {
|
|
||||||
auto _cmd = static_cast<StateChangeSubscription&>(*cmd);
|
|
||||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
|
||||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::state_change_unsubscription: {
|
|
||||||
auto _cmd = static_cast<StateChangeUnsubscription&>(*cmd);
|
|
||||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
|
||||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::state_change: {
|
|
||||||
auto _cmd = static_cast<StateChange&>(*cmd);
|
|
||||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
|
||||||
cmdBuilder->add_last_state(GetFBState(_cmd.GetLastState()));
|
|
||||||
cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::properties: {
|
|
||||||
auto _cmd = static_cast<Properties&>(*cmd);
|
|
||||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
|
||||||
|
|
||||||
std::vector<flatbuffers::Offset<FBProperty>> propsVector;
|
|
||||||
for (const auto& e : _cmd.GetProps()) {
|
|
||||||
auto key = fbb.CreateString(e.first);
|
|
||||||
auto val = fbb.CreateString(e.second);
|
|
||||||
auto prop = CreateFBProperty(fbb, key, val);
|
|
||||||
propsVector.push_back(prop);
|
|
||||||
}
|
|
||||||
auto props = fbb.CreateVector(propsVector);
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
|
||||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
|
||||||
cmdBuilder->add_properties(props);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::properties_set: {
|
|
||||||
auto _cmd = static_cast<PropertiesSet&>(*cmd);
|
|
||||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
|
||||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
|
||||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Serialize()");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdBuilder->add_command_id(typeToFBCmd.at(static_cast<int>(cmd->GetType())));
|
|
||||||
|
|
||||||
cmdOffset = cmdBuilder->Finish();
|
|
||||||
commandOffsets.push_back(cmdOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto commands = fbb.CreateVector(commandOffsets);
|
|
||||||
auto cmds = CreateFBCommands(fbb, commands);
|
|
||||||
fbb.Finish(cmds);
|
|
||||||
|
|
||||||
if (type == Format::Binary) {
|
|
||||||
return string(reinterpret_cast<char*>(fbb.GetBufferPointer()), fbb.GetSize());
|
|
||||||
} else { // Type == Format::JSON
|
|
||||||
flatbuffers::Parser parser;
|
|
||||||
if (!parser.Parse(commandsFormatDefFbs)) {
|
|
||||||
throw CommandFormatError("Serialize couldn't parse commands format");
|
|
||||||
}
|
|
||||||
std::string json;
|
|
||||||
if (!flatbuffers::GenerateText(parser, fbb.GetBufferPointer(), &json)) {
|
|
||||||
throw CommandFormatError("Serialize couldn't serialize parsed data to JSON!");
|
|
||||||
}
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cmds::Deserialize(const string& str, const Format type)
|
|
||||||
{
|
|
||||||
fCmds.clear();
|
|
||||||
|
|
||||||
const flatbuffers::Vector<flatbuffers::Offset<FBCommand>>* cmds = nullptr;
|
|
||||||
|
|
||||||
flatbuffers::Parser parser;
|
|
||||||
if (type == Format::Binary) {
|
|
||||||
cmds = cmd::GetFBCommands(const_cast<char*>(str.c_str()))->commands();
|
|
||||||
} else { // Type == Format::JSON
|
|
||||||
if (!parser.Parse(commandsFormatDefFbs)) {
|
|
||||||
throw CommandFormatError("Deserialize couldn't parse commands format");
|
|
||||||
}
|
|
||||||
if (!parser.Parse(str.c_str())) {
|
|
||||||
throw CommandFormatError("Deserialize couldn't parse incoming JSON string");
|
|
||||||
}
|
|
||||||
cmds = cmd::GetFBCommands(parser.builder_.GetBufferPointer())->commands();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < cmds->size(); ++i) {
|
|
||||||
const fair::mq::sdk::cmd::FBCommand& cmdPtr = *(cmds->Get(i));
|
|
||||||
switch (cmdPtr.command_id()) {
|
|
||||||
case FBCmd_check_state:
|
|
||||||
fCmds.emplace_back(make<CheckState>());
|
|
||||||
break;
|
|
||||||
case FBCmd_change_state:
|
|
||||||
fCmds.emplace_back(make<ChangeState>(GetMQTransition(cmdPtr.transition())));
|
|
||||||
break;
|
|
||||||
case FBCmd_dump_config:
|
|
||||||
fCmds.emplace_back(make<DumpConfig>());
|
|
||||||
break;
|
|
||||||
case FBCmd_subscribe_to_state_change:
|
|
||||||
fCmds.emplace_back(make<SubscribeToStateChange>(cmdPtr.interval()));
|
|
||||||
break;
|
|
||||||
case FBCmd_unsubscribe_from_state_change:
|
|
||||||
fCmds.emplace_back(make<UnsubscribeFromStateChange>());
|
|
||||||
break;
|
|
||||||
case FBCmd_state_change_exiting_received:
|
|
||||||
fCmds.emplace_back(make<StateChangeExitingReceived>());
|
|
||||||
break;
|
|
||||||
case FBCmd_get_properties:
|
|
||||||
fCmds.emplace_back(make<GetProperties>(cmdPtr.request_id(), cmdPtr.property_query()->str()));
|
|
||||||
break;
|
|
||||||
case FBCmd_set_properties: {
|
|
||||||
std::vector<std::pair<std::string, std::string>> properties;
|
|
||||||
auto props = cmdPtr.properties();
|
|
||||||
for (unsigned int j = 0; j < props->size(); ++j) {
|
|
||||||
properties.emplace_back(props->Get(j)->key()->str(), props->Get(j)->value()->str());
|
|
||||||
}
|
|
||||||
fCmds.emplace_back(make<SetProperties>(cmdPtr.request_id(), properties));
|
|
||||||
} break;
|
|
||||||
case FBCmd_subscription_heartbeat:
|
|
||||||
fCmds.emplace_back(make<SubscriptionHeartbeat>(cmdPtr.interval()));
|
|
||||||
break;
|
|
||||||
case FBCmd_current_state:
|
|
||||||
fCmds.emplace_back(make<CurrentState>(cmdPtr.device_id()->str(), GetMQState(cmdPtr.current_state())));
|
|
||||||
break;
|
|
||||||
case FBCmd_transition_status:
|
|
||||||
fCmds.emplace_back(make<TransitionStatus>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result()), GetMQTransition(cmdPtr.transition()), GetMQState(cmdPtr.current_state())));
|
|
||||||
break;
|
|
||||||
case FBCmd_config:
|
|
||||||
fCmds.emplace_back(make<Config>(cmdPtr.device_id()->str(), cmdPtr.config_string()->str()));
|
|
||||||
break;
|
|
||||||
case FBCmd_state_change_subscription:
|
|
||||||
fCmds.emplace_back(make<StateChangeSubscription>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result())));
|
|
||||||
break;
|
|
||||||
case FBCmd_state_change_unsubscription:
|
|
||||||
fCmds.emplace_back(make<StateChangeUnsubscription>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result())));
|
|
||||||
break;
|
|
||||||
case FBCmd_state_change:
|
|
||||||
fCmds.emplace_back(make<StateChange>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetMQState(cmdPtr.last_state()), GetMQState(cmdPtr.current_state())));
|
|
||||||
break;
|
|
||||||
case FBCmd_properties: {
|
|
||||||
std::vector<std::pair<std::string, std::string>> properties;
|
|
||||||
auto props = cmdPtr.properties();
|
|
||||||
for (unsigned int j = 0; j < props->size(); ++j) {
|
|
||||||
properties.emplace_back(props->Get(j)->key()->str(), props->Get(j)->value()->str());
|
|
||||||
}
|
|
||||||
fCmds.emplace_back(make<Properties>(cmdPtr.device_id()->str(), cmdPtr.request_id(), GetResult(cmdPtr.result()), properties));
|
|
||||||
} break;
|
|
||||||
case FBCmd_properties_set:
|
|
||||||
fCmds.emplace_back(make<PropertiesSet>(cmdPtr.device_id()->str(), cmdPtr.request_id(), GetResult(cmdPtr.result())));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Deserialize()");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk::cmd
|
|
|
@ -1,414 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_SDK_COMMANDFACTORY
|
|
||||||
#define FAIR_MQ_SDK_COMMANDFACTORY
|
|
||||||
|
|
||||||
#include <fairmq/States.h>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility> // move
|
|
||||||
|
|
||||||
namespace fair::mq::sdk::cmd
|
|
||||||
{
|
|
||||||
|
|
||||||
enum class Format : int {
|
|
||||||
Binary,
|
|
||||||
JSON
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Result : int {
|
|
||||||
Ok,
|
|
||||||
Failure
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Type : int
|
|
||||||
{
|
|
||||||
check_state, // args: { }
|
|
||||||
change_state, // args: { transition }
|
|
||||||
dump_config, // args: { }
|
|
||||||
subscribe_to_state_change, // args: { }
|
|
||||||
unsubscribe_from_state_change, // args: { }
|
|
||||||
state_change_exiting_received, // args: { }
|
|
||||||
get_properties, // args: { request_id, property_query }
|
|
||||||
set_properties, // args: { request_id, properties }
|
|
||||||
subscription_heartbeat, // args: { interval }
|
|
||||||
|
|
||||||
current_state, // args: { device_id, current_state }
|
|
||||||
transition_status, // args: { device_id, task_id, Result, transition, current_state }
|
|
||||||
config, // args: { device_id, config_string }
|
|
||||||
state_change_subscription, // args: { device_id, task_id, Result }
|
|
||||||
state_change_unsubscription, // args: { device_id, task_id, Result }
|
|
||||||
state_change, // args: { device_id, task_id, last_state, current_state }
|
|
||||||
properties, // args: { device_id, request_id, Result, properties }
|
|
||||||
properties_set // args: { device_id, request_id, Result }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Cmd
|
|
||||||
{
|
|
||||||
explicit Cmd(const Type type) : fType(type) {}
|
|
||||||
virtual ~Cmd() = default;
|
|
||||||
|
|
||||||
Type GetType() const { return fType; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type fType;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CheckState : Cmd
|
|
||||||
{
|
|
||||||
explicit CheckState() : Cmd(Type::check_state) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ChangeState : Cmd
|
|
||||||
{
|
|
||||||
explicit ChangeState(Transition transition)
|
|
||||||
: Cmd(Type::change_state)
|
|
||||||
, fTransition(transition)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Transition GetTransition() const { return fTransition; }
|
|
||||||
void SetTransition(Transition transition) { fTransition = transition; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Transition fTransition;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DumpConfig : Cmd
|
|
||||||
{
|
|
||||||
explicit DumpConfig() : Cmd(Type::dump_config) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SubscribeToStateChange : Cmd
|
|
||||||
{
|
|
||||||
explicit SubscribeToStateChange(int64_t interval)
|
|
||||||
: Cmd(Type::subscribe_to_state_change)
|
|
||||||
, fInterval(interval)
|
|
||||||
{}
|
|
||||||
|
|
||||||
int64_t GetInterval() const { return fInterval; }
|
|
||||||
void SetInterval(int64_t interval) { fInterval = interval; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int64_t fInterval;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UnsubscribeFromStateChange : Cmd
|
|
||||||
{
|
|
||||||
explicit UnsubscribeFromStateChange() : Cmd(Type::unsubscribe_from_state_change) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StateChangeExitingReceived : Cmd
|
|
||||||
{
|
|
||||||
explicit StateChangeExitingReceived() : Cmd(Type::state_change_exiting_received) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GetProperties : Cmd
|
|
||||||
{
|
|
||||||
GetProperties(std::size_t request_id, std::string query)
|
|
||||||
: Cmd(Type::get_properties)
|
|
||||||
, fRequestId(request_id)
|
|
||||||
, fQuery(std::move(query))
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto GetRequestId() const -> std::size_t { return fRequestId; }
|
|
||||||
auto SetRequestId(std::size_t requestId) -> void { fRequestId = requestId; }
|
|
||||||
auto GetQuery() const -> std::string { return fQuery; }
|
|
||||||
auto SetQuery(std::string query) -> void { fQuery = std::move(query); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::size_t fRequestId;
|
|
||||||
std::string fQuery;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SetProperties : Cmd
|
|
||||||
{
|
|
||||||
SetProperties(std::size_t request_id, std::vector<std::pair<std::string, std::string>> properties)
|
|
||||||
: Cmd(Type::set_properties)
|
|
||||||
, fRequestId(request_id)
|
|
||||||
, fProperties(std::move(properties))
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto GetRequestId() const -> std::size_t { return fRequestId; }
|
|
||||||
auto SetRequestId(std::size_t requestId) -> void { fRequestId = requestId; }
|
|
||||||
auto GetProps() const -> std::vector<std::pair<std::string, std::string>> { return fProperties; }
|
|
||||||
auto SetProps(std::vector<std::pair<std::string, std::string>> properties) -> void { fProperties = std::move(properties); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::size_t fRequestId;
|
|
||||||
std::vector<std::pair<std::string, std::string>> fProperties;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SubscriptionHeartbeat : Cmd
|
|
||||||
{
|
|
||||||
explicit SubscriptionHeartbeat(int64_t interval)
|
|
||||||
: Cmd(Type::subscription_heartbeat)
|
|
||||||
, fInterval(interval)
|
|
||||||
{}
|
|
||||||
|
|
||||||
int64_t GetInterval() const { return fInterval; }
|
|
||||||
void SetInterval(int64_t interval) { fInterval = interval; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int64_t fInterval;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CurrentState : Cmd
|
|
||||||
{
|
|
||||||
explicit CurrentState(std::string id, State currentState)
|
|
||||||
: Cmd(Type::current_state)
|
|
||||||
, fDeviceId(std::move(id))
|
|
||||||
, fCurrentState(currentState)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
fair::mq::State GetCurrentState() const { return fCurrentState; }
|
|
||||||
void SetCurrentState(fair::mq::State state) { fCurrentState = state; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
fair::mq::State fCurrentState;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TransitionStatus : Cmd
|
|
||||||
{
|
|
||||||
explicit TransitionStatus(std::string deviceId, const uint64_t taskId, const Result result, const Transition transition, State currentState)
|
|
||||||
: Cmd(Type::transition_status)
|
|
||||||
, fDeviceId(std::move(deviceId))
|
|
||||||
, fTaskId(taskId)
|
|
||||||
, fResult(result)
|
|
||||||
, fTransition(transition)
|
|
||||||
, fCurrentState(currentState)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
uint64_t GetTaskId() const { return fTaskId; }
|
|
||||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
|
||||||
Result GetResult() const { return fResult; }
|
|
||||||
void SetResult(const Result result) { fResult = result; }
|
|
||||||
Transition GetTransition() const { return fTransition; }
|
|
||||||
void SetTransition(const Transition transition) { fTransition = transition; }
|
|
||||||
fair::mq::State GetCurrentState() const { return fCurrentState; }
|
|
||||||
void SetCurrentState(fair::mq::State state) { fCurrentState = state; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
uint64_t fTaskId;
|
|
||||||
Result fResult;
|
|
||||||
Transition fTransition;
|
|
||||||
fair::mq::State fCurrentState;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Config : Cmd
|
|
||||||
{
|
|
||||||
explicit Config(std::string id, std::string config)
|
|
||||||
: Cmd(Type::config)
|
|
||||||
, fDeviceId(std::move(id))
|
|
||||||
, fConfig(std::move(config))
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
std::string GetConfig() const { return fConfig; }
|
|
||||||
void SetConfig(const std::string& config) { fConfig = config; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
std::string fConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StateChangeSubscription : Cmd
|
|
||||||
{
|
|
||||||
explicit StateChangeSubscription(std::string id, const uint64_t taskId, const Result result)
|
|
||||||
: Cmd(Type::state_change_subscription)
|
|
||||||
, fDeviceId(std::move(id))
|
|
||||||
, fTaskId(taskId)
|
|
||||||
, fResult(result)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
uint64_t GetTaskId() const { return fTaskId; }
|
|
||||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
|
||||||
Result GetResult() const { return fResult; }
|
|
||||||
void SetResult(const Result result) { fResult = result; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
uint64_t fTaskId;
|
|
||||||
Result fResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StateChangeUnsubscription : Cmd
|
|
||||||
{
|
|
||||||
explicit StateChangeUnsubscription(std::string id, const uint64_t taskId, const Result result)
|
|
||||||
: Cmd(Type::state_change_unsubscription)
|
|
||||||
, fDeviceId(std::move(id))
|
|
||||||
, fTaskId(taskId)
|
|
||||||
, fResult(result)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
uint64_t GetTaskId() const { return fTaskId; }
|
|
||||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
|
||||||
Result GetResult() const { return fResult; }
|
|
||||||
void SetResult(const Result result) { fResult = result; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
uint64_t fTaskId;
|
|
||||||
Result fResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StateChange : Cmd
|
|
||||||
{
|
|
||||||
explicit StateChange(std::string deviceId, const uint64_t taskId, const State lastState, const State currentState)
|
|
||||||
: Cmd(Type::state_change)
|
|
||||||
, fDeviceId(std::move(deviceId))
|
|
||||||
, fTaskId(taskId)
|
|
||||||
, fLastState(lastState)
|
|
||||||
, fCurrentState(currentState)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
uint64_t GetTaskId() const { return fTaskId; }
|
|
||||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
|
||||||
fair::mq::State GetLastState() const { return fLastState; }
|
|
||||||
void SetLastState(const fair::mq::State state) { fLastState = state; }
|
|
||||||
fair::mq::State GetCurrentState() const { return fCurrentState; }
|
|
||||||
void SetCurrentState(const fair::mq::State state) { fCurrentState = state; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
uint64_t fTaskId;
|
|
||||||
fair::mq::State fLastState;
|
|
||||||
fair::mq::State fCurrentState;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Properties : Cmd
|
|
||||||
{
|
|
||||||
Properties(std::string deviceId, std::size_t requestId, const Result result, std::vector<std::pair<std::string, std::string>> properties)
|
|
||||||
: Cmd(Type::properties)
|
|
||||||
, fDeviceId(std::move(deviceId))
|
|
||||||
, fRequestId(requestId)
|
|
||||||
, fResult(result)
|
|
||||||
, fProperties(std::move(properties))
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto GetDeviceId() const -> std::string { return fDeviceId; }
|
|
||||||
auto SetDeviceId(std::string deviceId) -> void { fDeviceId = std::move(deviceId); }
|
|
||||||
auto GetRequestId() const -> std::size_t { return fRequestId; }
|
|
||||||
auto SetRequestId(std::size_t requestId) -> void { fRequestId = requestId; }
|
|
||||||
auto GetResult() const -> Result { return fResult; }
|
|
||||||
auto SetResult(Result result) -> void { fResult = result; }
|
|
||||||
auto GetProps() const -> std::vector<std::pair<std::string, std::string>> { return fProperties; }
|
|
||||||
auto SetProps(std::vector<std::pair<std::string, std::string>> properties) -> void { fProperties = std::move(properties); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
std::size_t fRequestId;
|
|
||||||
Result fResult;
|
|
||||||
std::vector<std::pair<std::string, std::string>> fProperties;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PropertiesSet : Cmd {
|
|
||||||
PropertiesSet(std::string deviceId, std::size_t requestId, Result result)
|
|
||||||
: Cmd(Type::properties_set)
|
|
||||||
, fDeviceId(std::move(deviceId))
|
|
||||||
, fRequestId(requestId)
|
|
||||||
, fResult(result)
|
|
||||||
{}
|
|
||||||
|
|
||||||
auto GetDeviceId() const -> std::string { return fDeviceId; }
|
|
||||||
auto SetDeviceId(std::string deviceId) -> void { fDeviceId = std::move(deviceId); }
|
|
||||||
auto GetRequestId() const -> std::size_t { return fRequestId; }
|
|
||||||
auto SetRequestId(std::size_t requestId) -> void { fRequestId = requestId; }
|
|
||||||
auto GetResult() const -> Result { return fResult; }
|
|
||||||
auto SetResult(Result result) -> void { fResult = result; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
std::size_t fRequestId;
|
|
||||||
Result fResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename C, typename... Args>
|
|
||||||
std::unique_ptr<Cmd> make(Args&&... args)
|
|
||||||
{
|
|
||||||
return std::make_unique<C>(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Cmds
|
|
||||||
{
|
|
||||||
using container = std::vector<std::unique_ptr<Cmd>>;
|
|
||||||
struct CommandFormatError : std::runtime_error { using std::runtime_error::runtime_error; };
|
|
||||||
|
|
||||||
explicit Cmds() = default;
|
|
||||||
|
|
||||||
template<typename... Rest>
|
|
||||||
explicit Cmds(std::unique_ptr<Cmd>&& first, Rest&&... rest)
|
|
||||||
{
|
|
||||||
Unpack(std::forward<std::unique_ptr<Cmd>&&>(first), std::forward<Rest>(rest)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Add(std::unique_ptr<Cmd>&& cmd) { fCmds.emplace_back(std::move(cmd)); }
|
|
||||||
|
|
||||||
template<typename C, typename... Args>
|
|
||||||
void Add(Args&&... args)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of<Cmd, C>::value, "Only types derived from fair::mq::cmd::Cmd are allowed");
|
|
||||||
Add(make<C>(std::forward<Args>(args)...));
|
|
||||||
}
|
|
||||||
|
|
||||||
Cmd& At(size_t i) { return *(fCmds.at(i)); }
|
|
||||||
|
|
||||||
size_t Size() const { return fCmds.size(); }
|
|
||||||
void Reset() { fCmds.clear(); }
|
|
||||||
|
|
||||||
std::string Serialize(const Format type = Format::Binary) const;
|
|
||||||
void Deserialize(const std::string&, const Format type = Format::Binary);
|
|
||||||
|
|
||||||
private:
|
|
||||||
container fCmds;
|
|
||||||
|
|
||||||
void Unpack() {}
|
|
||||||
|
|
||||||
template <class... Rest>
|
|
||||||
void Unpack(std::unique_ptr<Cmd>&& first, Rest&&... rest)
|
|
||||||
{
|
|
||||||
fCmds.emplace_back(std::move(first));
|
|
||||||
Unpack(std::forward<Rest>(rest)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator = container::iterator;
|
|
||||||
using const_iterator = container::const_iterator;
|
|
||||||
|
|
||||||
auto begin() -> decltype(fCmds.begin()) { return fCmds.begin(); }
|
|
||||||
auto end() -> decltype(fCmds.end()) { return fCmds.end(); }
|
|
||||||
auto cbegin() -> decltype(fCmds.cbegin()) { return fCmds.cbegin(); }
|
|
||||||
auto cend() -> decltype(fCmds.cend()) { return fCmds.cend(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string GetResultName(const Result result);
|
|
||||||
std::string GetTypeName(const Type type);
|
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, const Result& result) { return os << GetResultName(result); }
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, const Type& type) { return os << GetTypeName(type); }
|
|
||||||
|
|
||||||
} // namespace fair::mq::sdk::cmd
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SDK_COMMANDFACTORY */
|
|
|
@ -1,89 +0,0 @@
|
||||||
namespace fair.mq.sdk.cmd;
|
|
||||||
|
|
||||||
enum FBResult:byte {
|
|
||||||
Ok,
|
|
||||||
Failure
|
|
||||||
}
|
|
||||||
|
|
||||||
enum FBState:byte {
|
|
||||||
Undefined,
|
|
||||||
Ok,
|
|
||||||
Error,
|
|
||||||
Idle,
|
|
||||||
InitializingDevice,
|
|
||||||
Initialized,
|
|
||||||
Binding,
|
|
||||||
Bound,
|
|
||||||
Connecting,
|
|
||||||
DeviceReady,
|
|
||||||
InitializingTask,
|
|
||||||
Ready,
|
|
||||||
Running,
|
|
||||||
ResettingTask,
|
|
||||||
ResettingDevice,
|
|
||||||
Exiting
|
|
||||||
}
|
|
||||||
|
|
||||||
enum FBTransition:byte {
|
|
||||||
Auto,
|
|
||||||
InitDevice,
|
|
||||||
CompleteInit,
|
|
||||||
Bind,
|
|
||||||
Connect,
|
|
||||||
InitTask,
|
|
||||||
Run,
|
|
||||||
Stop,
|
|
||||||
ResetTask,
|
|
||||||
ResetDevice,
|
|
||||||
End,
|
|
||||||
ErrorFound
|
|
||||||
}
|
|
||||||
|
|
||||||
table FBProperty {
|
|
||||||
key:string;
|
|
||||||
value:string;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum FBCmd:byte {
|
|
||||||
check_state, // args: { }
|
|
||||||
change_state, // args: { transition }
|
|
||||||
dump_config, // args: { }
|
|
||||||
subscribe_to_state_change, // args: { interval }
|
|
||||||
unsubscribe_from_state_change, // args: { }
|
|
||||||
state_change_exiting_received, // args: { }
|
|
||||||
get_properties, // args: { request_id, property_query }
|
|
||||||
set_properties, // args: { request_id, properties }
|
|
||||||
subscription_heartbeat, // args: { interval }
|
|
||||||
|
|
||||||
current_state, // args: { device_id, current_state }
|
|
||||||
transition_status, // args: { device_id, task_id, Result, transition, current_state }
|
|
||||||
config, // args: { device_id, config_string }
|
|
||||||
state_change_subscription, // args: { device_id, task_id, Result }
|
|
||||||
state_change_unsubscription, // args: { device_id, task_id, Result }
|
|
||||||
state_change, // args: { device_id, task_id, last_state, current_state }
|
|
||||||
properties, // args: { device_id, request_id, Result, properties }
|
|
||||||
properties_set // args: { device_id, request_id, Result }
|
|
||||||
}
|
|
||||||
|
|
||||||
table FBCommand {
|
|
||||||
command_id:FBCmd;
|
|
||||||
device_id:string;
|
|
||||||
task_id:uint64;
|
|
||||||
request_id:uint64;
|
|
||||||
interval:int64;
|
|
||||||
state:FBState;
|
|
||||||
transition:FBTransition;
|
|
||||||
result:FBResult;
|
|
||||||
config_string:string;
|
|
||||||
last_state:FBState;
|
|
||||||
current_state:FBState;
|
|
||||||
debug:string;
|
|
||||||
properties:[FBProperty];
|
|
||||||
property_query:string;
|
|
||||||
}
|
|
||||||
|
|
||||||
table FBCommands {
|
|
||||||
commands:[FBCommand];
|
|
||||||
}
|
|
||||||
|
|
||||||
root_type FBCommands;
|
|
|
@ -1,18 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace fair::mq::sdk
|
|
||||||
{
|
|
||||||
namespace cmd {
|
|
||||||
|
|
||||||
constexpr auto commandsFormatDefFbs = R"(@commands_format_def_fbs@)";
|
|
||||||
|
|
||||||
} // namespace cmd
|
|
||||||
} // namespace fair::mq::sdk
|
|
|
@ -1,256 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2014-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include <fairmq/sdk/commands/Commands.h>
|
|
||||||
#include <fairmq/States.h>
|
|
||||||
#include <fairmq/SDK.h>
|
|
||||||
#include <fairmq/tools/Strings.h>
|
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
|
||||||
|
|
||||||
#include <termios.h> // raw mode console input
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <mutex>
|
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace fair::mq;
|
|
||||||
using namespace fair::mq::sdk;
|
|
||||||
using namespace fair::mq::sdk::cmd;
|
|
||||||
namespace bpo = boost::program_options;
|
|
||||||
|
|
||||||
struct TerminalConfig
|
|
||||||
{
|
|
||||||
explicit TerminalConfig()
|
|
||||||
{
|
|
||||||
termios t;
|
|
||||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
|
||||||
t.c_lflag &= ~ICANON; // disable canonical input
|
|
||||||
// t.c_lflag &= ~ECHO; // do not echo input chars
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
|
||||||
}
|
|
||||||
|
|
||||||
~TerminalConfig()
|
|
||||||
{
|
|
||||||
termios t;
|
|
||||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
|
||||||
t.c_lflag |= ICANON; // re-enable canonical input
|
|
||||||
// t.c_lflag |= ECHO; // echo input chars
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void printControlsHelp()
|
|
||||||
{
|
|
||||||
cout << "Use keys to control the devices:" << endl;
|
|
||||||
cout << "[c] check states, [o] dump config, [h] help, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device, [k] complete init, [b] bind, [x] connect, [p] set property" << endl;
|
|
||||||
cout << "To quit press Ctrl+C" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleCommand(const string& command, const string& path, unsigned int timeout, Topology& topo, const string& pKey, const string& pVal)
|
|
||||||
{
|
|
||||||
std::pair<std::error_code, fair::mq::sdk::TopologyState> changeStateResult;
|
|
||||||
|
|
||||||
if (command == "c") {
|
|
||||||
cout << "> checking state of the devices" << endl;
|
|
||||||
auto const result = topo.GetCurrentState();
|
|
||||||
bool error = false;
|
|
||||||
for (const auto& d : result) {
|
|
||||||
cout << d.taskId << " : " << d.state << endl;
|
|
||||||
if (d.state == sdk::DeviceState::Error) {
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
throw runtime_error("Some of the devices are in the Error state");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else if (command == "o") {
|
|
||||||
cout << "> dumping config of " << (path.empty() ? "all" : path) << endl;
|
|
||||||
// TODO: extend this regex to return all properties, once command size limitation is removed.
|
|
||||||
auto const result = topo.GetProperties("^(session|id)$", path, std::chrono::milliseconds(timeout));
|
|
||||||
if (result.first != std::error_code()) {
|
|
||||||
cout << "ERROR: GetProperties failed for '" << path << "': " << result.first.message() << endl;
|
|
||||||
throw runtime_error(tools::ToString("GetProperties failed for '", path, "': ", result.first.message()));
|
|
||||||
}
|
|
||||||
for (const auto& d : result.second.devices) {
|
|
||||||
for (auto const& p : d.second.props) {
|
|
||||||
cout << d.first << ": " << p.first << " : " << p.second << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else if (command == "p") {
|
|
||||||
if (pKey.empty() || pVal.empty()) {
|
|
||||||
cout << "cannot send property with empty key and/or value! given key: '" << pKey << "', value: '" << pVal << "'." << endl;
|
|
||||||
throw runtime_error(tools::ToString("cannot send property with empty key and/or value! given key: '", pKey, "', value: '", pVal, "'."));
|
|
||||||
}
|
|
||||||
const DeviceProperties props{{pKey, pVal}};
|
|
||||||
cout << "> setting properties --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
auto const result = topo.SetProperties(props, path);
|
|
||||||
if (result.first != std::error_code()) {
|
|
||||||
cout << "ERROR: SetProperties failed for '" << path << "': " << result.first.message() << endl;
|
|
||||||
throw runtime_error(tools::ToString("SetProperties failed for '", path, "': ", result.first.message()));
|
|
||||||
}
|
|
||||||
// give dds time to complete request
|
|
||||||
this_thread::sleep_for(chrono::milliseconds(100));
|
|
||||||
return;
|
|
||||||
} else if (command == "i") {
|
|
||||||
cout << "> initiating InitDevice transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::InitDevice, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "k") {
|
|
||||||
cout << "> initiating CompleteInit transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::CompleteInit, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "b") {
|
|
||||||
cout << "> initiating Bind transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::Bind, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "x") {
|
|
||||||
cout << "> initiating Connect transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::Connect, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "j") {
|
|
||||||
cout << "> initiating InitTask transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::InitTask, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "r") {
|
|
||||||
cout << "> initiating Run transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::Run, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "s") {
|
|
||||||
cout << "> initiating Stop transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::Stop, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "t") {
|
|
||||||
cout << "> initiating ResetTask transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::ResetTask, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "d") {
|
|
||||||
cout << "> initiating ResetDevice transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::ResetDevice, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "q") {
|
|
||||||
cout << "> initiating End transition --> " << (path.empty() ? "all" : path) << endl;
|
|
||||||
changeStateResult = topo.ChangeState(TopologyTransition::End, path, std::chrono::milliseconds(timeout));
|
|
||||||
} else if (command == "h") {
|
|
||||||
cout << "> help" << endl;
|
|
||||||
printControlsHelp();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
cout << "\033[01;32mInvalid input: [" << command << "]\033[0m" << endl;
|
|
||||||
printControlsHelp();
|
|
||||||
throw runtime_error(tools::ToString("\033[01;32mInvalid input: [", command, "]\033[0m"));
|
|
||||||
}
|
|
||||||
if (changeStateResult.first != std::error_code()) {
|
|
||||||
cout << "ERROR: ChangeState failed for '" << path << "': " << changeStateResult.first.message() << endl;
|
|
||||||
throw runtime_error(tools::ToString("ERROR: ChangeState failed for '", path, "': ", changeStateResult.first.message()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendCommand(const string& commandIn, const string& path, unsigned int timeout, Topology& topo, const string& pKey, const string& pVal)
|
|
||||||
{
|
|
||||||
if (!commandIn.empty()) {
|
|
||||||
handleCommand(commandIn, path, timeout, topo, pKey, pVal);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char c = 0;
|
|
||||||
string command;
|
|
||||||
TerminalConfig tconfig;
|
|
||||||
|
|
||||||
printControlsHelp();
|
|
||||||
cin >> c;
|
|
||||||
command = c;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
handleCommand(command, path, timeout, topo, pKey, pVal);
|
|
||||||
} catch(exception& e) {
|
|
||||||
cout << "Error: " << e.what() << endl;
|
|
||||||
}
|
|
||||||
cin >> c;
|
|
||||||
command = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
try {
|
|
||||||
string sessionID;
|
|
||||||
string topoFile;
|
|
||||||
|
|
||||||
string command;
|
|
||||||
string path;
|
|
||||||
string targetState;
|
|
||||||
string pKey;
|
|
||||||
string pVal;
|
|
||||||
unsigned int timeout = 0;
|
|
||||||
|
|
||||||
fair::Logger::SetConsoleSeverity("debug");
|
|
||||||
fair::Logger::SetConsoleColor(true);
|
|
||||||
|
|
||||||
bpo::options_description options("Common options");
|
|
||||||
|
|
||||||
auto envSessionId = getenv("DDS_SESSION_ID");
|
|
||||||
if (envSessionId) {
|
|
||||||
options.add_options()("session,s", bpo::value<string>(&sessionID)->default_value(envSessionId), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
|
||||||
} else {
|
|
||||||
options.add_options()("session,s", bpo::value<string>(&sessionID)->required(), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto envTopoFile = getenv("FAIRMQ_DDS_TOPO_FILE");
|
|
||||||
if (envTopoFile) {
|
|
||||||
options.add_options()("topology-file,f", bpo::value<string>(&topoFile)->default_value(envTopoFile), "DDS topology file path");
|
|
||||||
} else {
|
|
||||||
options.add_options()("topology-file,f", bpo::value<string>(&topoFile)->required(), "DDS topology file path");
|
|
||||||
}
|
|
||||||
|
|
||||||
options.add_options()
|
|
||||||
("command,c", bpo::value<string>(&command)->default_value(""), "Command character")
|
|
||||||
("path,p", bpo::value<string>(&path)->default_value(""), "DDS Topology path to send command to (empty - send to all tasks)")
|
|
||||||
("property-key", bpo::value<string>(&pKey)->default_value(""), "property key to be used with 'p' command")
|
|
||||||
("property-value", bpo::value<string>(&pVal)->default_value(""), "property value to be used with 'p' command")
|
|
||||||
("wait-for-state,w", bpo::value<string>(&targetState)->default_value(""), "Wait until targeted FairMQ devices reach the given state")
|
|
||||||
("timeout,t", bpo::value<unsigned int>(&timeout)->default_value(0), "Timeout in milliseconds when waiting for a device state (0 - wait infinitely)")
|
|
||||||
("help,h", "Produce help message");
|
|
||||||
|
|
||||||
bpo::variables_map vm;
|
|
||||||
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
|
|
||||||
|
|
||||||
if (vm.count("help")) {
|
|
||||||
cout << "FairMQ DDS Command UI" << endl << options << endl;
|
|
||||||
cout << "Commands: [c] check state, [o] dump config, [h] help, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device, [k] complete init, [b] bind, [x] connect, [p] set property" << endl;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
bpo::notify(vm);
|
|
||||||
|
|
||||||
DDSEnvironment env;
|
|
||||||
DDSSession session(sessionID, env);
|
|
||||||
DDSTopology ddsTopo(DDSTopology::Path(topoFile), env);
|
|
||||||
|
|
||||||
Topology topo(ddsTopo, session, true);
|
|
||||||
|
|
||||||
if (!targetState.empty()) {
|
|
||||||
if (!command.empty()) {
|
|
||||||
sendCommand(command, path, timeout, topo, pKey, pVal);
|
|
||||||
}
|
|
||||||
size_t pos = targetState.find("->");
|
|
||||||
cout << "> waiting for " << (path.empty() ? "all" : path) << " to reach " << targetState << endl;
|
|
||||||
if (pos == string::npos) {
|
|
||||||
/* auto ec = */topo.WaitForState(GetState(targetState), path, std::chrono::milliseconds(timeout));
|
|
||||||
// cout << "WaitForState(" << targetState << ") result: " << ec.message() << endl;
|
|
||||||
} else {
|
|
||||||
/* auto ec = */topo.WaitForState(GetState(targetState.substr(0, pos)), GetState(targetState.substr(pos + 2)), path, std::chrono::milliseconds(timeout));
|
|
||||||
// cout << "WaitForState(" << targetState << ") result: " << ec.message() << endl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendCommand(command, path, timeout, topo, pKey, pVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
} catch (exception& e) {
|
|
||||||
cerr << "Error: " << e.what() << endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
# Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||||
# #
|
# #
|
||||||
# This software is distributed under the terms of the #
|
# This software is distributed under the terms of the #
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||||
|
@ -292,56 +292,3 @@ add_testsuite(MemoryResources
|
||||||
TIMEOUT 5
|
TIMEOUT 5
|
||||||
${definitions}
|
${definitions}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(BUILD_SDK)
|
|
||||||
# configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sdk/test_topo.xml
|
|
||||||
# ${CMAKE_BINARY_DIR}/test_topo.xml)
|
|
||||||
# add_testsuite(SDK
|
|
||||||
# SOURCES
|
|
||||||
# ${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
|
||||||
# sdk/_async_op.cxx
|
|
||||||
# sdk/_dds.cxx
|
|
||||||
# sdk/_topology.cxx
|
|
||||||
# sdk/Fixtures.h
|
|
||||||
#
|
|
||||||
# LINKS
|
|
||||||
# SDK
|
|
||||||
# Tools
|
|
||||||
# DDS::dds_topology_lib
|
|
||||||
# DDS::dds_tools_lib
|
|
||||||
# INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
# ${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
# TIMEOUT 30
|
|
||||||
# ${definitions}
|
|
||||||
# )
|
|
||||||
|
|
||||||
if(DDS_TESTS)
|
|
||||||
foreach(i RANGE 1 ${DDS_TESTS})
|
|
||||||
add_test(NAME DDSToolsAPIStabilityTest_${i}
|
|
||||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/testsuite_SDK --gtest_filter=TopologyHelper.MakeTopology --gtest_also_run_disabled_tests
|
|
||||||
)
|
|
||||||
set_tests_properties(DDSToolsAPIStabilityTest_${i} PROPERTIES TIMEOUT 10)
|
|
||||||
endforeach()
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DDSToolsAPIStabilityTest.cmake.in
|
|
||||||
${CMAKE_BINARY_DIR}/DDSToolsAPIStabilityTest.cmake
|
|
||||||
@ONLY
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_SDK_COMMANDS)
|
|
||||||
add_testsuite(Commands
|
|
||||||
SOURCES
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
|
||||||
commands/_commands.cxx
|
|
||||||
|
|
||||||
LINKS
|
|
||||||
Commands
|
|
||||||
StateMachine
|
|
||||||
Tools
|
|
||||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
TIMEOUT 30
|
|
||||||
${definitions}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
################################################################################
|
|
||||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
|
||||||
# #
|
|
||||||
# This software is distributed under the terms of the #
|
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
|
||||||
# copied verbatim in the file "LICENSE" #
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
include(@CMAKE_SOURCE_DIR@/CTestConfig.cmake)
|
|
||||||
|
|
||||||
cmake_host_system_information(RESULT fqdn QUERY FQDN)
|
|
||||||
set(CTEST_SITE ${fqdn})
|
|
||||||
set(CTEST_BUILD_NAME "@CMAKE_SYSTEM@ - @CMAKE_CXX_COMPILER_ID@ @CMAKE_CXX_COMPILER_VERSION@ - DDS Stability Test (@DDS_TESTS@ iterations, DDS: @DDS_VERSION@, FairMQ: @PROJECT_GIT_VERSION@, Boost: @Boost_VERSION@)")
|
|
||||||
set(CTEST_SOURCE_DIRECTORY @CMAKE_SOURCE_DIR@)
|
|
||||||
set(CTEST_BINARY_DIRECTORY @CMAKE_BINARY_DIR@)
|
|
||||||
file(REMOVE_RECURSE ${CTEST_BINARY_DIRECTORY}/test/.DDS)
|
|
||||||
|
|
||||||
ctest_start(Experimental)
|
|
||||||
ctest_test(INCLUDE "DDSToolsAPIStabilityTest")
|
|
||||||
ctest_submit()
|
|
||||||
|
|
||||||
set(dds_logs @CMAKE_BINARY_DIR@/dds_logs.tar.gz)
|
|
||||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar "cfvz" "${dds_logs}" "@CMAKE_BINARY_DIR@/test/.DDS" OUTPUT_QUIET)
|
|
||||||
message("DDS logs packed: ${dds_logs}")
|
|
|
@ -1,241 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <fairmq/sdk/commands/Commands.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace fair::mq;
|
|
||||||
using namespace fair::mq::sdk::cmd;
|
|
||||||
|
|
||||||
TEST(Format, Construction)
|
|
||||||
{
|
|
||||||
auto const props(std::vector<std::pair<std::string, std::string>>({{"k1", "v1"}, {"k2", "v2"}}));
|
|
||||||
|
|
||||||
Cmds checkStateCmds(make<CheckState>());
|
|
||||||
Cmds changeStateCmds(make<ChangeState>(Transition::Stop));
|
|
||||||
Cmds dumpConfigCmds(make<DumpConfig>());
|
|
||||||
Cmds subscribeToStateChangeCmds(make<SubscribeToStateChange>(60000));
|
|
||||||
Cmds unsubscribeFromStateChangeCmds(make<UnsubscribeFromStateChange>());
|
|
||||||
Cmds stateChangeExitingReceivedCmds(make<StateChangeExitingReceived>());
|
|
||||||
Cmds getPropertiesCmds(make<GetProperties>(66, "k[12]"));
|
|
||||||
Cmds setPropertiesCmds(make<SetProperties>(42, props));
|
|
||||||
Cmds subscriptionHeartbeatCmds(make<SubscriptionHeartbeat>(60000));
|
|
||||||
Cmds currentStateCmds(make<CurrentState>("somedeviceid", State::Running));
|
|
||||||
Cmds transitionStatusCmds(make<TransitionStatus>("somedeviceid", 123456, Result::Ok, Transition::Stop, State::Running));
|
|
||||||
Cmds configCmds(make<Config>("somedeviceid", "someconfig"));
|
|
||||||
Cmds stateChangeSubscriptionCmds(make<StateChangeSubscription>("somedeviceid", 123456, Result::Ok));
|
|
||||||
Cmds stateChangeUnsubscriptionCmds(make<StateChangeUnsubscription>("somedeviceid", 123456, Result::Ok));
|
|
||||||
Cmds stateChangeCmds(make<StateChange>("somedeviceid", 123456, State::Running, State::Ready));
|
|
||||||
Cmds propertiesCmds(make<Properties>("somedeviceid", 66, Result::Ok, props));
|
|
||||||
Cmds propertiesSetCmds(make<PropertiesSet>("somedeviceid", 42, Result::Ok));
|
|
||||||
|
|
||||||
ASSERT_EQ(checkStateCmds.At(0).GetType(), Type::check_state);
|
|
||||||
ASSERT_EQ(changeStateCmds.At(0).GetType(), Type::change_state);
|
|
||||||
ASSERT_EQ(static_cast<ChangeState&>(changeStateCmds.At(0)).GetTransition(), Transition::Stop);
|
|
||||||
ASSERT_EQ(dumpConfigCmds.At(0).GetType(), Type::dump_config);
|
|
||||||
ASSERT_EQ(subscribeToStateChangeCmds.At(0).GetType(), Type::subscribe_to_state_change);
|
|
||||||
ASSERT_EQ(static_cast<SubscribeToStateChange&>(subscribeToStateChangeCmds.At(0)).GetInterval(), 60000);
|
|
||||||
ASSERT_EQ(unsubscribeFromStateChangeCmds.At(0).GetType(), Type::unsubscribe_from_state_change);
|
|
||||||
ASSERT_EQ(stateChangeExitingReceivedCmds.At(0).GetType(), Type::state_change_exiting_received);
|
|
||||||
ASSERT_EQ(getPropertiesCmds.At(0).GetType(), Type::get_properties);
|
|
||||||
ASSERT_EQ(static_cast<GetProperties&>(getPropertiesCmds.At(0)).GetRequestId(), 66);
|
|
||||||
ASSERT_EQ(static_cast<GetProperties&>(getPropertiesCmds.At(0)).GetQuery(), "k[12]");
|
|
||||||
ASSERT_EQ(setPropertiesCmds.At(0).GetType(), Type::set_properties);
|
|
||||||
ASSERT_EQ(static_cast<SetProperties&>(setPropertiesCmds.At(0)).GetRequestId(), 42);
|
|
||||||
ASSERT_EQ(static_cast<SetProperties&>(setPropertiesCmds.At(0)).GetProps(), props);
|
|
||||||
ASSERT_EQ(subscriptionHeartbeatCmds.At(0).GetType(), Type::subscription_heartbeat);
|
|
||||||
ASSERT_EQ(static_cast<SubscriptionHeartbeat&>(subscriptionHeartbeatCmds.At(0)).GetInterval(), 60000);
|
|
||||||
ASSERT_EQ(currentStateCmds.At(0).GetType(), Type::current_state);
|
|
||||||
ASSERT_EQ(static_cast<CurrentState&>(currentStateCmds.At(0)).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<CurrentState&>(currentStateCmds.At(0)).GetCurrentState(), State::Running);
|
|
||||||
ASSERT_EQ(transitionStatusCmds.At(0).GetType(), Type::transition_status);
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(transitionStatusCmds.At(0)).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(transitionStatusCmds.At(0)).GetTaskId(), 123456);
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(transitionStatusCmds.At(0)).GetResult(), Result::Ok);
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(transitionStatusCmds.At(0)).GetTransition(), Transition::Stop);
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(transitionStatusCmds.At(0)).GetCurrentState(), State::Running);
|
|
||||||
ASSERT_EQ(configCmds.At(0).GetType(), Type::config);
|
|
||||||
ASSERT_EQ(static_cast<Config&>(configCmds.At(0)).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<Config&>(configCmds.At(0)).GetConfig(), "someconfig");
|
|
||||||
ASSERT_EQ(stateChangeSubscriptionCmds.At(0).GetType(), Type::state_change_subscription);
|
|
||||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(stateChangeSubscriptionCmds.At(0)).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(stateChangeSubscriptionCmds.At(0)).GetTaskId(), 123456);
|
|
||||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(stateChangeSubscriptionCmds.At(0)).GetResult(), Result::Ok);
|
|
||||||
ASSERT_EQ(stateChangeUnsubscriptionCmds.At(0).GetType(), Type::state_change_unsubscription);
|
|
||||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(stateChangeUnsubscriptionCmds.At(0)).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(stateChangeUnsubscriptionCmds.At(0)).GetTaskId(), 123456);
|
|
||||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(stateChangeUnsubscriptionCmds.At(0)).GetResult(), Result::Ok);
|
|
||||||
ASSERT_EQ(stateChangeCmds.At(0).GetType(), Type::state_change);
|
|
||||||
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetTaskId(), 123456);
|
|
||||||
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetLastState(), State::Running);
|
|
||||||
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetCurrentState(), State::Ready);
|
|
||||||
ASSERT_EQ(propertiesCmds.At(0).GetType(), Type::properties);
|
|
||||||
ASSERT_EQ(static_cast<Properties&>(propertiesCmds.At(0)).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<Properties&>(propertiesCmds.At(0)).GetRequestId(), 66);
|
|
||||||
ASSERT_EQ(static_cast<Properties&>(propertiesCmds.At(0)).GetResult(), Result::Ok);
|
|
||||||
ASSERT_EQ(static_cast<Properties&>(propertiesCmds.At(0)).GetProps(), props);
|
|
||||||
ASSERT_EQ(propertiesSetCmds.At(0).GetType(), Type::properties_set);
|
|
||||||
ASSERT_EQ(static_cast<PropertiesSet&>(propertiesSetCmds.At(0)).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<PropertiesSet&>(propertiesSetCmds.At(0)).GetRequestId(), 42);
|
|
||||||
ASSERT_EQ(static_cast<PropertiesSet&>(propertiesSetCmds.At(0)).GetResult(), Result::Ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fillCommands(Cmds& cmds)
|
|
||||||
{
|
|
||||||
auto const props(std::vector<std::pair<std::string, std::string>>({{"k1", "v1"}, {"k2", "v2"}}));
|
|
||||||
|
|
||||||
cmds.Add<CheckState>();
|
|
||||||
cmds.Add<ChangeState>(Transition::Stop);
|
|
||||||
cmds.Add<DumpConfig>();
|
|
||||||
cmds.Add<SubscribeToStateChange>(60000);
|
|
||||||
cmds.Add<UnsubscribeFromStateChange>();
|
|
||||||
cmds.Add<StateChangeExitingReceived>();
|
|
||||||
cmds.Add<GetProperties>(66, "k[12]");
|
|
||||||
cmds.Add<SetProperties>(42, props);
|
|
||||||
cmds.Add<SubscriptionHeartbeat>(60000);
|
|
||||||
cmds.Add<CurrentState>("somedeviceid", State::Running);
|
|
||||||
cmds.Add<TransitionStatus>("somedeviceid", 123456, Result::Ok, Transition::Stop, State::Running);
|
|
||||||
cmds.Add<Config>("somedeviceid", "someconfig");
|
|
||||||
cmds.Add<StateChangeSubscription>("somedeviceid", 123456, Result::Ok);
|
|
||||||
cmds.Add<StateChangeUnsubscription>("somedeviceid", 123456, Result::Ok);
|
|
||||||
cmds.Add<StateChange>("somedeviceid", 123456, State::Running, State::Ready);
|
|
||||||
cmds.Add<Properties>("somedeviceid", 66, Result::Ok, props);
|
|
||||||
cmds.Add<PropertiesSet>("somedeviceid", 42, Result::Ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkCommands(Cmds& cmds)
|
|
||||||
{
|
|
||||||
ASSERT_EQ(cmds.Size(), 17);
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
auto const props(std::vector<std::pair<std::string, std::string>>({{"k1", "v1"}, {"k2", "v2"}}));
|
|
||||||
|
|
||||||
for (const auto& cmd : cmds) {
|
|
||||||
switch (cmd->GetType()) {
|
|
||||||
case Type::check_state:
|
|
||||||
++count;
|
|
||||||
break;
|
|
||||||
case Type::change_state:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<ChangeState&>(*cmd).GetTransition(), Transition::Stop);
|
|
||||||
break;
|
|
||||||
case Type::dump_config:
|
|
||||||
++count;
|
|
||||||
break;
|
|
||||||
case Type::subscribe_to_state_change:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<SubscribeToStateChange&>(*cmd).GetInterval(), 60000);
|
|
||||||
break;
|
|
||||||
case Type::unsubscribe_from_state_change:
|
|
||||||
++count;
|
|
||||||
break;
|
|
||||||
case Type::state_change_exiting_received:
|
|
||||||
++count;
|
|
||||||
break;
|
|
||||||
case Type::get_properties:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<GetProperties&>(*cmd).GetRequestId(), 66);
|
|
||||||
ASSERT_EQ(static_cast<GetProperties&>(*cmd).GetQuery(), "k[12]");
|
|
||||||
break;
|
|
||||||
case Type::set_properties:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<SetProperties&>(*cmd).GetRequestId(), 42);
|
|
||||||
ASSERT_EQ(static_cast<SetProperties&>(*cmd).GetProps(), props);
|
|
||||||
break;
|
|
||||||
case Type::subscription_heartbeat:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<SubscriptionHeartbeat&>(*cmd).GetInterval(), 60000);
|
|
||||||
break;
|
|
||||||
case Type::current_state:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<CurrentState&>(*cmd).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<CurrentState&>(*cmd).GetCurrentState(), State::Running);
|
|
||||||
break;
|
|
||||||
case Type::transition_status:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(*cmd).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(*cmd).GetTaskId(), 123456);
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(*cmd).GetResult(), Result::Ok);
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(*cmd).GetTransition(), Transition::Stop);
|
|
||||||
ASSERT_EQ(static_cast<TransitionStatus&>(*cmd).GetCurrentState(), State::Running);
|
|
||||||
break;
|
|
||||||
case Type::config:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<Config&>(*cmd).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<Config&>(*cmd).GetConfig(), "someconfig");
|
|
||||||
break;
|
|
||||||
case Type::state_change_subscription:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(*cmd).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(*cmd).GetTaskId(), 123456);
|
|
||||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(*cmd).GetResult(), Result::Ok);
|
|
||||||
break;
|
|
||||||
case Type::state_change_unsubscription:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(*cmd).GetTaskId(), 123456);
|
|
||||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(*cmd).GetResult(), Result::Ok);
|
|
||||||
break;
|
|
||||||
case Type::state_change:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<StateChange&>(*cmd).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<StateChange&>(*cmd).GetTaskId(), 123456);
|
|
||||||
ASSERT_EQ(static_cast<StateChange&>(*cmd).GetLastState(), State::Running);
|
|
||||||
ASSERT_EQ(static_cast<StateChange&>(*cmd).GetCurrentState(), State::Ready);
|
|
||||||
break;
|
|
||||||
case Type::properties:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<Properties&>(*cmd).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<Properties&>(*cmd).GetRequestId(), 66);
|
|
||||||
ASSERT_EQ(static_cast<Properties&>(*cmd).GetResult(), Result::Ok);
|
|
||||||
ASSERT_EQ(static_cast<Properties&>(*cmd).GetProps(), props);
|
|
||||||
break;
|
|
||||||
case Type::properties_set:
|
|
||||||
++count;
|
|
||||||
ASSERT_EQ(static_cast<PropertiesSet&>(*cmd).GetDeviceId(), "somedeviceid");
|
|
||||||
ASSERT_EQ(static_cast<PropertiesSet&>(*cmd).GetRequestId(), 42);
|
|
||||||
ASSERT_EQ(static_cast<PropertiesSet&>(*cmd).GetResult(), Result::Ok);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ASSERT_TRUE(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(count, 17);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Format, SerializationBinary)
|
|
||||||
{
|
|
||||||
Cmds outCmds;
|
|
||||||
fillCommands(outCmds);
|
|
||||||
std::string buffer(outCmds.Serialize());
|
|
||||||
|
|
||||||
Cmds inCmds;
|
|
||||||
inCmds.Deserialize(buffer);
|
|
||||||
checkCommands(inCmds);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Format, SerializationJSON)
|
|
||||||
{
|
|
||||||
Cmds outCmds;
|
|
||||||
fillCommands(outCmds);
|
|
||||||
std::string buffer(outCmds.Serialize(Format::JSON));
|
|
||||||
|
|
||||||
Cmds inCmds;
|
|
||||||
inCmds.Deserialize(buffer, Format::JSON);
|
|
||||||
checkCommands(inCmds);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
|
@ -1,169 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FAIR_MQ_TEST_FIXTURES
|
|
||||||
#define FAIR_MQ_TEST_FIXTURES
|
|
||||||
|
|
||||||
#include "TestEnvironment.h"
|
|
||||||
|
|
||||||
#include <fairmq/SDK.h>
|
|
||||||
#include <fairmq/tools/Strings.h>
|
|
||||||
|
|
||||||
#include <fairlogger/Logger.h>
|
|
||||||
|
|
||||||
#include <asio/io_context.hpp>
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
#include <algorithm> // for_each
|
|
||||||
#include <array>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace fair::mq::test
|
|
||||||
{
|
|
||||||
|
|
||||||
struct LoggerConfig
|
|
||||||
{
|
|
||||||
LoggerConfig()
|
|
||||||
{
|
|
||||||
Logger::SetConsoleSeverity("debug");
|
|
||||||
Logger::DefineVerbosity("user1",
|
|
||||||
fair::VerbositySpec::Make(VerbositySpec::Info::timestamp_us,
|
|
||||||
VerbositySpec::Info::severity));
|
|
||||||
Logger::SetVerbosity("user1");
|
|
||||||
Logger::SetConsoleColor();
|
|
||||||
|
|
||||||
std::string path(std::getenv("PATH"));
|
|
||||||
path = tools::ToString(FAIRMQ_TEST_ENVIRONMENT, ":", path);
|
|
||||||
setenv("PATH", path.c_str(), 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TopologyFixture : ::testing::Test
|
|
||||||
{
|
|
||||||
TopologyFixture()
|
|
||||||
: mDDSTopoFile(tools::ToString(SDK_TESTSUITE_SOURCE_DIR, "/test_topo.xml"))
|
|
||||||
, mDDSEnv(CMAKE_CURRENT_BINARY_DIR)
|
|
||||||
, mDDSSession(mDDSEnv)
|
|
||||||
, mDDSTopo(sdk::DDSTopology::Path(mDDSTopoFile), mDDSEnv)
|
|
||||||
{
|
|
||||||
mDDSSession.StopOnDestruction();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SetUp() -> void override {
|
|
||||||
LOG(info) << mDDSEnv;
|
|
||||||
LOG(info) << mDDSSession;
|
|
||||||
LOG(info) << mDDSTopo;
|
|
||||||
auto n(mDDSTopo.GetNumRequiredAgents());
|
|
||||||
mDDSSession.SubmitAgents(n);
|
|
||||||
mDDSSession.ActivateTopology(mDDSTopo);
|
|
||||||
|
|
||||||
std::vector<sdk::DDSAgent> agents = mDDSSession.RequestAgentInfo();
|
|
||||||
LOG(debug) << "##### AgentInfo:";
|
|
||||||
LOG(debug) << "size: " << agents.size();
|
|
||||||
for (const auto& a : agents) {
|
|
||||||
LOG(debug) << a;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<sdk::DDSTask> tasks = mDDSSession.RequestTaskInfo();
|
|
||||||
LOG(debug) << "##### TaskInfo:";
|
|
||||||
LOG(debug) << "size: " << tasks.size();
|
|
||||||
for (const auto& t : tasks) {
|
|
||||||
LOG(debug) << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<sdk::DDSCollection> collections = mDDSTopo.GetCollections();
|
|
||||||
LOG(debug) << "##### CollectionInfo:";
|
|
||||||
LOG(debug) << "size: " << collections.size();
|
|
||||||
for (const auto& c : collections) {
|
|
||||||
LOG(debug) << c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto TearDown() -> void override {}
|
|
||||||
|
|
||||||
LoggerConfig mLoggerConfig;
|
|
||||||
std::string mDDSTopoFile;
|
|
||||||
sdk::DDSEnvironment mDDSEnv;
|
|
||||||
sdk::DDSSession mDDSSession;
|
|
||||||
sdk::DDSTopology mDDSTopo;
|
|
||||||
asio::io_context mIoContext;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MultipleTopologiesFixture : ::testing::Test
|
|
||||||
{
|
|
||||||
MultipleTopologiesFixture()
|
|
||||||
: mDDSTopoFile(tools::ToString(SDK_TESTSUITE_SOURCE_DIR, "/test_topo.xml"))
|
|
||||||
, mDDSEnv(CMAKE_CURRENT_BINARY_DIR)
|
|
||||||
, mDDSSessions{ sdk::DDSSession(mDDSEnv),
|
|
||||||
sdk::DDSSession(mDDSEnv) }
|
|
||||||
, mDDSTopologies{ sdk::DDSTopology(sdk::DDSTopology::Path(mDDSTopoFile), mDDSEnv),
|
|
||||||
sdk::DDSTopology(sdk::DDSTopology::Path(mDDSTopoFile), mDDSEnv) }
|
|
||||||
{
|
|
||||||
std::for_each(mDDSSessions.begin(), mDDSSessions.end(), [](sdk::DDSSession& s) {
|
|
||||||
s.StopOnDestruction();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SetUp() -> void override
|
|
||||||
{
|
|
||||||
LOG(info) << mDDSEnv;
|
|
||||||
for (int i = 0; i < mNumSessions; ++i) {
|
|
||||||
LOG(info) << "##### SESSION " << i << " #####";
|
|
||||||
LOG(info) << mDDSSessions[i];
|
|
||||||
LOG(info) << mDDSTopologies[i];
|
|
||||||
auto n(mDDSTopologies[i].GetNumRequiredAgents());
|
|
||||||
mDDSSessions[i].SubmitAgents(n);
|
|
||||||
mDDSSessions[i].ActivateTopology(mDDSTopologies[i]);
|
|
||||||
|
|
||||||
std::vector<sdk::DDSAgent> agents = mDDSSessions[i].RequestAgentInfo();
|
|
||||||
LOG(info) << "##### AgentInfo:";
|
|
||||||
LOG(info) << "size: " << agents.size();
|
|
||||||
for (const auto& a : agents) {
|
|
||||||
LOG(info) << a;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<sdk::DDSTask> tasks = mDDSSessions[i].RequestTaskInfo();
|
|
||||||
LOG(info) << "##### TaskInfo:";
|
|
||||||
LOG(info) << "size: " << tasks.size();
|
|
||||||
for (const auto& t : tasks) {
|
|
||||||
LOG(info) << t;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<sdk::DDSCollection> collections = mDDSTopologies[i].GetCollections();
|
|
||||||
LOG(info) << "##### CollectionInfo:";
|
|
||||||
LOG(info) << "size: " << collections.size();
|
|
||||||
for (const auto& c : collections) {
|
|
||||||
LOG(info) << c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto TearDown() -> void override {}
|
|
||||||
|
|
||||||
static constexpr int mNumSessions = 2;
|
|
||||||
LoggerConfig mLoggerConfig;
|
|
||||||
std::string mDDSTopoFile;
|
|
||||||
sdk::DDSEnvironment mDDSEnv;
|
|
||||||
std::array<sdk::DDSSession, mNumSessions> mDDSSessions;
|
|
||||||
std::array<sdk::DDSTopology, mNumSessions> mDDSTopologies;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AsyncOpFixture : ::testing::Test
|
|
||||||
{
|
|
||||||
auto SetUp() -> void override {}
|
|
||||||
auto TearDown() -> void override {}
|
|
||||||
|
|
||||||
LoggerConfig mLoggerConfig;
|
|
||||||
asio::io_context mIoContext;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace fair::mq::test
|
|
||||||
|
|
||||||
#endif /* FAIR_MQ_TEST_FIXTURES */
|
|
|
@ -1,118 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "Fixtures.h"
|
|
||||||
|
|
||||||
#include <fairmq/sdk/AsioBase.h>
|
|
||||||
#include <fairmq/sdk/AsioAsyncOp.h>
|
|
||||||
#include <asio/steady_timer.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using AsyncOp = fair::mq::test::AsyncOpFixture;
|
|
||||||
|
|
||||||
// template <typename Executor, typename Allocator>
|
|
||||||
// class : public AsioBase<Executor, Allocator>
|
|
||||||
|
|
||||||
TEST_F(AsyncOp, DefaultConstruction)
|
|
||||||
{
|
|
||||||
using namespace fair::mq::sdk;
|
|
||||||
|
|
||||||
AsioAsyncOp<DefaultExecutor, DefaultAllocator, void(std::error_code, int)> op;
|
|
||||||
EXPECT_TRUE(op.IsCompleted());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncOp, ConstructionWithHandler)
|
|
||||||
{
|
|
||||||
using namespace fair::mq::sdk;
|
|
||||||
|
|
||||||
AsioAsyncOp<DefaultExecutor, DefaultAllocator, void(std::error_code, int)> op(
|
|
||||||
[](std::error_code, int) {});
|
|
||||||
EXPECT_FALSE(op.IsCompleted());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncOp, Complete)
|
|
||||||
{
|
|
||||||
using namespace fair::mq::sdk;
|
|
||||||
|
|
||||||
AsioAsyncOp<DefaultExecutor, DefaultAllocator, void(std::error_code, int)> op(
|
|
||||||
[](std::error_code ec, int v) {
|
|
||||||
EXPECT_FALSE(ec); // success
|
|
||||||
EXPECT_EQ(v, 42);
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_FALSE(op.IsCompleted());
|
|
||||||
op.Complete(42);
|
|
||||||
EXPECT_TRUE(op.IsCompleted());
|
|
||||||
|
|
||||||
EXPECT_THROW(op.Complete(6), RuntimeError); // No double completion!
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncOp, Cancel)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
sdk::AsioAsyncOp<sdk::DefaultExecutor, sdk::DefaultAllocator, void(std::error_code)> op(
|
|
||||||
[](std::error_code ec) {
|
|
||||||
EXPECT_TRUE(ec); // error
|
|
||||||
EXPECT_EQ(ec, MakeErrorCode(ErrorCode::OperationCanceled));
|
|
||||||
});
|
|
||||||
|
|
||||||
op.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncOp, Timeout)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
asio::steady_timer timer(mIoContext.get_executor(), std::chrono::milliseconds(50));
|
|
||||||
sdk::AsioAsyncOp<sdk::DefaultExecutor, sdk::DefaultAllocator, void(std::error_code)> op(
|
|
||||||
mIoContext.get_executor(),
|
|
||||||
[&timer](std::error_code ec) {
|
|
||||||
timer.cancel();
|
|
||||||
std::cout << "Completion with: " << ec.message() << std::endl;
|
|
||||||
EXPECT_TRUE(ec); // error
|
|
||||||
EXPECT_EQ(ec, MakeErrorCode(ErrorCode::OperationTimeout));
|
|
||||||
});
|
|
||||||
timer.async_wait([&op](asio::error_code ec) {
|
|
||||||
std::cout << "Timer event" << std::endl;
|
|
||||||
if (ec != asio::error::operation_aborted) {
|
|
||||||
op.Timeout();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mIoContext.run();
|
|
||||||
EXPECT_THROW(op.Complete(), sdk::RuntimeError);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncOp, Timeout2)
|
|
||||||
{
|
|
||||||
using namespace fair::mq::sdk;
|
|
||||||
|
|
||||||
asio::steady_timer timer(mIoContext.get_executor(), std::chrono::milliseconds(50));
|
|
||||||
AsioAsyncOp<DefaultExecutor, DefaultAllocator, void(std::error_code)> op(
|
|
||||||
mIoContext.get_executor(),
|
|
||||||
[&timer](std::error_code ec) {
|
|
||||||
timer.cancel();
|
|
||||||
std::cout << "Completion with: " << ec.message() << std::endl;
|
|
||||||
EXPECT_FALSE(ec); // success
|
|
||||||
});
|
|
||||||
op.Complete(); // Complete before timer
|
|
||||||
timer.async_wait([&op](asio::error_code ec) {
|
|
||||||
std::cout << "Timer event" << std::endl;
|
|
||||||
if (ec != asio::error::operation_aborted) {
|
|
||||||
op.Timeout();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mIoContext.run();
|
|
||||||
EXPECT_THROW(op.Complete(), RuntimeError);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
|
@ -1,50 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "Fixtures.h"
|
|
||||||
|
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <dds/dds.h>
|
|
||||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
TEST(DDSEnvironment, Construction)
|
|
||||||
{
|
|
||||||
fair::mq::test::LoggerConfig cfg;
|
|
||||||
fair::mq::sdk::DDSEnvironment env(CMAKE_CURRENT_BINARY_DIR);
|
|
||||||
|
|
||||||
LOG(debug) << env;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DDSSession, Construction)
|
|
||||||
{
|
|
||||||
fair::mq::test::LoggerConfig cfg;
|
|
||||||
fair::mq::sdk::DDSEnvironment env(CMAKE_CURRENT_BINARY_DIR);
|
|
||||||
|
|
||||||
fair::mq::sdk::DDSSession session(env);
|
|
||||||
session.StopOnDestruction();
|
|
||||||
LOG(debug) << session;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DDSSession, Construction2)
|
|
||||||
{
|
|
||||||
fair::mq::test::LoggerConfig cfg;
|
|
||||||
fair::mq::sdk::DDSEnvironment env(CMAKE_CURRENT_BINARY_DIR);
|
|
||||||
|
|
||||||
auto nativeSession(std::make_shared<dds::tools_api::CSession>());
|
|
||||||
nativeSession->create();
|
|
||||||
|
|
||||||
fair::mq::sdk::DDSSession session(nativeSession, env);
|
|
||||||
session.StopOnDestruction();
|
|
||||||
LOG(debug) << session;
|
|
||||||
|
|
||||||
session.RequestCommanderInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
|
@ -1,589 +0,0 @@
|
||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
|
||||||
* *
|
|
||||||
* This software is distributed under the terms of the *
|
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
|
||||||
* copied verbatim in the file "LICENSE" *
|
|
||||||
********************************************************************************/
|
|
||||||
|
|
||||||
#include "Fixtures.h"
|
|
||||||
|
|
||||||
#include <asio.hpp>
|
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <dds/dds.h>
|
|
||||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
|
||||||
#include <fairmq/sdk/Topology.h>
|
|
||||||
#include <fairmq/tools/Strings.h>
|
|
||||||
#include <fairmq/tools/Semaphore.h>
|
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using Topology = fair::mq::test::TopologyFixture;
|
|
||||||
using MultipleTopologies = fair::mq::test::MultipleTopologiesFixture;
|
|
||||||
|
|
||||||
void control(fair::mq::sdk::Topology& topo)
|
|
||||||
{
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
for (auto transition : {TopologyTransition::InitDevice,
|
|
||||||
TopologyTransition::CompleteInit,
|
|
||||||
TopologyTransition::Bind,
|
|
||||||
TopologyTransition::Connect,
|
|
||||||
TopologyTransition::InitTask,
|
|
||||||
TopologyTransition::Run,
|
|
||||||
TopologyTransition::Stop,
|
|
||||||
TopologyTransition::ResetTask,
|
|
||||||
TopologyTransition::ResetDevice,
|
|
||||||
TopologyTransition::End}) {
|
|
||||||
ASSERT_EQ(topo.ChangeState(transition).first, std::error_code());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TopologyHelper, MakeTopology)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
// This is only needed for this unit test
|
|
||||||
test::LoggerConfig cfg;
|
|
||||||
sdk::DDSEnv env(CMAKE_CURRENT_BINARY_DIR);
|
|
||||||
|
|
||||||
std::string topoFile(tools::ToString(SDK_TESTSUITE_SOURCE_DIR, "/test_topo.xml"));
|
|
||||||
dds::topology_api::CTopology nativeTopo(topoFile);
|
|
||||||
auto nativeSession(std::make_shared<dds::tools_api::CSession>());
|
|
||||||
nativeSession->create();
|
|
||||||
EXPECT_THROW(sdk::MakeTopology(nativeTopo, nativeSession, env), sdk::RuntimeError);
|
|
||||||
nativeSession->shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(MultipleTopologies, Construction)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
std::array<sdk::Topology, mNumSessions> topos{
|
|
||||||
sdk::Topology(mDDSTopologies[0], mDDSSessions[0]),
|
|
||||||
sdk::Topology(mDDSTopologies[1], mDDSSessions[1])
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(MultipleTopologies, ChangeStateFullDeviceLifecycle)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
std::array<sdk::Topology, mNumSessions> topos{
|
|
||||||
sdk::Topology(mDDSTopologies[0], mDDSSessions[0]),
|
|
||||||
sdk::Topology(mDDSTopologies[1], mDDSSessions[1])
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; i < mNumSessions; ++i) {
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
for (auto transition : {TopologyTransition::InitDevice,
|
|
||||||
TopologyTransition::CompleteInit,
|
|
||||||
TopologyTransition::Bind,
|
|
||||||
TopologyTransition::Connect,
|
|
||||||
TopologyTransition::InitTask,
|
|
||||||
TopologyTransition::Run,
|
|
||||||
TopologyTransition::Stop,
|
|
||||||
TopologyTransition::ResetTask,
|
|
||||||
TopologyTransition::ResetDevice,
|
|
||||||
TopologyTransition::End}) {
|
|
||||||
ASSERT_EQ(topos[i].ChangeState(transition).first, std::error_code());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(MultipleTopologies, ChangeStateFullDeviceLifecycleConcurrent)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
std::array<sdk::Topology, mNumSessions> topos{
|
|
||||||
sdk::Topology(mDDSTopologies[0], mDDSSessions[0]),
|
|
||||||
sdk::Topology(mDDSTopologies[1], mDDSSessions[1])
|
|
||||||
};
|
|
||||||
|
|
||||||
std::thread t0(control, std::ref(topos[0]));
|
|
||||||
std::thread t1(control, std::ref(topos[1]));
|
|
||||||
t0.join();
|
|
||||||
t1.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST_F(Topology, Construction)
|
|
||||||
{
|
|
||||||
fair::mq::sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, Construction2)
|
|
||||||
{
|
|
||||||
fair::mq::sdk::Topology topo(mIoContext.get_executor(), mDDSTopo, mDDSSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, AsyncChangeState)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
tools::SharedSemaphore blocker;
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
topo.AsyncChangeState(
|
|
||||||
sdk::TopologyTransition::InitDevice,
|
|
||||||
[=](std::error_code ec, sdk::TopologyState) mutable {
|
|
||||||
LOG(info) << ec;
|
|
||||||
EXPECT_EQ(ec, std::error_code());
|
|
||||||
blocker.Signal();
|
|
||||||
});
|
|
||||||
blocker.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, AsyncChangeStateWithCustomExecutor)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
sdk::Topology topo(mIoContext.get_executor(), mDDSTopo, mDDSSession);
|
|
||||||
topo.AsyncChangeState(
|
|
||||||
sdk::TopologyTransition::InitDevice,
|
|
||||||
[](std::error_code ec, sdk::TopologyState) {
|
|
||||||
LOG(info) << ec;
|
|
||||||
EXPECT_EQ(ec, std::error_code());
|
|
||||||
});
|
|
||||||
|
|
||||||
mIoContext.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, AsyncChangeStateFuture)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
sdk::Topology topo(mIoContext.get_executor(), mDDSTopo, mDDSSession);
|
|
||||||
auto fut(topo.AsyncChangeState(
|
|
||||||
sdk::TopologyTransition::InitDevice,
|
|
||||||
asio::use_future));
|
|
||||||
std::thread t([&]() { mIoContext.run(); });
|
|
||||||
bool success(false);
|
|
||||||
|
|
||||||
try {
|
|
||||||
sdk::TopologyState state = fut.get();
|
|
||||||
success = true;
|
|
||||||
} catch (const std::system_error& ex) {
|
|
||||||
LOG(error) << ex.what();
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPECT_TRUE(success);
|
|
||||||
t.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(ASIO_HAS_CO_AWAIT)
|
|
||||||
TEST_F(Topology, AsyncChangeStateCoroutine)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
bool success(false);
|
|
||||||
asio::co_spawn(
|
|
||||||
mIoContext.get_executor(),
|
|
||||||
[&]() mutable -> asio::awaitable<void> {
|
|
||||||
auto executor = co_await asio::this_coro::executor;
|
|
||||||
sdk::Topology topo(executor, mDDSTopo, mDDSSession);
|
|
||||||
try {
|
|
||||||
sdk::TopologyState state = co_await topo.AsyncChangeState(
|
|
||||||
sdk::TopologyTransition::InitDevice, asio::use_awaitable);
|
|
||||||
success = true;
|
|
||||||
} catch (const std::system_error& ex) {
|
|
||||||
LOG(error) << ex.what();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
asio::detached);
|
|
||||||
|
|
||||||
mIoContext.run();
|
|
||||||
EXPECT_TRUE(success);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST_F(Topology, ChangeState)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
auto result(topo.ChangeState(sdk::TopologyTransition::InitDevice));
|
|
||||||
LOG(info) << result.first;
|
|
||||||
|
|
||||||
EXPECT_EQ(result.first, std::error_code());
|
|
||||||
EXPECT_NO_THROW(sdk::AggregateState(result.second));
|
|
||||||
EXPECT_EQ(sdk::StateEqualsTo(result.second, sdk::DeviceState::InitializingDevice), true);
|
|
||||||
auto const currentState = topo.GetCurrentState();
|
|
||||||
EXPECT_NO_THROW(sdk::AggregateState(currentState));
|
|
||||||
EXPECT_EQ(sdk::StateEqualsTo(currentState, sdk::DeviceState::InitializingDevice), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, MixedState)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
auto result1(topo.ChangeState(sdk::TopologyTransition::InitDevice, "main/Sampler.*"));
|
|
||||||
LOG(info) << result1.first;
|
|
||||||
|
|
||||||
EXPECT_EQ(result1.first, std::error_code());
|
|
||||||
EXPECT_EQ(sdk::AggregateState(result1.second), sdk::AggregatedTopologyState::Mixed);
|
|
||||||
EXPECT_EQ(sdk::StateEqualsTo(result1.second, sdk::DeviceState::InitializingDevice), false);
|
|
||||||
auto const currentState1 = topo.GetCurrentState();
|
|
||||||
EXPECT_EQ(sdk::AggregateState(currentState1), sdk::AggregatedTopologyState::Mixed);
|
|
||||||
EXPECT_EQ(sdk::StateEqualsTo(currentState1, sdk::DeviceState::InitializingDevice), false);
|
|
||||||
|
|
||||||
auto result2(topo.ChangeState(sdk::TopologyTransition::InitDevice, "main/SinkGroup/.*"));
|
|
||||||
LOG(info) << result2.first;
|
|
||||||
|
|
||||||
EXPECT_EQ(result2.first, std::error_code());
|
|
||||||
EXPECT_EQ(sdk::AggregateState(result2.second), sdk::AggregatedTopologyState::InitializingDevice);
|
|
||||||
EXPECT_EQ(sdk::StateEqualsTo(result2.second, sdk::DeviceState::InitializingDevice), true);
|
|
||||||
auto const currentState2 = topo.GetCurrentState();
|
|
||||||
EXPECT_EQ(sdk::AggregateState(currentState2), sdk::AggregatedTopologyState::InitializingDevice);
|
|
||||||
EXPECT_EQ(sdk::StateEqualsTo(currentState2, sdk::DeviceState::InitializingDevice), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, AsyncChangeStateConcurrent)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
topo.AsyncChangeState(sdk::TopologyTransition::InitDevice, "main/Sampler.*",
|
|
||||||
[](std::error_code ec, sdk::TopologyState) mutable {
|
|
||||||
LOG(info) << "ChangeState for Sampler: " << ec;
|
|
||||||
EXPECT_EQ(ec, std::error_code());
|
|
||||||
});
|
|
||||||
topo.AsyncChangeState(sdk::TopologyTransition::InitDevice, "main/SinkGroup/.*",
|
|
||||||
[](std::error_code ec, sdk::TopologyState) mutable {
|
|
||||||
LOG(info) << "ChangeState for Sinks: " << ec;
|
|
||||||
EXPECT_EQ(ec, std::error_code());
|
|
||||||
});
|
|
||||||
|
|
||||||
topo.WaitForState(sdk::DeviceState::InitializingDevice);
|
|
||||||
auto const currentState = topo.GetCurrentState();
|
|
||||||
EXPECT_NO_THROW(sdk::AggregateState(currentState));
|
|
||||||
EXPECT_EQ(sdk::StateEqualsTo(currentState, sdk::DeviceState::InitializingDevice), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, AsyncChangeStateTimeout)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
sdk::Topology topo(mIoContext.get_executor(), mDDSTopo, mDDSSession);
|
|
||||||
topo.AsyncChangeState(sdk::TopologyTransition::InitDevice,
|
|
||||||
std::chrono::milliseconds(1),
|
|
||||||
[](std::error_code ec, sdk::TopologyState) {
|
|
||||||
LOG(info) << ec;
|
|
||||||
EXPECT_EQ(ec, MakeErrorCode(ErrorCode::OperationTimeout));
|
|
||||||
});
|
|
||||||
|
|
||||||
mIoContext.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, AsyncChangeStateCollectionView)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
tools::SharedSemaphore blocker;
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
topo.AsyncChangeState(
|
|
||||||
sdk::TopologyTransition::InitDevice,
|
|
||||||
[=](std::error_code ec, sdk::TopologyState state) mutable {
|
|
||||||
LOG(info) << ec;
|
|
||||||
sdk::TopologyStateByCollection cstate(sdk::GroupByCollectionId(state));
|
|
||||||
LOG(debug) << "num collections: " << cstate.size();
|
|
||||||
ASSERT_EQ(cstate.size(), 5);
|
|
||||||
for (const auto& c : cstate) {
|
|
||||||
LOG(debug) << "\t" << c.first;
|
|
||||||
sdk::AggregatedTopologyState s;
|
|
||||||
ASSERT_NO_THROW(s = sdk::AggregateState(c.second));
|
|
||||||
ASSERT_EQ(s, static_cast<sdk::AggregatedTopologyState>(State::InitializingDevice));
|
|
||||||
LOG(debug) << "\tAggregated state: " << s;
|
|
||||||
for (const auto& ds : c.second) {
|
|
||||||
LOG(debug) << "\t\t" << ds.state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPECT_EQ(ec, std::error_code());
|
|
||||||
blocker.Signal();
|
|
||||||
});
|
|
||||||
blocker.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, ChangeStateFullDeviceLifecycle)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
for (auto transition : {TopologyTransition::InitDevice,
|
|
||||||
TopologyTransition::CompleteInit,
|
|
||||||
TopologyTransition::Bind,
|
|
||||||
TopologyTransition::Connect,
|
|
||||||
TopologyTransition::InitTask,
|
|
||||||
TopologyTransition::Run,
|
|
||||||
TopologyTransition::Stop,
|
|
||||||
TopologyTransition::ResetTask,
|
|
||||||
TopologyTransition::ResetDevice,
|
|
||||||
TopologyTransition::End}) {
|
|
||||||
ASSERT_EQ(topo.ChangeState(transition).first, std::error_code());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, WaitForStateFullDeviceLifecycle)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
topo.AsyncWaitForState(sdk::DeviceState::ResettingDevice, [](std::error_code ec){
|
|
||||||
ASSERT_EQ(ec, std::error_code());
|
|
||||||
});
|
|
||||||
for (auto transition : {TopologyTransition::InitDevice,
|
|
||||||
TopologyTransition::CompleteInit,
|
|
||||||
TopologyTransition::Bind,
|
|
||||||
TopologyTransition::Connect,
|
|
||||||
TopologyTransition::InitTask,
|
|
||||||
TopologyTransition::Run,
|
|
||||||
TopologyTransition::Stop,
|
|
||||||
TopologyTransition::ResetTask,
|
|
||||||
TopologyTransition::ResetDevice,
|
|
||||||
TopologyTransition::End}) {
|
|
||||||
topo.ChangeState(transition);
|
|
||||||
ASSERT_EQ(topo.WaitForState(sdk::expectedState.at(transition)), std::error_code());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, ChangeStateFullDeviceLifecycle2)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
for (int i(0); i < 10; ++i) {
|
|
||||||
for (auto transition : {TopologyTransition::InitDevice,
|
|
||||||
TopologyTransition::CompleteInit,
|
|
||||||
TopologyTransition::Bind,
|
|
||||||
TopologyTransition::Connect,
|
|
||||||
TopologyTransition::InitTask,
|
|
||||||
TopologyTransition::Run}) {
|
|
||||||
ASSERT_EQ(topo.ChangeState(transition).first, std::error_code());
|
|
||||||
}
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
||||||
for (auto transition : {TopologyTransition::Stop,
|
|
||||||
TopologyTransition::ResetTask,
|
|
||||||
TopologyTransition::ResetDevice}) {
|
|
||||||
ASSERT_EQ(topo.ChangeState(transition).first, std::error_code());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, SetProperties)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::InitDevice).first, std::error_code());
|
|
||||||
|
|
||||||
auto const result1 = topo.SetProperties({{"key1", "val1"}});
|
|
||||||
LOG(info) << result1.first;
|
|
||||||
ASSERT_EQ(result1.first, std::error_code());
|
|
||||||
ASSERT_EQ(result1.second.size(), 0);
|
|
||||||
auto const result2 = topo.SetProperties({{"key2", "val2"}, {"key3", "val3"}});
|
|
||||||
LOG(info) << result2.first;
|
|
||||||
ASSERT_EQ(result2.first, std::error_code());
|
|
||||||
ASSERT_EQ(result2.second.size(), 0);
|
|
||||||
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::CompleteInit).first, std::error_code());
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::ResetDevice).first, std::error_code());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, AsyncSetPropertiesConcurrent)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::InitDevice).first, std::error_code());
|
|
||||||
|
|
||||||
tools::SharedSemaphore blocker(2);
|
|
||||||
topo.AsyncSetProperties(
|
|
||||||
{{"key1", "val1"}},
|
|
||||||
[=](std::error_code ec, sdk::FailedDevices failed) mutable {
|
|
||||||
LOG(info) << ec;
|
|
||||||
ASSERT_EQ(ec, std::error_code());
|
|
||||||
ASSERT_EQ(failed.size(), 0);
|
|
||||||
blocker.Signal();
|
|
||||||
});
|
|
||||||
topo.AsyncSetProperties(
|
|
||||||
{{"key2", "val2"}, {"key3", "val3"}},
|
|
||||||
[=](std::error_code ec, sdk::FailedDevices failed) mutable {
|
|
||||||
LOG(info) << ec;
|
|
||||||
ASSERT_EQ(ec, std::error_code());
|
|
||||||
ASSERT_EQ(failed.size(), 0);
|
|
||||||
blocker.Signal();
|
|
||||||
});
|
|
||||||
blocker.Wait();
|
|
||||||
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::CompleteInit).first, std::error_code());
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::ResetDevice).first, std::error_code());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, AsyncSetPropertiesTimeout)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::InitDevice).first, std::error_code());
|
|
||||||
|
|
||||||
topo.AsyncSetProperties({{"key1", "val1"}},
|
|
||||||
"",
|
|
||||||
std::chrono::microseconds(1),
|
|
||||||
[=](std::error_code ec, sdk::FailedDevices) mutable {
|
|
||||||
LOG(info) << ec;
|
|
||||||
EXPECT_EQ(ec, MakeErrorCode(ErrorCode::OperationTimeout));
|
|
||||||
});
|
|
||||||
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::CompleteInit).first, std::error_code());
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::ResetDevice).first, std::error_code());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, SetPropertiesMixed)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::InitDevice).first, std::error_code());
|
|
||||||
|
|
||||||
tools::SharedSemaphore blocker;
|
|
||||||
topo.AsyncSetProperties(
|
|
||||||
{{"key1", "val1"}},
|
|
||||||
[=](std::error_code ec, sdk::FailedDevices failed) mutable {
|
|
||||||
LOG(info) << ec;
|
|
||||||
ASSERT_EQ(ec, std::error_code());
|
|
||||||
ASSERT_EQ(failed.size(), 0);
|
|
||||||
blocker.Signal();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto result = topo.SetProperties({{"key2", "val2"}});
|
|
||||||
LOG(info) << result.first;
|
|
||||||
ASSERT_EQ(result.first, std::error_code());
|
|
||||||
ASSERT_EQ(result.second.size(), 0);
|
|
||||||
|
|
||||||
blocker.Wait();
|
|
||||||
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::CompleteInit).first, std::error_code());
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::ResetDevice).first, std::error_code());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, GetProperties)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::InitDevice).first, std::error_code());
|
|
||||||
|
|
||||||
auto const result = topo.GetProperties("^(session|id)$");
|
|
||||||
LOG(info) << result.first;
|
|
||||||
ASSERT_EQ(result.first, std::error_code());
|
|
||||||
ASSERT_EQ(result.second.failed.size(), 0);
|
|
||||||
for (auto const& d : result.second.devices) {
|
|
||||||
LOG(info) << d.first;
|
|
||||||
ASSERT_EQ(d.second.props.size(), 2);
|
|
||||||
for (auto const& p : d.second.props) {
|
|
||||||
LOG(info) << p.first << " : " << p.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::CompleteInit).first, std::error_code());
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::ResetDevice).first, std::error_code());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(Topology, SetAndGetProperties)
|
|
||||||
{
|
|
||||||
using namespace fair::mq;
|
|
||||||
using fair::mq::sdk::TopologyTransition;
|
|
||||||
|
|
||||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::InitDevice).first, std::error_code());
|
|
||||||
|
|
||||||
sdk::DeviceProperties const props{{"key1", "val1"}, {"key2", "val2"}};
|
|
||||||
|
|
||||||
auto const result1 = topo.SetProperties(props);
|
|
||||||
LOG(info) << result1.first;
|
|
||||||
ASSERT_EQ(result1.first, std::error_code());
|
|
||||||
ASSERT_EQ(result1.second.size(), 0);
|
|
||||||
|
|
||||||
auto const result2 = topo.GetProperties("^key.*");
|
|
||||||
LOG(info) << result2.first;
|
|
||||||
ASSERT_EQ(result2.first, std::error_code());
|
|
||||||
ASSERT_EQ(result2.second.failed.size(), 0);
|
|
||||||
ASSERT_EQ(result2.second.devices.size(), 6);
|
|
||||||
for (auto const& d : result2.second.devices) {
|
|
||||||
ASSERT_EQ(d.second.props, props);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::CompleteInit).first, std::error_code());
|
|
||||||
ASSERT_EQ(topo.ChangeState(TopologyTransition::ResetDevice).first, std::error_code());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Topology2, AggregatedTopologyStateComparison)
|
|
||||||
{
|
|
||||||
using namespace fair::mq::sdk;
|
|
||||||
ASSERT_TRUE(DeviceState::Undefined == AggregatedTopologyState::Undefined);
|
|
||||||
ASSERT_TRUE(AggregatedTopologyState::Undefined == DeviceState::Undefined);
|
|
||||||
ASSERT_TRUE(DeviceState::Ok == AggregatedTopologyState::Ok);
|
|
||||||
ASSERT_TRUE(DeviceState::Error == AggregatedTopologyState::Error);
|
|
||||||
ASSERT_TRUE(DeviceState::Idle == AggregatedTopologyState::Idle);
|
|
||||||
ASSERT_TRUE(DeviceState::InitializingDevice == AggregatedTopologyState::InitializingDevice);
|
|
||||||
ASSERT_TRUE(DeviceState::Initialized == AggregatedTopologyState::Initialized);
|
|
||||||
ASSERT_TRUE(DeviceState::Binding == AggregatedTopologyState::Binding);
|
|
||||||
ASSERT_TRUE(DeviceState::Bound == AggregatedTopologyState::Bound);
|
|
||||||
ASSERT_TRUE(DeviceState::Connecting == AggregatedTopologyState::Connecting);
|
|
||||||
ASSERT_TRUE(DeviceState::DeviceReady == AggregatedTopologyState::DeviceReady);
|
|
||||||
ASSERT_TRUE(DeviceState::InitializingTask == AggregatedTopologyState::InitializingTask);
|
|
||||||
ASSERT_TRUE(DeviceState::Ready == AggregatedTopologyState::Ready);
|
|
||||||
ASSERT_TRUE(DeviceState::Running == AggregatedTopologyState::Running);
|
|
||||||
ASSERT_TRUE(DeviceState::ResettingTask == AggregatedTopologyState::ResettingTask);
|
|
||||||
ASSERT_TRUE(DeviceState::ResettingDevice == AggregatedTopologyState::ResettingDevice);
|
|
||||||
ASSERT_TRUE(DeviceState::Exiting == AggregatedTopologyState::Exiting);
|
|
||||||
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("UNDEFINED") == AggregatedTopologyState::Undefined);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("OK") == AggregatedTopologyState::Ok);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("ERROR") == AggregatedTopologyState::Error);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("IDLE") == AggregatedTopologyState::Idle);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("INITIALIZING DEVICE") == AggregatedTopologyState::InitializingDevice);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("INITIALIZED") == AggregatedTopologyState::Initialized);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("BINDING") == AggregatedTopologyState::Binding);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("BOUND") == AggregatedTopologyState::Bound);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("CONNECTING") == AggregatedTopologyState::Connecting);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("DEVICE READY") == AggregatedTopologyState::DeviceReady);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("INITIALIZING TASK") == AggregatedTopologyState::InitializingTask);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("READY") == AggregatedTopologyState::Ready);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("RUNNING") == AggregatedTopologyState::Running);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("RESETTING TASK") == AggregatedTopologyState::ResettingTask);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("RESETTING DEVICE") == AggregatedTopologyState::ResettingDevice);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("EXITING") == AggregatedTopologyState::Exiting);
|
|
||||||
ASSERT_TRUE(GetAggregatedTopologyState("MIXED") == AggregatedTopologyState::Mixed);
|
|
||||||
|
|
||||||
ASSERT_TRUE("UNDEFINED" == GetAggregatedTopologyStateName(AggregatedTopologyState::Undefined));
|
|
||||||
ASSERT_TRUE("OK" == GetAggregatedTopologyStateName(AggregatedTopologyState::Ok));
|
|
||||||
ASSERT_TRUE("ERROR" == GetAggregatedTopologyStateName(AggregatedTopologyState::Error));
|
|
||||||
ASSERT_TRUE("IDLE" == GetAggregatedTopologyStateName(AggregatedTopologyState::Idle));
|
|
||||||
ASSERT_TRUE("INITIALIZING DEVICE" == GetAggregatedTopologyStateName(AggregatedTopologyState::InitializingDevice));
|
|
||||||
ASSERT_TRUE("INITIALIZED" == GetAggregatedTopologyStateName(AggregatedTopologyState::Initialized));
|
|
||||||
ASSERT_TRUE("BINDING" == GetAggregatedTopologyStateName(AggregatedTopologyState::Binding));
|
|
||||||
ASSERT_TRUE("BOUND" == GetAggregatedTopologyStateName(AggregatedTopologyState::Bound));
|
|
||||||
ASSERT_TRUE("CONNECTING" == GetAggregatedTopologyStateName(AggregatedTopologyState::Connecting));
|
|
||||||
ASSERT_TRUE("DEVICE READY" == GetAggregatedTopologyStateName(AggregatedTopologyState::DeviceReady));
|
|
||||||
ASSERT_TRUE("INITIALIZING TASK" == GetAggregatedTopologyStateName(AggregatedTopologyState::InitializingTask));
|
|
||||||
ASSERT_TRUE("READY" == GetAggregatedTopologyStateName(AggregatedTopologyState::Ready));
|
|
||||||
ASSERT_TRUE("RUNNING" == GetAggregatedTopologyStateName(AggregatedTopologyState::Running));
|
|
||||||
ASSERT_TRUE("RESETTING TASK" == GetAggregatedTopologyStateName(AggregatedTopologyState::ResettingTask));
|
|
||||||
ASSERT_TRUE("RESETTING DEVICE" == GetAggregatedTopologyStateName(AggregatedTopologyState::ResettingDevice));
|
|
||||||
ASSERT_TRUE("EXITING" == GetAggregatedTopologyStateName(AggregatedTopologyState::Exiting));
|
|
||||||
ASSERT_TRUE("MIXED" == GetAggregatedTopologyStateName(AggregatedTopologyState::Mixed));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
|
@ -1,42 +0,0 @@
|
||||||
<topology name="sdk-test-topo">
|
|
||||||
|
|
||||||
<property name="fmqchan_data" />
|
|
||||||
|
|
||||||
<declrequirement name="SamplerWorker" type="wnname" value="sampler"/>
|
|
||||||
<declrequirement name="SinkWorker" type="wnname" value="sink"/>
|
|
||||||
|
|
||||||
<decltask name="Sampler">
|
|
||||||
<exe reachable="true">fairmq-bsampler --color false --channel-config name=data,type=push,method=bind -P dds --msg-rate 10 --severity trace --verbosity veryhigh</exe>
|
|
||||||
<requirements>
|
|
||||||
<name>SamplerWorker</name>
|
|
||||||
</requirements>
|
|
||||||
<properties>
|
|
||||||
<name access="write">fmqchan_data</name>
|
|
||||||
</properties>
|
|
||||||
</decltask>
|
|
||||||
|
|
||||||
<decltask name="Sink">
|
|
||||||
<exe reachable="true">fairmq-sink --color false --channel-config name=data,type=pull,method=connect -P dds --severity trace --verbosity veryhigh</exe>
|
|
||||||
<requirements>
|
|
||||||
<name>SinkWorker</name>
|
|
||||||
</requirements>
|
|
||||||
<properties>
|
|
||||||
<name access="read">fmqchan_data</name>
|
|
||||||
</properties>
|
|
||||||
</decltask>
|
|
||||||
|
|
||||||
<declcollection name="Sinks">
|
|
||||||
<tasks>
|
|
||||||
<name>Sink</name>
|
|
||||||
</tasks>
|
|
||||||
</declcollection>
|
|
||||||
|
|
||||||
<main name="main">
|
|
||||||
<task>Sampler</task>
|
|
||||||
<group name="SinkGroup" n="5">
|
|
||||||
<collection>Sinks</collection>
|
|
||||||
</group>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
</topology>
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user