diff --git a/agent_lib/CMakeLists.txt b/agent_lib/CMakeLists.txt index edde309c..2c099e7a 100644 --- a/agent_lib/CMakeLists.txt +++ b/agent_lib/CMakeLists.txt @@ -1,445 +1,447 @@ -set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../src/mtconnect") - -set(AGENT_SOURCES - # src HEADER_FILE_ONLY - - "${SOURCE_DIR}/agent.hpp" - "${SOURCE_DIR}/config.hpp" - "${SOURCE_DIR}/logging.hpp" - "${SOURCE_DIR}/utilities.hpp" - -# src SOURCE_FILES_ONLY - - "${SOURCE_DIR}/agent.cpp" - "${SOURCE_DIR}/utilities.cpp" - "${SOURCE_DIR}/version.cpp" - - -# src/asset HEADER_FILE_ONLY - - "${SOURCE_DIR}/asset/asset.hpp" - "${SOURCE_DIR}/asset/asset_buffer.hpp" - "${SOURCE_DIR}/asset/asset_storage.hpp" - "${SOURCE_DIR}/asset/cutting_tool.hpp" - "${SOURCE_DIR}/asset/file_asset.hpp" - "${SOURCE_DIR}/asset/raw_material.hpp" - "${SOURCE_DIR}/asset/qif_document.hpp" - "${SOURCE_DIR}/asset/component_configuration_parameters.hpp" - -# src/asset SOURCE_FILES_ONLY - - "${SOURCE_DIR}/asset/asset.cpp" - "${SOURCE_DIR}/asset/cutting_tool.cpp" - "${SOURCE_DIR}/asset/file_asset.cpp" - "${SOURCE_DIR}/asset/raw_material.cpp" - "${SOURCE_DIR}/asset/qif_document.cpp" - "${SOURCE_DIR}/asset/component_configuration_parameters.cpp" - -# src/buffer HEADER_FILES_ONLY - - "${SOURCE_DIR}/buffer/checkpoint.hpp" - "${SOURCE_DIR}/buffer/circular_buffer.hpp" - -# src/buffer SOURCE_FILES_ONLY - - "${SOURCE_DIR}/buffer/checkpoint.cpp" - -# src/configuration HEADER_FILE_ONLY - - "${SOURCE_DIR}/configuration/agent_config.hpp" - "${SOURCE_DIR}/configuration/async_context.hpp" - "${SOURCE_DIR}/configuration/config_options.hpp" - "${SOURCE_DIR}/configuration/hook_manager.hpp" - "${SOURCE_DIR}/configuration/parser.hpp" - "${SOURCE_DIR}/configuration/service.hpp" - -# src/configuration SOURCE_FILES_ONLY - - "${SOURCE_DIR}/configuration/agent_config.cpp" - "${SOURCE_DIR}/configuration/parser.cpp" - "${SOURCE_DIR}/configuration/service.cpp" - -# src/device_model HEADER_FILE_ONLY - - "${SOURCE_DIR}/device_model/agent_device.hpp" - "${SOURCE_DIR}/device_model/component.hpp" - "${SOURCE_DIR}/device_model/composition.hpp" - "${SOURCE_DIR}/device_model/description.hpp" - "${SOURCE_DIR}/device_model/device.hpp" - "${SOURCE_DIR}/device_model/reference.hpp" - -# src/device_model SOURCE_FILES_ONLY - - "${SOURCE_DIR}/device_model/agent_device.cpp" - "${SOURCE_DIR}/device_model/component.cpp" - "${SOURCE_DIR}/device_model/composition.cpp" - "${SOURCE_DIR}/device_model/description.cpp" - "${SOURCE_DIR}/device_model/device.cpp" - "${SOURCE_DIR}/device_model/reference.cpp" - -# src/device_model/configuration HEADER_FILE_ONLY - - "${SOURCE_DIR}/device_model/configuration/configuration.hpp" - "${SOURCE_DIR}/device_model/configuration/coordinate_systems.hpp" - "${SOURCE_DIR}/device_model/configuration/image_file.hpp" - "${SOURCE_DIR}/device_model/configuration/motion.hpp" - "${SOURCE_DIR}/device_model/configuration/relationships.hpp" - "${SOURCE_DIR}/device_model/configuration/sensor_configuration.hpp" - "${SOURCE_DIR}/device_model/configuration/solid_model.hpp" - "${SOURCE_DIR}/device_model/configuration/specifications.hpp" - -# src/device_model/configuration SOURCE_FILES_ONLY - - "${SOURCE_DIR}/device_model/configuration/configuration.cpp" - "${SOURCE_DIR}/device_model/configuration/coordinate_systems.cpp" - "${SOURCE_DIR}/device_model/configuration/image_file.cpp" - "${SOURCE_DIR}/device_model/configuration/motion.cpp" - "${SOURCE_DIR}/device_model/configuration/relationships.cpp" - "${SOURCE_DIR}/device_model/configuration/sensor_configuration.cpp" - "${SOURCE_DIR}/device_model/configuration/solid_model.cpp" - "${SOURCE_DIR}/device_model/configuration/specifications.cpp" - -# src/device_model/data_item HEADER_FILE_ONLY - - "${SOURCE_DIR}/device_model/data_item/constraints.hpp" - "${SOURCE_DIR}/device_model/data_item/data_item.hpp" - "${SOURCE_DIR}/device_model/data_item/definition.hpp" - "${SOURCE_DIR}/device_model/data_item/filter.hpp" - "${SOURCE_DIR}/device_model/data_item/relationships.hpp" - "${SOURCE_DIR}/device_model/data_item/source.hpp" - "${SOURCE_DIR}/device_model/data_item/unit_conversion.hpp" - -# src/device_model/data_item SOURCE_FILES_ONLY - - "${SOURCE_DIR}/device_model/data_item/data_item.cpp" - "${SOURCE_DIR}/device_model/data_item/unit_conversion.cpp" - -# src/entity HEADER_FILE_ONLY - - "${SOURCE_DIR}/entity/data_set.hpp" - "${SOURCE_DIR}/entity/entity.hpp" - "${SOURCE_DIR}/entity/factory.hpp" - "${SOURCE_DIR}/entity/json_parser.hpp" - "${SOURCE_DIR}/entity/json_printer.hpp" - "${SOURCE_DIR}/entity/qname.hpp" - "${SOURCE_DIR}/entity/requirement.hpp" - "${SOURCE_DIR}/entity/xml_parser.hpp" - "${SOURCE_DIR}/entity/xml_printer.hpp" - -# src/entity SOURCE_FILES_ONLY - - "${SOURCE_DIR}/entity/data_set.cpp" - "${SOURCE_DIR}/entity/entity.cpp" - "${SOURCE_DIR}/entity/factory.cpp" - "${SOURCE_DIR}/entity/json_parser.cpp" - "${SOURCE_DIR}/entity/requirement.cpp" - "${SOURCE_DIR}/entity/xml_parser.cpp" - "${SOURCE_DIR}/entity/xml_printer.cpp" - -# src/mqtt HEADER_FILE_ONLY - - "${SOURCE_DIR}/mqtt/mqtt_authorization.hpp" - "${SOURCE_DIR}/mqtt/mqtt_client.hpp" - "${SOURCE_DIR}/mqtt/mqtt_server.hpp" - "${SOURCE_DIR}/mqtt/mqtt_client_impl.hpp" - "${SOURCE_DIR}/mqtt/mqtt_server_impl.hpp" - -# src/observation HEADER_FILE_ONLY - - "${SOURCE_DIR}/observation/change_observer.hpp" - "${SOURCE_DIR}/observation/observation.hpp" - -#src/observation SOURCE_FILES_ONLY - - "${SOURCE_DIR}/observation/change_observer.cpp" - "${SOURCE_DIR}/observation/observation.cpp" - -# src/parser HEADER_FILE_ONLY - - "${SOURCE_DIR}/parser/xml_parser.hpp" - -# src/parser SOURCE_FILES_ONLY - - "${SOURCE_DIR}/parser/xml_parser.cpp" - -# src/pipeline HEADER_FILE_ONLY - - "${SOURCE_DIR}/pipeline/convert_sample.hpp" - "${SOURCE_DIR}/pipeline/deliver.hpp" - "${SOURCE_DIR}/pipeline/delta_filter.hpp" - "${SOURCE_DIR}/pipeline/duplicate_filter.hpp" - "${SOURCE_DIR}/pipeline/guard.hpp" - "${SOURCE_DIR}/pipeline/message_mapper.hpp" - "${SOURCE_DIR}/pipeline/mtconnect_xml_transform.hpp" - "${SOURCE_DIR}/pipeline/period_filter.hpp" - "${SOURCE_DIR}/pipeline/pipeline.hpp" - "${SOURCE_DIR}/pipeline/pipeline_context.hpp" - "${SOURCE_DIR}/pipeline/pipeline_contract.hpp" - "${SOURCE_DIR}/pipeline/response_document.hpp" - "${SOURCE_DIR}/pipeline/shdr_token_mapper.hpp" - "${SOURCE_DIR}/pipeline/shdr_tokenizer.hpp" - "${SOURCE_DIR}/pipeline/timestamp_extractor.hpp" - "${SOURCE_DIR}/pipeline/topic_mapper.hpp" - "${SOURCE_DIR}/pipeline/transform.hpp" - "${SOURCE_DIR}/pipeline/upcase_value.hpp" - -# src/pipeline SOURCE_FILES_ONLY - - "${SOURCE_DIR}/pipeline/deliver.cpp" - "${SOURCE_DIR}/pipeline/shdr_token_mapper.cpp" - "${SOURCE_DIR}/pipeline/timestamp_extractor.cpp" - "${SOURCE_DIR}/pipeline/response_document.cpp" - -# src/printer HEADER_FILE_ONLY - - "${SOURCE_DIR}/printer/json_printer.hpp" - "${SOURCE_DIR}/printer/json_printer_helper.hpp" - "${SOURCE_DIR}/printer/printer.hpp" - "${SOURCE_DIR}/printer/xml_helper.hpp" - "${SOURCE_DIR}/printer/xml_printer.hpp" - "${SOURCE_DIR}/printer/xml_printer_helper.hpp" - -# src/printer SOURCE_FILES_ONLY - - "${SOURCE_DIR}/printer/xml_printer.cpp" - "${SOURCE_DIR}/printer/json_printer.cpp" - -# src/source HEADER_FILE_ONLY - - "${SOURCE_DIR}/source/adapter/adapter.hpp" - "${SOURCE_DIR}/source/adapter/adapter_pipeline.hpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/agent_adapter.hpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/http_session.hpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/https_session.hpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/session.hpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/session_impl.hpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/url_parser.hpp" - "${SOURCE_DIR}/source/adapter/mqtt/mqtt_adapter.hpp" - "${SOURCE_DIR}/source/adapter/shdr/connector.hpp" - "${SOURCE_DIR}/source/adapter/shdr/shdr_adapter.hpp" - "${SOURCE_DIR}/source/adapter/shdr/shdr_pipeline.hpp" - "${SOURCE_DIR}/source/error_code.hpp" - "${SOURCE_DIR}/source/loopback_source.hpp" - "${SOURCE_DIR}/source/source.hpp" - -# src/source SOURCE_FILES_ONLY - - "${SOURCE_DIR}/source/adapter/adapter_pipeline.cpp" - "${SOURCE_DIR}/source/adapter/mqtt/mqtt_adapter.cpp" - "${SOURCE_DIR}/source/adapter/shdr/connector.cpp" - "${SOURCE_DIR}/source/adapter/shdr/shdr_adapter.cpp" - "${SOURCE_DIR}/source/adapter/shdr/shdr_pipeline.cpp" - "${SOURCE_DIR}/source/loopback_source.cpp" - "${SOURCE_DIR}/source/source.cpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/agent_adapter.cpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/url_parser.cpp" - -# src/sink HEADER_FILE_ONLY - - "${SOURCE_DIR}/sink/sink.hpp" - -# src/sink SOURCE_FILE_ONLY - - "${SOURCE_DIR}/sink/sink.cpp" - -# src/sink/mqtt_sink HEADER_FILE_ONLY - - "${SOURCE_DIR}/sink/mqtt_sink/mqtt_service.hpp" - -#src/sink/mqtt_sink SOURCE_FILES_ONLY - - "${SOURCE_DIR}/sink/mqtt_sink/mqtt_service.cpp" - -# src/sink/rest_sink HEADER_FILE_ONLY - - "${SOURCE_DIR}/sink/rest_sink/cached_file.hpp" - "${SOURCE_DIR}/sink/rest_sink/file_cache.hpp" - "${SOURCE_DIR}/sink/rest_sink/parameter.hpp" - "${SOURCE_DIR}/sink/rest_sink/request.hpp" - "${SOURCE_DIR}/sink/rest_sink/response.hpp" - "${SOURCE_DIR}/sink/rest_sink/rest_service.hpp" - "${SOURCE_DIR}/sink/rest_sink/routing.hpp" - "${SOURCE_DIR}/sink/rest_sink/server.hpp" - "${SOURCE_DIR}/sink/rest_sink/session.hpp" - "${SOURCE_DIR}/sink/rest_sink/session_impl.hpp" - "${SOURCE_DIR}/sink/rest_sink/tls_dector.hpp" - -# src/sink/rest_sink SOURCE_FILES_ONLY - - "${SOURCE_DIR}/sink/rest_sink/file_cache.cpp" - "${SOURCE_DIR}/sink/rest_sink/rest_service.cpp" - "${SOURCE_DIR}/sink/rest_sink/server.cpp" - "${SOURCE_DIR}/sink/rest_sink/session_impl.cpp" - ) - -if(WITH_RUBY) - set(AGENT_SOURCES ${AGENT_SOURCES} -# HEADER_FILE_ONLY - "${SOURCE_DIR}/ruby/embedded.hpp" - "${SOURCE_DIR}/ruby/ruby_agent.hpp" - "${SOURCE_DIR}/ruby/ruby_entity.hpp" - "${SOURCE_DIR}/ruby/ruby_observation.hpp" - "${SOURCE_DIR}/ruby/ruby_pipeline.hpp" - "${SOURCE_DIR}/ruby/ruby_smart_ptr.hpp" - "${SOURCE_DIR}/ruby/ruby_transform.hpp" - "${SOURCE_DIR}/ruby/ruby_type.hpp" - "${SOURCE_DIR}/ruby/ruby_vm.hpp" - -#SOURCE_FILES_ONLY - "${SOURCE_DIR}/ruby/embedded.cpp" - ) -endif() - -find_package(Boost REQUIRED) -find_package(LibXml2 REQUIRED) -find_package(date REQUIRED) -find_package(OpenSSL REQUIRED) -find_package(nlohmann_json REQUIRED) -find_package(mqtt_cpp REQUIRED) -find_package(RapidJSON REQUIRED) - -## configure a header file to pass some of the CMake settings to the source code -configure_file("${SOURCE_DIR}/version.h.in" "${PROJECT_BINARY_DIR}/agent_lib/mtconnect/version.h") - -set(AGENT_LIB_HEADERS ${AGENT_SOURCES}) -list(FILTER AGENT_LIB_HEADERS INCLUDE REGEX "\\.(h|hpp|ipp)$") -set(AGENT_LIB_SOURCES ${AGENT_SOURCES}) -list(FILTER AGENT_LIB_SOURCES INCLUDE REGEX "\\.(c|cpp)$") - -# For IDE Grouping -source_group("Header Files") -source_group("Source Files") -source_group(TREE "${SOURCE_DIR}" PREFIX "Header Files" FILES ${AGENT_LIB_HEADERS}) -source_group(TREE "${SOURCE_DIR}" PREFIX "Source Files" FILES ${AGENT_LIB_SOURCES}) - -if(MSVC) - if(CMAKE_GENERATOR_TOOLSET) - if(${CMAKE_GENERATOR_TOOLSET} MATCHES "v14[01]_xp") - message(info ": Setting /Ob1 for rest_sink/session_impl.cpp") - set_property(SOURCE "${SOURCE_DIR}/sink/rest_sink/session_impl.cpp" - PROPERTY COMPILE_FLAGS "/Ob1") - endif() - endif() - - # The modules including Beast required the /bigobj option in Windows - set_property(SOURCE - "${SOURCE_DIR}/sink/mqtt_sink/mqtt_service.cpp" - "${SOURCE_DIR}/sink/rest_sink/session_impl.cpp" - "${SOURCE_DIR}/source/adapter/mqtt/mqtt_adapter.cpp" - "${SOURCE_DIR}/source/adapter/agent_adapter/agent_adapter.cpp" - "${SOURCE_DIR}/source/adapter/shdr/shdr_pipeline.cpp" - "${SOURCE_DIR}/source/adapter/adapter_pipeline.cpp" - "${SOURCE_DIR}/device_model/component.cpp" - "${SOURCE_DIR}/configuration/agent_config.cpp" - "${SOURCE_DIR}/sink/rest_sink/rest_service.cpp" - "${SOURCE_DIR}/ruby/embedded.cpp" - "${SOURCE_DIR}/pipeline/deliver.cpp" - "${SOURCE_DIR}/agent.cpp" - PROPERTY COMPILE_FLAGS "/bigobj") -endif() - -if(SHARED_AGENT_LIB) - add_library(agent_lib SHARED ${AGENT_SOURCES}) - target_compile_definitions( - agent_lib - PRIVATE - AGENT_BUILD_SHARED_LIB) - target_compile_definitions( - agent_lib - PUBLIC - SHARED_AGENT_LIB) -else() - add_library(agent_lib STATIC ${AGENT_SOURCES}) -endif() - -if(AGENT_PREFIX) - set_target_properties(agent_lib PROPERTIES OUTPUT_NAME "${AGENT_PREFIX}agent_lib") -endif() - -target_include_directories( - agent_lib - PUBLIC - "${CONAN_INCLUDE_DIRS}" - "${PROJECT_BINARY_DIR}/agent_lib" - "${CMAKE_CURRENT_LIST_DIR}/../src" - ) - -target_link_libraries( - agent_lib - PUBLIC - boost::boost LibXml2::LibXml2 date::date-tz openssl::openssl - nlohmann_json::nlohmann_json mqtt_cpp::mqtt_cpp - rapidjson BZip2::BZip2 - - $<$:pthread> - $<$:bcrypt> - ) - -if(WITH_RUBY) - find_package(mruby REQUIRED) - find_package(oniguruma REQUIRED) - target_link_libraries( - agent_lib - PUBLIC - mruby::mruby - oniguruma::onig) -endif() - -target_compile_definitions( - agent_lib - PUBLIC - $<$:APPVEYOR> - $<$:NOMINMAX> - $<$:WINVER=${WINVER}> - $<$:_WIN32_WINNT=${WINVER}> - MQTT_USE_TLS=ON - MQTT_USE_WS=ON - MQTT_USE_STR_CHECK=ON - MQTT_STD_VARIANT - MQTT_STD_OPTIONAL - MQTT_STD_STRING_VIEW - MQTT_USE_LOG - BOOST_FILESYSTEM_VERSION=3 - ) - -if(WITH_PYTHON) - target_compile_definitions( - agent_lib - PUBLIC - WITH_PYTHON ) -endif() - -if(WITH_RUBY) - target_compile_definitions( - agent_lib - PUBLIC - WITH_RUBY ) -endif() - -if(AGENT_WITHOUT_IPV6) - target_compile_definitions( - agent_lib - PUBLIC - AGENT_WITHOUT_IPV6 ) -endif() - -# set_property(SOURCE ${AGENT_SOURCES} PROPERTY COMPILE_FLAGS_DEBUG "${COVERAGE_FLAGS}") -target_compile_features(agent_lib PUBLIC ${CXX_COMPILE_FEATURES}) -target_clangformat_setup(agent_lib) -target_clangtidy_setup(agent_lib) - -include(../cmake/document.cmake) -if (AGENT_WITH_DOCS AND DOXYGEN_FOUND) - doxygen_add_docs(docs ../README.md ${AGENT_SOURCES}) - install(DIRECTORY "${PROJECT_BINARY_DIR}/Documentation/" DESTINATION "Documentation") -endif() - -target_sources(agent_lib PUBLIC FILE_SET headers - TYPE HEADERS - BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../src/" - FILES "${AGENT_LIB_HEADERS}") - -install(TARGETS agent_lib LIBRARY DESTINATION "lib") -install(TARGETS agent_lib ARCHIVE DESTINATION "lib") -install(TARGETS agent_lib FILE_SET headers DESTINATION "include") -install(FILES "${PROJECT_BINARY_DIR}/agent_lib/mtconnect/version.h" DESTINATION "include/mtconnect") +set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../src/mtconnect") + +set(AGENT_SOURCES + # src HEADER_FILE_ONLY + + "${SOURCE_DIR}/agent.hpp" + "${SOURCE_DIR}/config.hpp" + "${SOURCE_DIR}/logging.hpp" + "${SOURCE_DIR}/utilities.hpp" + +# src SOURCE_FILES_ONLY + + "${SOURCE_DIR}/agent.cpp" + "${SOURCE_DIR}/utilities.cpp" + "${SOURCE_DIR}/version.cpp" + + +# src/asset HEADER_FILE_ONLY + + "${SOURCE_DIR}/asset/asset.hpp" + "${SOURCE_DIR}/asset/asset_buffer.hpp" + "${SOURCE_DIR}/asset/asset_storage.hpp" + "${SOURCE_DIR}/asset/cutting_tool.hpp" + "${SOURCE_DIR}/asset/file_asset.hpp" + "${SOURCE_DIR}/asset/raw_material.hpp" + "${SOURCE_DIR}/asset/qif_document.hpp" + "${SOURCE_DIR}/asset/component_configuration_parameters.hpp" + +# src/asset SOURCE_FILES_ONLY + + "${SOURCE_DIR}/asset/asset.cpp" + "${SOURCE_DIR}/asset/cutting_tool.cpp" + "${SOURCE_DIR}/asset/file_asset.cpp" + "${SOURCE_DIR}/asset/raw_material.cpp" + "${SOURCE_DIR}/asset/qif_document.cpp" + "${SOURCE_DIR}/asset/component_configuration_parameters.cpp" + +# src/buffer HEADER_FILES_ONLY + + "${SOURCE_DIR}/buffer/checkpoint.hpp" + "${SOURCE_DIR}/buffer/circular_buffer.hpp" + +# src/buffer SOURCE_FILES_ONLY + + "${SOURCE_DIR}/buffer/checkpoint.cpp" + +# src/configuration HEADER_FILE_ONLY + + "${SOURCE_DIR}/configuration/agent_config.hpp" + "${SOURCE_DIR}/configuration/async_context.hpp" + "${SOURCE_DIR}/configuration/config_options.hpp" + "${SOURCE_DIR}/configuration/hook_manager.hpp" + "${SOURCE_DIR}/configuration/parser.hpp" + "${SOURCE_DIR}/configuration/service.hpp" + +# src/configuration SOURCE_FILES_ONLY + + "${SOURCE_DIR}/configuration/agent_config.cpp" + "${SOURCE_DIR}/configuration/parser.cpp" + "${SOURCE_DIR}/configuration/service.cpp" + +# src/device_model HEADER_FILE_ONLY + + "${SOURCE_DIR}/device_model/agent_device.hpp" + "${SOURCE_DIR}/device_model/component.hpp" + "${SOURCE_DIR}/device_model/composition.hpp" + "${SOURCE_DIR}/device_model/description.hpp" + "${SOURCE_DIR}/device_model/device.hpp" + "${SOURCE_DIR}/device_model/reference.hpp" + +# src/device_model SOURCE_FILES_ONLY + + "${SOURCE_DIR}/device_model/agent_device.cpp" + "${SOURCE_DIR}/device_model/component.cpp" + "${SOURCE_DIR}/device_model/composition.cpp" + "${SOURCE_DIR}/device_model/description.cpp" + "${SOURCE_DIR}/device_model/device.cpp" + "${SOURCE_DIR}/device_model/reference.cpp" + +# src/device_model/configuration HEADER_FILE_ONLY + + "${SOURCE_DIR}/device_model/configuration/configuration.hpp" + "${SOURCE_DIR}/device_model/configuration/coordinate_systems.hpp" + "${SOURCE_DIR}/device_model/configuration/image_file.hpp" + "${SOURCE_DIR}/device_model/configuration/motion.hpp" + "${SOURCE_DIR}/device_model/configuration/relationships.hpp" + "${SOURCE_DIR}/device_model/configuration/sensor_configuration.hpp" + "${SOURCE_DIR}/device_model/configuration/solid_model.hpp" + "${SOURCE_DIR}/device_model/configuration/specifications.hpp" + +# src/device_model/configuration SOURCE_FILES_ONLY + + "${SOURCE_DIR}/device_model/configuration/configuration.cpp" + "${SOURCE_DIR}/device_model/configuration/coordinate_systems.cpp" + "${SOURCE_DIR}/device_model/configuration/image_file.cpp" + "${SOURCE_DIR}/device_model/configuration/motion.cpp" + "${SOURCE_DIR}/device_model/configuration/relationships.cpp" + "${SOURCE_DIR}/device_model/configuration/sensor_configuration.cpp" + "${SOURCE_DIR}/device_model/configuration/solid_model.cpp" + "${SOURCE_DIR}/device_model/configuration/specifications.cpp" + +# src/device_model/data_item HEADER_FILE_ONLY + + "${SOURCE_DIR}/device_model/data_item/constraints.hpp" + "${SOURCE_DIR}/device_model/data_item/data_item.hpp" + "${SOURCE_DIR}/device_model/data_item/definition.hpp" + "${SOURCE_DIR}/device_model/data_item/filter.hpp" + "${SOURCE_DIR}/device_model/data_item/relationships.hpp" + "${SOURCE_DIR}/device_model/data_item/source.hpp" + "${SOURCE_DIR}/device_model/data_item/unit_conversion.hpp" + +# src/device_model/data_item SOURCE_FILES_ONLY + + "${SOURCE_DIR}/device_model/data_item/data_item.cpp" + "${SOURCE_DIR}/device_model/data_item/unit_conversion.cpp" + +# src/entity HEADER_FILE_ONLY + + "${SOURCE_DIR}/entity/data_set.hpp" + "${SOURCE_DIR}/entity/entity.hpp" + "${SOURCE_DIR}/entity/factory.hpp" + "${SOURCE_DIR}/entity/json_parser.hpp" + "${SOURCE_DIR}/entity/json_printer.hpp" + "${SOURCE_DIR}/entity/qname.hpp" + "${SOURCE_DIR}/entity/requirement.hpp" + "${SOURCE_DIR}/entity/xml_parser.hpp" + "${SOURCE_DIR}/entity/xml_printer.hpp" + +# src/entity SOURCE_FILES_ONLY + + "${SOURCE_DIR}/entity/data_set.cpp" + "${SOURCE_DIR}/entity/entity.cpp" + "${SOURCE_DIR}/entity/factory.cpp" + "${SOURCE_DIR}/entity/json_parser.cpp" + "${SOURCE_DIR}/entity/requirement.cpp" + "${SOURCE_DIR}/entity/xml_parser.cpp" + "${SOURCE_DIR}/entity/xml_printer.cpp" + +# src/mqtt HEADER_FILE_ONLY + + "${SOURCE_DIR}/mqtt/mqtt_authorization.hpp" + "${SOURCE_DIR}/mqtt/mqtt_client.hpp" + "${SOURCE_DIR}/mqtt/mqtt_server.hpp" + "${SOURCE_DIR}/mqtt/mqtt_client_impl.hpp" + "${SOURCE_DIR}/mqtt/mqtt_server_impl.hpp" + +# src/observation HEADER_FILE_ONLY + + "${SOURCE_DIR}/observation/change_observer.hpp" + "${SOURCE_DIR}/observation/observation.hpp" + +#src/observation SOURCE_FILES_ONLY + + "${SOURCE_DIR}/observation/change_observer.cpp" + "${SOURCE_DIR}/observation/observation.cpp" + +# src/parser HEADER_FILE_ONLY + + "${SOURCE_DIR}/parser/xml_parser.hpp" + +# src/parser SOURCE_FILES_ONLY + + "${SOURCE_DIR}/parser/xml_parser.cpp" + +# src/pipeline HEADER_FILE_ONLY + + "${SOURCE_DIR}/pipeline/convert_sample.hpp" + "${SOURCE_DIR}/pipeline/deliver.hpp" + "${SOURCE_DIR}/pipeline/delta_filter.hpp" + "${SOURCE_DIR}/pipeline/duplicate_filter.hpp" + "${SOURCE_DIR}/pipeline/guard.hpp" + "${SOURCE_DIR}/pipeline/message_mapper.hpp" + "${SOURCE_DIR}/pipeline/mtconnect_xml_transform.hpp" + "${SOURCE_DIR}/pipeline/period_filter.hpp" + "${SOURCE_DIR}/pipeline/pipeline.hpp" + "${SOURCE_DIR}/pipeline/pipeline_context.hpp" + "${SOURCE_DIR}/pipeline/pipeline_contract.hpp" + "${SOURCE_DIR}/pipeline/response_document.hpp" + "${SOURCE_DIR}/pipeline/shdr_token_mapper.hpp" + "${SOURCE_DIR}/pipeline/shdr_tokenizer.hpp" + "${SOURCE_DIR}/pipeline/timestamp_extractor.hpp" + "${SOURCE_DIR}/pipeline/topic_mapper.hpp" + "${SOURCE_DIR}/pipeline/transform.hpp" + "${SOURCE_DIR}/pipeline/upcase_value.hpp" + +# src/pipeline SOURCE_FILES_ONLY + + "${SOURCE_DIR}/pipeline/deliver.cpp" + "${SOURCE_DIR}/pipeline/shdr_token_mapper.cpp" + "${SOURCE_DIR}/pipeline/timestamp_extractor.cpp" + "${SOURCE_DIR}/pipeline/response_document.cpp" + +# src/printer HEADER_FILE_ONLY + + "${SOURCE_DIR}/printer/json_printer.hpp" + "${SOURCE_DIR}/printer/json_printer_helper.hpp" + "${SOURCE_DIR}/printer/printer.hpp" + "${SOURCE_DIR}/printer/xml_helper.hpp" + "${SOURCE_DIR}/printer/xml_printer.hpp" + "${SOURCE_DIR}/printer/xml_printer_helper.hpp" + +# src/printer SOURCE_FILES_ONLY + + "${SOURCE_DIR}/printer/xml_printer.cpp" + "${SOURCE_DIR}/printer/json_printer.cpp" + +# src/source HEADER_FILE_ONLY + + "${SOURCE_DIR}/source/adapter/adapter.hpp" + "${SOURCE_DIR}/source/adapter/adapter_pipeline.hpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/agent_adapter.hpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/http_session.hpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/https_session.hpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/session.hpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/session_impl.hpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/url_parser.hpp" + "${SOURCE_DIR}/source/adapter/mqtt/mqtt_adapter.hpp" + "${SOURCE_DIR}/source/adapter/shdr/connector.hpp" + "${SOURCE_DIR}/source/adapter/shdr/shdr_adapter.hpp" + "${SOURCE_DIR}/source/adapter/shdr/shdr_pipeline.hpp" + "${SOURCE_DIR}/source/error_code.hpp" + "${SOURCE_DIR}/source/loopback_source.hpp" + "${SOURCE_DIR}/source/source.hpp" + +# src/source SOURCE_FILES_ONLY + + "${SOURCE_DIR}/source/adapter/adapter_pipeline.cpp" + "${SOURCE_DIR}/source/adapter/mqtt/mqtt_adapter.cpp" + "${SOURCE_DIR}/source/adapter/shdr/connector.cpp" + "${SOURCE_DIR}/source/adapter/shdr/shdr_adapter.cpp" + "${SOURCE_DIR}/source/adapter/shdr/shdr_pipeline.cpp" + "${SOURCE_DIR}/source/loopback_source.cpp" + "${SOURCE_DIR}/source/source.cpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/agent_adapter.cpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/url_parser.cpp" + +# src/sink HEADER_FILE_ONLY + + "${SOURCE_DIR}/sink/sink.hpp" + +# src/sink SOURCE_FILE_ONLY + + "${SOURCE_DIR}/sink/sink.cpp" + +# src/sink/mqtt_sink HEADER_FILE_ONLY + + "${SOURCE_DIR}/sink/mqtt_sink/mqtt_service.hpp" + "${SOURCE_DIR}/sink/mqtt_sink/mqtt2_service.hpp" + +#src/sink/mqtt_sink SOURCE_FILES_ONLY + + "${SOURCE_DIR}/sink/mqtt_sink/mqtt_service.cpp" + "${SOURCE_DIR}/sink/mqtt_sink/mqtt2_service.cpp" + +# src/sink/rest_sink HEADER_FILE_ONLY + + "${SOURCE_DIR}/sink/rest_sink/cached_file.hpp" + "${SOURCE_DIR}/sink/rest_sink/file_cache.hpp" + "${SOURCE_DIR}/sink/rest_sink/parameter.hpp" + "${SOURCE_DIR}/sink/rest_sink/request.hpp" + "${SOURCE_DIR}/sink/rest_sink/response.hpp" + "${SOURCE_DIR}/sink/rest_sink/rest_service.hpp" + "${SOURCE_DIR}/sink/rest_sink/routing.hpp" + "${SOURCE_DIR}/sink/rest_sink/server.hpp" + "${SOURCE_DIR}/sink/rest_sink/session.hpp" + "${SOURCE_DIR}/sink/rest_sink/session_impl.hpp" + "${SOURCE_DIR}/sink/rest_sink/tls_dector.hpp" + +# src/sink/rest_sink SOURCE_FILES_ONLY + + "${SOURCE_DIR}/sink/rest_sink/file_cache.cpp" + "${SOURCE_DIR}/sink/rest_sink/rest_service.cpp" + "${SOURCE_DIR}/sink/rest_sink/server.cpp" + "${SOURCE_DIR}/sink/rest_sink/session_impl.cpp" + ) + +if(WITH_RUBY) + set(AGENT_SOURCES ${AGENT_SOURCES} +# HEADER_FILE_ONLY + "${SOURCE_DIR}/ruby/embedded.hpp" + "${SOURCE_DIR}/ruby/ruby_agent.hpp" + "${SOURCE_DIR}/ruby/ruby_entity.hpp" + "${SOURCE_DIR}/ruby/ruby_observation.hpp" + "${SOURCE_DIR}/ruby/ruby_pipeline.hpp" + "${SOURCE_DIR}/ruby/ruby_smart_ptr.hpp" + "${SOURCE_DIR}/ruby/ruby_transform.hpp" + "${SOURCE_DIR}/ruby/ruby_type.hpp" + "${SOURCE_DIR}/ruby/ruby_vm.hpp" + +#SOURCE_FILES_ONLY + "${SOURCE_DIR}/ruby/embedded.cpp" + ) +endif() + +find_package(Boost REQUIRED) +find_package(LibXml2 REQUIRED) +find_package(date REQUIRED) +find_package(OpenSSL REQUIRED) +find_package(nlohmann_json REQUIRED) +find_package(mqtt_cpp REQUIRED) +find_package(RapidJSON REQUIRED) + +## configure a header file to pass some of the CMake settings to the source code +configure_file("${SOURCE_DIR}/version.h.in" "${PROJECT_BINARY_DIR}/agent_lib/mtconnect/version.h") + +set(AGENT_LIB_HEADERS ${AGENT_SOURCES}) +list(FILTER AGENT_LIB_HEADERS INCLUDE REGEX "\\.(h|hpp|ipp)$") +set(AGENT_LIB_SOURCES ${AGENT_SOURCES}) +list(FILTER AGENT_LIB_SOURCES INCLUDE REGEX "\\.(c|cpp)$") + +# For IDE Grouping +source_group("Header Files") +source_group("Source Files") +source_group(TREE "${SOURCE_DIR}" PREFIX "Header Files" FILES ${AGENT_LIB_HEADERS}) +source_group(TREE "${SOURCE_DIR}" PREFIX "Source Files" FILES ${AGENT_LIB_SOURCES}) + +if(MSVC) + if(CMAKE_GENERATOR_TOOLSET) + if(${CMAKE_GENERATOR_TOOLSET} MATCHES "v14[01]_xp") + message(info ": Setting /Ob1 for rest_sink/session_impl.cpp") + set_property(SOURCE "${SOURCE_DIR}/sink/rest_sink/session_impl.cpp" + PROPERTY COMPILE_FLAGS "/Ob1") + endif() + endif() + + # The modules including Beast required the /bigobj option in Windows + set_property(SOURCE + "${SOURCE_DIR}/sink/mqtt_sink/mqtt_service.cpp" + "${SOURCE_DIR}/sink/rest_sink/session_impl.cpp" + "${SOURCE_DIR}/source/adapter/mqtt/mqtt_adapter.cpp" + "${SOURCE_DIR}/source/adapter/agent_adapter/agent_adapter.cpp" + "${SOURCE_DIR}/source/adapter/shdr/shdr_pipeline.cpp" + "${SOURCE_DIR}/source/adapter/adapter_pipeline.cpp" + "${SOURCE_DIR}/device_model/component.cpp" + "${SOURCE_DIR}/configuration/agent_config.cpp" + "${SOURCE_DIR}/sink/rest_sink/rest_service.cpp" + "${SOURCE_DIR}/ruby/embedded.cpp" + "${SOURCE_DIR}/pipeline/deliver.cpp" + "${SOURCE_DIR}/agent.cpp" + PROPERTY COMPILE_FLAGS "/bigobj") +endif() + +if(SHARED_AGENT_LIB) + add_library(agent_lib SHARED ${AGENT_SOURCES}) + target_compile_definitions( + agent_lib + PRIVATE + AGENT_BUILD_SHARED_LIB) + target_compile_definitions( + agent_lib + PUBLIC + SHARED_AGENT_LIB) +else() + add_library(agent_lib STATIC ${AGENT_SOURCES}) +endif() + +if(AGENT_PREFIX) + set_target_properties(agent_lib PROPERTIES OUTPUT_NAME "${AGENT_PREFIX}agent_lib") +endif() + +target_include_directories( + agent_lib + PUBLIC + "${CONAN_INCLUDE_DIRS}" + "${PROJECT_BINARY_DIR}/agent_lib" + "${CMAKE_CURRENT_LIST_DIR}/../src" + ) + +target_link_libraries( + agent_lib + PUBLIC + boost::boost LibXml2::LibXml2 date::date-tz openssl::openssl + nlohmann_json::nlohmann_json mqtt_cpp::mqtt_cpp + rapidjson BZip2::BZip2 + + $<$:pthread> + $<$:bcrypt> + ) + +if(WITH_RUBY) + find_package(mruby REQUIRED) + find_package(oniguruma REQUIRED) + target_link_libraries( + agent_lib + PUBLIC + mruby::mruby + oniguruma::onig) +endif() + +target_compile_definitions( + agent_lib + PUBLIC + $<$:APPVEYOR> + $<$:NOMINMAX> + $<$:WINVER=${WINVER}> + $<$:_WIN32_WINNT=${WINVER}> + MQTT_USE_TLS=ON + MQTT_USE_WS=ON + MQTT_USE_STR_CHECK=ON + MQTT_STD_VARIANT + MQTT_STD_OPTIONAL + MQTT_STD_STRING_VIEW + MQTT_USE_LOG + BOOST_FILESYSTEM_VERSION=3 + ) + +if(WITH_PYTHON) + target_compile_definitions( + agent_lib + PUBLIC + WITH_PYTHON ) +endif() + +if(WITH_RUBY) + target_compile_definitions( + agent_lib + PUBLIC + WITH_RUBY ) +endif() + +if(AGENT_WITHOUT_IPV6) + target_compile_definitions( + agent_lib + PUBLIC + AGENT_WITHOUT_IPV6 ) +endif() + +# set_property(SOURCE ${AGENT_SOURCES} PROPERTY COMPILE_FLAGS_DEBUG "${COVERAGE_FLAGS}") +target_compile_features(agent_lib PUBLIC ${CXX_COMPILE_FEATURES}) +target_clangformat_setup(agent_lib) +target_clangtidy_setup(agent_lib) + +include(../cmake/document.cmake) +if (AGENT_WITH_DOCS AND DOXYGEN_FOUND) + doxygen_add_docs(docs ../README.md ${AGENT_SOURCES}) + install(DIRECTORY "${PROJECT_BINARY_DIR}/Documentation/" DESTINATION "Documentation") +endif() + +target_sources(agent_lib PUBLIC FILE_SET headers + TYPE HEADERS + BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../src/" + FILES "${AGENT_LIB_HEADERS}") + +install(TARGETS agent_lib LIBRARY DESTINATION "lib") +install(TARGETS agent_lib ARCHIVE DESTINATION "lib") +install(TARGETS agent_lib FILE_SET headers DESTINATION "include") +install(FILES "${PROJECT_BINARY_DIR}/agent_lib/mtconnect/version.h" DESTINATION "include/mtconnect") diff --git a/appveyor.yml b/appveyor.yml index 465cddda..cd4c1a0d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,8 +6,8 @@ branches: - /.*master.*/ image: - - Ubuntu2004 - Visual Studio 2019 + - Ubuntu2004 - macos-monterey environment: diff --git a/src/mtconnect/configuration/agent_config.cpp b/src/mtconnect/configuration/agent_config.cpp index 39fcca9a..efca7164 100644 --- a/src/mtconnect/configuration/agent_config.cpp +++ b/src/mtconnect/configuration/agent_config.cpp @@ -57,6 +57,7 @@ #include "mtconnect/device_model/device.hpp" #include "mtconnect/printer/xml_printer.hpp" #include "mtconnect/sink/mqtt_sink/mqtt_service.hpp" +#include "mtconnect/sink/mqtt_sink/mqtt2_service.hpp" #include "mtconnect/sink/rest_sink/rest_service.hpp" #include "mtconnect/source/adapter/agent_adapter/agent_adapter.hpp" #include "mtconnect/source/adapter/mqtt/mqtt_adapter.hpp" @@ -110,6 +111,7 @@ namespace mtconnect::configuration { bool success = false; sink::mqtt_sink::MqttService::registerFactory(m_sinkFactory); + sink::mqtt_sink::Mqtt2Service::registerFactory(m_sinkFactory); sink::rest_sink::RestService::registerFactory(m_sinkFactory); adapter::shdr::ShdrAdapter::registerFactory(m_sourceFactory); adapter::mqtt_adapter::MqttAdapter::registerFactory(m_sourceFactory); diff --git a/src/mtconnect/mqtt/mqtt_authorization.hpp b/src/mtconnect/mqtt/mqtt_authorization.hpp index 08105aa2..469f1731 100644 --- a/src/mtconnect/mqtt/mqtt_authorization.hpp +++ b/src/mtconnect/mqtt/mqtt_authorization.hpp @@ -44,6 +44,7 @@ namespace mtconnect { }; public: + MqttTopicPermission(const std::string& topic) { m_topic = topic; @@ -74,6 +75,11 @@ namespace mtconnect { return false; } + const std::string& getTopic() const + { + return m_topic; + } + protected: TopicMode m_mode; AuthorizationType m_type; @@ -81,42 +87,99 @@ namespace mtconnect { }; // namespace MqttTopicPermission + using MqttTopicPermissionPtr = std::shared_ptr; + class MqttAuthorization { public: MqttAuthorization(const ConfigOptions& options) : m_options(options) { - m_clientId = *GetOption(options, configuration::MqttClientId); m_username = GetOption(options, configuration::MqttUserName); m_password = GetOption(options, configuration::MqttPassword); } virtual ~MqttAuthorization() = default; - MqttTopicPermission getPermissionsForClient(const std::string& topic) + void addTopicPermissionForClient(const std::string& packetId, const std::string& topic) { - MqttTopicPermission mqttTopicPerm = *new MqttTopicPermission(topic); - return mqttTopicPerm; - } - - list getPermissionsForClient(const std::list& topics) + if (m_mapMqttTopicPermissions.empty()) + { + list mqttTopicPermissions; + MqttTopicPermissionPtr mqttTopicPerm = make_shared(topic); + mqttTopicPermissions.emplace_back(mqttTopicPerm); + m_mapMqttTopicPermissions.emplace(packetId, mqttTopicPermissions); + } + else + { + list mqttTopicPermissions = getTopicPermissionsForClient(packetId); + + if (!mqttTopicPermissions.empty()) + { + MqttTopicPermissionPtr mqttTopicPerm = make_shared(topic); + mqttTopicPermissions.emplace_back(mqttTopicPerm); + m_mapMqttTopicPermissions[packetId] = mqttTopicPermissions; + } + } + } + + void addTopicPermissionsForClient(const std::string& packetId, + const std::list& topics) { - list mqttTopicPermissions; + list mqttTopicPermissions; for (auto& topic : topics) { - mqttTopicPermissions.push_back(*new MqttTopicPermission(topic)); + MqttTopicPermissionPtr mqttTopicPerm = make_shared(topic); + mqttTopicPermissions.emplace_back(mqttTopicPerm); + } + m_mapMqttTopicPermissions.emplace(packetId, mqttTopicPermissions); + } + + MqttTopicPermissionPtr getTopicPermissionForClient(const std::string& packetId, + const std::string& topic) const + { + MqttTopicPermissionPtr mqttTopicPerm; + for (const auto& mqttPerms : m_mapMqttTopicPermissions) + { + if (!mqttPerms.second.empty()) + { + for (MqttTopicPermissionPtr mqttperm : mqttPerms.second) + { + if (mqttperm->getTopic() == topic) + return mqttperm; + } + } } + return mqttTopicPerm; + } - return mqttTopicPermissions; + list getTopicPermissionsForClient(const std::string& packetId) + { + return m_mapMqttTopicPermissions[packetId]; + } + + bool hasAuthorization(const std::string& packetId, const std::string& topic) + { + for (const auto& mqttPerms : m_mapMqttTopicPermissions) + { + if (!mqttPerms.second.empty()) + { + for (MqttTopicPermissionPtr mqttperm : mqttPerms.second) + { + if (mqttperm->getTopic() == topic) + return mqttperm->hasAuthorization(); + } + } + } + return false; } protected: std::optional m_username; std::optional m_password; - std::string m_clientId; + std::uint16_t m_packetId; ConfigOptions m_options; - + std::map > m_mapMqttTopicPermissions; }; // namespace MqttAuthorization class MqttAuthentication @@ -138,7 +201,6 @@ namespace mtconnect { LOG(error) << "MQTT USERNAME_OR_PASSWORD are Not Available"; return false; } - return true; } diff --git a/src/mtconnect/sink/mqtt_sink/mqtt2_service.cpp b/src/mtconnect/sink/mqtt_sink/mqtt2_service.cpp new file mode 100644 index 00000000..f03d01f1 --- /dev/null +++ b/src/mtconnect/sink/mqtt_sink/mqtt2_service.cpp @@ -0,0 +1,228 @@ + // + // Copyright Copyright 2009-2023, AMT – The Association For Manufacturing Technology (“AMT”) + // All rights reserved. + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. + // You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + // See the License for the specific language governing permissions and + // limitations under the License. + // + + #include "mqtt2_service.hpp" + + #include "mtconnect/configuration/config_options.hpp" + #include "mtconnect/entity/entity.hpp" + #include "mtconnect/entity/factory.hpp" + #include "mtconnect/entity/json_parser.hpp" + #include "mtconnect/mqtt/mqtt_client_impl.hpp" + #include "mtconnect/printer/json_printer.hpp" + + using ptree = boost::property_tree::ptree; + + using namespace std; + using namespace mtconnect::asset; + + namespace asio = boost::asio; + namespace config = ::mtconnect::configuration; + + namespace mtconnect { + namespace sink { + namespace mqtt_sink { + // get obeservation in + // create a json printer + // call print + + Mqtt2Service::Mqtt2Service(boost::asio::io_context &context, sink::SinkContractPtr &&contract, + const ConfigOptions &options, const ptree &config) + : Sink("Mqtt2Service", std::move(contract)), m_context(context), m_options(options) + { + auto jsonPrinter = dynamic_cast(m_sinkContract->getPrinter("json")); + m_jsonPrinter = make_unique(jsonPrinter->getJsonVersion()); + + GetOptions(config, m_options, options); + AddOptions(config, m_options, + {{configuration::MqttCaCert, string()}, + {configuration::MqttPrivateKey, string()}, + {configuration::MqttCert, string()}, + {configuration::MqttClientId, string()}}); + AddDefaultedOptions(config, m_options, + {{configuration::MqttHost, "127.0.0.1"s}, + {configuration::DeviceTopic, "MTConnect/Device/"s}, + {configuration::AssetTopic, "MTConnect/Asset/"s}, + {configuration::ObservationTopic, "MTConnect/Observation/"s}, + {configuration::MqttPort, 1883}, + {configuration::MqttTls, false}}); + + auto clientHandler = make_unique(); + clientHandler->m_connected = [this](shared_ptr client) { + // Publish latest devices, assets, and observations + auto &circ = m_sinkContract->getCircularBuffer(); + std::lock_guard lock(circ); + client->connectComplete(); + + for (auto &dev : m_sinkContract->getDevices()) + { + publish(dev); + } + + auto obsList {circ.getLatest().getObservations()}; + for (auto &obs : obsList) + { + observation::ObservationPtr p {obs.second}; + publish(p); + } + + AssetList list; + m_sinkContract->getAssetStorage()->getAssets(list, 100000); + for (auto &asset : list) + { + publish(asset); + } + }; + + m_devicePrefix = get(m_options[configuration::DeviceTopic]); + m_assetPrefix = get(m_options[configuration::AssetTopic]); + m_observationPrefix = get(m_options[configuration::ObservationTopic]); + + if (IsOptionSet(m_options, configuration::MqttTls)) + { + m_client = make_shared(m_context, m_options, std::move(clientHandler)); + } + else + { + m_client = make_shared(m_context, m_options, std::move(clientHandler)); + } + } + + void Mqtt2Service::start() + { + // mqtt client side not a server side... + if (!m_client) + return; + + m_client->start(); + } + + void Mqtt2Service::stop() + { + // stop client side + if (m_client) + m_client->stop(); + } + + std::shared_ptr Mqtt2Service::getClient() { return m_client; } + + bool Mqtt2Service::publish(observation::ObservationPtr &observation) + { + // get the data item from observation + if (observation->isOrphan()) + return false; + + DataItemPtr dataItem = observation->getDataItem(); + + auto topic = m_observationPrefix + dataItem->getTopic(); // client asyn topic + auto content = dataItem->getTopicName(); // client asyn content + + // We may want to use the observation from the checkpoint. + auto doc = m_jsonPrinter->printEntity(observation); + if (m_client) + m_client->publish(topic, doc); + + return true; + } + + bool Mqtt2Service::publish(device_model::DevicePtr device) + { + auto topic = m_devicePrefix + *device->getUuid(); + auto doc = m_jsonPrinter->print(device); + + stringstream buffer; + buffer << doc; + + if (m_client) + + m_client->publish(topic, buffer.str()); + + return true; + } + + bool Mqtt2Service::publish_Probe(device_model::DevicePtr device) + { + auto topic = m_devicePrefix + *device->getUuid(); + auto doc = m_jsonPrinter->print(device); + + stringstream buffer; + buffer << doc; + + if (m_client) + + m_client->publish(topic, buffer.str()); + + return true; + } + + bool Mqtt2Service::publish_Current(device_model::DevicePtr device) + { + auto topic = m_devicePrefix + *device->getUuid(); + auto doc = m_jsonPrinter->print(device); + + stringstream buffer; + buffer << doc; + + if (m_client) + + m_client->publish(topic, buffer.str()); + + return true; + } + + bool Mqtt2Service::publish_Samples(device_model::DevicePtr device) + { + auto topic = m_devicePrefix + *device->getUuid(); + auto doc = m_jsonPrinter->print(device); + + stringstream buffer; + buffer << doc; + + if (m_client) + + m_client->publish(topic, buffer.str()); + + return true; + } + + bool Mqtt2Service::publish(asset::AssetPtr asset) + { + auto topic = m_assetPrefix + get(asset->getIdentity()); + auto doc = m_jsonPrinter->print(asset); + + stringstream buffer; + buffer << doc; + + if (m_client) + m_client->publish(topic, buffer.str()); + + return true; + } + + // Register the service with the sink factory + void Mqtt2Service::registerFactory(SinkFactory &factory) + { + factory.registerFactory( + "Mqtt2Service", + [](const std::string &name, boost::asio::io_context &io, SinkContractPtr &&contract, + const ConfigOptions &options, const boost::property_tree::ptree &block) -> SinkPtr { + auto sink = std::make_shared(io, std::move(contract), options, block); + return sink; + }); + } + } // namespace mqtt_sink + } // namespace sink + } // namespace mtconnect diff --git a/src/mtconnect/sink/mqtt_sink/mqtt2_service.hpp b/src/mtconnect/sink/mqtt_sink/mqtt2_service.hpp new file mode 100644 index 00000000..2840d0ce --- /dev/null +++ b/src/mtconnect/sink/mqtt_sink/mqtt2_service.hpp @@ -0,0 +1,114 @@ + // + // Copyright Copyright 2009-2023, AMT – The Association For Manufacturing Technology (“AMT”) + // All rights reserved. + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. + // You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + // See the License for the specific language governing permissions and + // limitations under the License. + // + + #pragma once + + #include "boost/asio/io_context.hpp" + #include + + #include "mtconnect/buffer/checkpoint.hpp" + #include "mtconnect/config.hpp" + #include "mtconnect/configuration/agent_config.hpp" + #include "mtconnect/entity/json_printer.hpp" + #include "mtconnect/mqtt/mqtt_client.hpp" + #include "mtconnect/observation/observation.hpp" + #include "mtconnect/printer/printer.hpp" + #include "mtconnect/printer/xml_printer_helper.hpp" + #include "mtconnect/sink/sink.hpp" + #include "mtconnect/utilities.hpp" + + using namespace std; + using namespace mtconnect::entity; + using namespace mtconnect::mqtt_client; + + namespace mtconnect { + class XmlPrinter; + + namespace sink { + + /// @brief MTConnect Mqtt implemention namespace + + namespace mqtt_sink { + class AGENT_LIB_API Mqtt2Service : public sink::Sink + { + // dynamic loading of sink + + public: + /// @brief Create a Mqtt Service sink + /// @param context the boost asio io_context + /// @param contract the Sink Contract from the agent + /// @param options configuration options + /// @param config additional configuration options if specified directly as a sink + Mqtt2Service(boost::asio::io_context &context, sink::SinkContractPtr &&contract, + const ConfigOptions &options, const boost::property_tree::ptree &config); + + ~Mqtt2Service() = default; + + // Sink Methods + /// @brief Start the Mqtt service + void start() override; + + /// @brief Shutdown the Mqtt service + void stop() override; + + /// @brief Receive an observation + /// @param observation shared pointer to the observation + /// @return `true` if the publishing was successful + bool publish(observation::ObservationPtr &observation) override; + + /// @brief Receive an asset + /// @param asset shared point to the asset + /// @return `true` if successful + bool publish(asset::AssetPtr asset) override; + + /// @brief Receive a device + /// @param device shared pointer to the device + /// @return `true` if successful + bool publish(device_model::DevicePtr device) override; + + bool publish_Probe(device_model::DevicePtr device); + + bool publish_Current(device_model::DevicePtr device); + + bool publish_Samples(device_model::DevicePtr device); + + /// @brief Register the Sink factory to create this sink + /// @param factory + static void registerFactory(SinkFactory &factory); + + /// @brief gets a Mqtt Client + /// @return MqttClient + std::shared_ptr getClient(); + + /// @brief Mqtt Client is Connected or not + /// @return `true` when the client was connected + bool isConnected() { return m_client && m_client->isConnected(); } + + protected: + std::string m_devicePrefix; + std::string m_assetPrefix; + std::string m_observationPrefix; + + boost::asio::io_context &m_context; + ConfigOptions m_options; + std::unique_ptr m_jsonPrinter; + std::shared_ptr m_client; + //boost::asio::steady_timer m_timer; + }; + } // namespace mqtt_sink + } // namespace sink + } // namespace mtconnect diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9e416f8b..a3c84186 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -174,6 +174,7 @@ add_agent_test(routing FALSE sink/rest_sink) add_agent_test(mqtt_isolated FALSE mqtt_isolated TRUE) add_agent_test(mqtt_sink FALSE sink/mqtt_sink TRUE) +add_agent_test(mqtt_sink_2 FALSE sink/mqtt_sink_2 TRUE) add_agent_test(json_printer_asset TRUE json) add_agent_test(json_printer_error TRUE json) diff --git a/test/agent_test_helper.hpp b/test/agent_test_helper.hpp index 2f3291bc..c1cdbbd9 100644 --- a/test/agent_test_helper.hpp +++ b/test/agent_test_helper.hpp @@ -30,6 +30,7 @@ #include "mtconnect/configuration/config_options.hpp" #include "mtconnect/pipeline/pipeline.hpp" #include "mtconnect/sink/mqtt_sink/mqtt_service.hpp" +#include "mtconnect/sink/mqtt_sink/mqtt2_service.hpp" #include "mtconnect/sink/rest_sink/response.hpp" #include "mtconnect/sink/rest_sink/rest_service.hpp" #include "mtconnect/sink/rest_sink/routing.hpp" @@ -122,6 +123,7 @@ class AgentTestHelper ~AgentTestHelper() { m_mqttService.reset(); + m_mqtt2Service.reset(); m_restService.reset(); m_adapter.reset(); if (m_agent) @@ -176,6 +178,15 @@ class AgentTestHelper return mqtt; } + std::shared_ptr getMqtt2Service() + { + using namespace mtconnect; + sink::SinkPtr mqttSink = m_agent->findSink("Mqtt2Service"); + std::shared_ptr mqtt2 = + std::dynamic_pointer_cast(mqttSink); + return mqtt2; + } + auto createAgent(const std::string &file, int bufferSize = 8, int maxAssets = 4, const std::string &version = "1.7", int checkpoint = 25, bool put = false, bool observe = true, const mtconnect::ConfigOptions ops = {}) @@ -187,6 +198,8 @@ class AgentTestHelper sink::rest_sink::RestService::registerFactory(m_sinkFactory); sink::mqtt_sink::MqttService::registerFactory(m_sinkFactory); + sink::mqtt_sink::Mqtt2Service::registerFactory(m_sinkFactory); + source::adapter::shdr::ShdrAdapter::registerFactory(m_sourceFactory); ConfigOptions options = ops; @@ -228,6 +241,16 @@ class AgentTestHelper m_agent->addSink(m_mqttService); } + if (HasOption(options, "Mqtt2Sink")) + { + auto mqttContract = m_agent->makeSinkContract(); + mqttContract->m_pipelineContext = m_context; + auto mqtt2sink = m_sinkFactory.make("Mqtt2Service", "Mqtt2Service", m_ioContext, + std::move(mqttContract), options, ptree {}); + m_mqtt2Service = std::dynamic_pointer_cast(mqtt2sink); + m_agent->addSink(m_mqtt2Service); + } + m_agent->initialize(m_context); if (observe) @@ -301,6 +324,7 @@ class AgentTestHelper std::shared_ptr m_context; std::shared_ptr m_adapter; std::shared_ptr m_mqttService; + std::shared_ptr m_mqtt2Service; std::shared_ptr m_restService; std::shared_ptr m_loopback; diff --git a/test/mqtt_isolated_test.cpp b/test/mqtt_isolated_test.cpp index 5d902132..5ee1aab5 100644 --- a/test/mqtt_isolated_test.cpp +++ b/test/mqtt_isolated_test.cpp @@ -68,31 +68,23 @@ class MqttIsolatedUnitTest : public testing::Test void TearDown() override { - try + if (m_client) { - if (m_client) - { - m_client->stop(); - while (m_agentTestHelper->m_ioContext.run_one_for(100ms)) - ; - m_client.reset(); - } - - if (m_server) - { - m_server->stop(); - m_agentTestHelper->m_ioContext.run_for(1000ms); - m_server.reset(); - } - - m_agentTestHelper.reset(); - m_jsonPrinter.reset(); + m_client->stop(); + while (m_agentTestHelper->m_ioContext.run_one_for(10ms)) + ; + m_client.reset(); } - catch (...) + if (m_server) { - cerr << "Exception occurred in TearDown, ignoring" << endl; + m_server->stop(); + m_agentTestHelper->m_ioContext.run_for(500ms); + m_server.reset(); } + + m_agentTestHelper.reset(); + m_jsonPrinter.reset(); } void createServer(const ConfigOptions &options) @@ -209,7 +201,7 @@ TEST_F(MqttIsolatedUnitTest, mqtt_tcp_client_should_receive_loopback_publication { ConfigOptions options {{ServerIp, "127.0.0.1"s}, {MqttPort, 0}, - {MqttTls, false}, + {MqttTls, false}, {AutoAvailable, false}, {RealTime, false}}; @@ -423,7 +415,6 @@ TEST_F(MqttIsolatedUnitTest, mqtt_tcp_client_authentication) client->set_keep_alive_sec(30); MqttAuthorization *mqttAuct = new MqttAuthorization(options); - MqttTopicPermission permission = mqttAuct->getPermissionsForClient("mqtt_tcp_client_cpp/topic1"); client->set_connack_handler([&](bool sp, mqtt::connect_return_code connack_return_code) { std::cout << "Connack handler called" << std::endl; @@ -461,21 +452,16 @@ TEST_F(MqttIsolatedUnitTest, mqtt_tcp_client_authentication) client->set_close_handler([] { std::cout << "closed" << std::endl; }); client->set_suback_handler( - [&client, &pid_sub1, &permission](std::uint16_t packet_id, - std::vector results) { + [&client, &pid_sub1, &mqttAuct](std::uint16_t packet_id, + std::vector results) { std::cout << "suback received. packet_id: " << packet_id << std::endl; for (auto const &e : results) { std::cout << "subscribe result: " << e << std::endl; } - // check either topic had authorization permissions - if (!permission.hasAuthorization()) - { - std::cout << "MqttAuthorization Failed. packet_id: " << pid_sub1 << std::endl; - client->async_force_disconnect(); - return false; - } + mqttAuct->addTopicPermissionForClient(boost::lexical_cast(packet_id), + "mqtt_tcp_client_cpp/topic1"); if (packet_id == pid_sub1) { @@ -494,24 +480,37 @@ TEST_F(MqttIsolatedUnitTest, mqtt_tcp_client_authentication) }); bool received = false; - client->set_publish_handler([&client, &received](mqtt::optional packet_id, - mqtt::publish_options pubopts, - mqtt::buffer topic_name, mqtt::buffer contents) { - std::cout << "publish received." - << " dup: " << pubopts.get_dup() << " qos: " << pubopts.get_qos() - << " retain: " << pubopts.get_retain() << std::endl; - if (packet_id) - std::cout << "packet_id: " << *packet_id << std::endl; - std::cout << "topic_name: " << topic_name << std::endl; - std::cout << "contents: " << contents << std::endl; - - EXPECT_EQ("mqtt_tcp_client_cpp/topic1", topic_name); - EXPECT_EQ("test1", contents); - - client->async_disconnect(); - received = true; - return true; - }); + client->set_publish_handler( + [&client, &pid_sub1, &received, &mqttAuct](mqtt::optional packet_id, + mqtt::publish_options pubopts, mqtt::buffer topic_name, + mqtt::buffer contents) { + // check either topic had authorization permissions + if (pid_sub1) + { + string pacValue(boost::lexical_cast(pid_sub1)); + string topicName(boost::lexical_cast(topic_name)); + if (!mqttAuct->hasAuthorization(pacValue, topicName)) + { + std::cout << "MqttAuthorization Failed. client packet_id: " << pacValue << std::endl; + client->async_force_disconnect(); + return false; + } + } + std::cout << "publish received." + << " dup: " << pubopts.get_dup() << " qos: " << pubopts.get_qos() + << " retain: " << pubopts.get_retain() << std::endl; + if (packet_id) + std::cout << "packet_id: " << *packet_id << std::endl; + std::cout << "topic_name: " << topic_name << std::endl; + std::cout << "contents: " << contents << std::endl; + + EXPECT_EQ("mqtt_tcp_client_cpp/topic1", topic_name); + EXPECT_EQ("test1", contents); + + client->async_disconnect(); + received = true; + return true; + }); client->async_connect([](mqtt::error_code ec) { ASSERT_FALSE(ec) << "CAnnot connect"; }); ASSERT_TRUE(waitFor(5s, [&received]() { return received; })); diff --git a/test/mqtt_sink_2_test.cpp b/test/mqtt_sink_2_test.cpp new file mode 100644 index 00000000..e5187db5 --- /dev/null +++ b/test/mqtt_sink_2_test.cpp @@ -0,0 +1,298 @@ +// +// Copyright Copyright 2009-2022, AMT – The Association For Manufacturing Technology (“AMT”) +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Ensure that gtest is the first header otherwise Windows raises an error +#include +// Keep this comment to keep gtest.h above. (clang-format off/on is not working here!) + +#include + +#include + +#include "agent_test_helper.hpp" +#include "mtconnect/buffer/checkpoint.hpp" +#include "mtconnect/device_model/data_item/data_item.hpp" +#include "mtconnect/entity/entity.hpp" +#include "mtconnect/entity/json_parser.hpp" +#include "mtconnect/mqtt/mqtt_client_impl.hpp" +#include "mtconnect/mqtt/mqtt_server_impl.hpp" +#include "mtconnect/printer//json_printer.hpp" +#include "mtconnect/sink/mqtt_sink/mqtt2_service.hpp" + +using namespace std; +using namespace mtconnect; +using namespace mtconnect::device_model::data_item; +using namespace mtconnect::sink::mqtt_sink; +using namespace mtconnect::asset; +using namespace mtconnect::configuration; + +// main +int main(int argc, char *argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + +using json = nlohmann::json; + +class MqttSinkTest : public testing::Test +{ +protected: + void SetUp() override + { + m_agentTestHelper = make_unique(); + m_jsonPrinter = std::make_unique(2, true); + } + + void TearDown() override + { + const auto agent = m_agentTestHelper->getAgent(); + if (agent) + { + m_agentTestHelper->getAgent()->stop(); + m_agentTestHelper->m_ioContext.run_for(100ms); + } + if (m_client) + { + m_client->stop(); + m_agentTestHelper->m_ioContext.run_for(500ms); + m_client.reset(); + } + if (m_server) + { + m_server->stop(); + m_agentTestHelper->m_ioContext.run_for(500ms); + m_server.reset(); + } + m_agentTestHelper.reset(); + m_jsonPrinter.reset(); + } + + void createAgent(std::string testFile = {}, ConfigOptions options = {}) + { + if (testFile == "") + testFile = "/samples/test_config.xml"; + + ConfigOptions opts(options); + MergeOptions(opts, {{"Mqtt2Sink", true}, + {configuration::MqttPort, m_port}, + {configuration::MqttHost, "127.0.0.1"s}}); + m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 25, false, true, opts); + addAdapter(); + + m_agentTestHelper->getAgent()->start(); + } + + void createServer(const ConfigOptions &options) + { + using namespace mtconnect::configuration; + ConfigOptions opts(options); + MergeOptions(opts, {{ServerIp, "127.0.0.1"s}, + {MqttPort, 0}, + {MqttTls, false}, + {AutoAvailable, false}, + {RealTime, false}}); + + m_server = + make_shared(m_agentTestHelper->m_ioContext, opts); + } + + template + bool waitFor(const chrono::duration &time, function pred) + { + boost::asio::steady_timer timer(m_agentTestHelper->m_ioContext); + timer.expires_from_now(time); + bool timeout = false; + timer.async_wait([&timeout](boost::system::error_code ec) { + if (!ec) + { + timeout = true; + } + }); + + while (!timeout && !pred()) + { + m_agentTestHelper->m_ioContext.run_for(100ms); + } + timer.cancel(); + + return pred(); + } + + void startServer() + { + if (m_server) + { + bool start = m_server->start(); + if (start) + { + m_port = m_server->getPort(); + m_agentTestHelper->m_ioContext.run_for(500ms); + } + } + } + + void createClient(const ConfigOptions &options, unique_ptr &&handler) + { + ConfigOptions opts(options); + MergeOptions(opts, {{MqttHost, "127.0.0.1"s}, + {MqttPort, m_port}, + {MqttTls, false}, + {AutoAvailable, false}, + {RealTime, false}}); + m_client = make_shared(m_agentTestHelper->m_ioContext, + opts, move(handler)); + } + + bool startClient() + { + bool started = m_client && m_client->start(); + if (started) + { + return waitFor(1s, [this]() { return m_client->isConnected(); }); + } + return started; + } + + void addAdapter(ConfigOptions options = ConfigOptions {}) + { + m_agentTestHelper->addAdapter(options, "localhost", 7878, + m_agentTestHelper->m_agent->getDefaultDevice()->getName()); + } + + std::unique_ptr m_jsonPrinter; + std::shared_ptr m_server; + std::shared_ptr m_client; + std::unique_ptr m_agentTestHelper; + uint16_t m_port {0}; +}; + +TEST_F(MqttSinkTest, mqtt_sink_should_publish_Probe) +{ + ConfigOptions options; + createServer(options); + startServer(); + ASSERT_NE(0, m_port); + + entity::JsonParser parser; + + auto handler = make_unique(); + bool gotDevice = false; + handler->m_receive = [&gotDevice, &parser](std::shared_ptr client, + const std::string &topic, const std::string &payload) { + EXPECT_EQ("MTConnect/Device/000", topic); + + ErrorList list; + auto ptr = parser.parse(device_model::Device::getRoot(), payload, "2.0", list); + EXPECT_EQ(0, list.size()); + auto dev = dynamic_pointer_cast(ptr); + EXPECT_TRUE(dev); + EXPECT_EQ("LinuxCNC", dev->getComponentName()); + EXPECT_EQ("000", *dev->getUuid()); + + gotDevice = true; + }; + + createClient(options, move(handler)); + ASSERT_TRUE(startClient()); + m_client->subscribe("MTConnect/Device/000"); + + createAgent(); + + auto service = m_agentTestHelper->getMqtt2Service(); + + ASSERT_TRUE(waitFor(60s, [&service]() { return service->isConnected(); })); + + waitFor(1s, [&gotDevice]() { return gotDevice; }); +} + +TEST_F(MqttSinkTest, mqtt_sink_should_publish_Sample) +{ + ConfigOptions options; + createServer(options); + startServer(); + ASSERT_NE(0, m_port); + + entity::JsonParser parser; + + auto handler = make_unique(); + bool gotSample = false; + handler->m_receive = [&gotSample, &parser](std::shared_ptr client, + const std::string &topic, const std::string &payload) { + EXPECT_EQ("MTConnect/000/Sample", topic); + + ErrorList list; + auto ptr = parser.parse(device_model::Device::getRoot(), payload, "2.0", list); + EXPECT_EQ(0, list.size()); + auto dev = dynamic_pointer_cast(ptr); + EXPECT_TRUE(dev); + EXPECT_EQ("LinuxCNC", dev->getComponentName()); + EXPECT_EQ("000", *dev->getUuid()); + + gotSample = true; + }; + + createClient(options, move(handler)); + ASSERT_TRUE(startClient()); + m_client->subscribe("MTConnect/000/Sample"); + + createAgent(); + + auto service = m_agentTestHelper->getMqtt2Service(); + + ASSERT_TRUE(waitFor(60s, [&service]() { return service->isConnected(); })); + + waitFor(1s, [&gotSample]() { return gotSample; }); +} + +TEST_F(MqttSinkTest, mqtt_sink_should_publish_Current) +{ + ConfigOptions options; + createServer(options); + startServer(); + ASSERT_NE(0, m_port); + + entity::JsonParser parser; + + auto handler = make_unique(); + bool gotCurrent = false; + handler->m_receive = [&gotCurrent, &parser](std::shared_ptr client, + const std::string &topic, const std::string &payload) { + EXPECT_EQ("MTConnect/e481314c-07c4-525f-966f-71dd53b8d717/Current", topic); + + ErrorList list; + auto ptr = parser.parse(device_model::Device::getRoot(), payload, "2.0", list); + EXPECT_EQ(0, list.size()); + auto dev = dynamic_pointer_cast(ptr); + EXPECT_TRUE(dev); + EXPECT_EQ("LinuxCNC", dev->getComponentName()); + EXPECT_EQ("e481314c-07c4-525f-966f-71dd53b8d717", *dev->getUuid()); + + gotCurrent = true; + }; + + createClient(options, move(handler)); + ASSERT_TRUE(startClient()); + m_client->subscribe("MTConnect/e481314c-07c4-525f-966f-71dd53b8d717/Current"); + + createAgent(); + + auto service = m_agentTestHelper->getMqtt2Service(); + + ASSERT_TRUE(waitFor(60s, [&service]() { return service->isConnected(); })); + + waitFor(1s, [&gotCurrent]() { return gotCurrent; }); +} diff --git a/test/mqtt_sink_test.cpp b/test/mqtt_sink_test.cpp index 9e91d6ad..34676438 100644 --- a/test/mqtt_sink_test.cpp +++ b/test/mqtt_sink_test.cpp @@ -59,26 +59,34 @@ class MqttSinkTest : public testing::Test void TearDown() override { - const auto agent = m_agentTestHelper->getAgent(); - if (agent) + try { - m_agentTestHelper->getAgent()->stop(); - m_agentTestHelper->m_ioContext.run_for(100ms); - } - if (m_client) - { - m_client->stop(); - m_agentTestHelper->m_ioContext.run_for(100ms); - m_client.reset(); + const auto agent = m_agentTestHelper->getAgent(); + if (agent) + { + m_agentTestHelper->getAgent()->stop(); + m_agentTestHelper->m_ioContext.run_for(100ms); + } + if (m_client) + { + m_client->stop(); + m_agentTestHelper->m_ioContext.run_for(100ms); + m_client.reset(); + } + if (m_server) + { + m_server->stop(); + m_agentTestHelper->m_ioContext.run_for(500ms); + m_server.reset(); + } + m_agentTestHelper->m_ioContext.stop(); + m_agentTestHelper.reset(); + m_jsonPrinter.reset(); } - if (m_server) + catch(...) { - m_server->stop(); - m_agentTestHelper->m_ioContext.run_for(500ms); - m_server.reset(); + cerr << "Exception thown in TearDown. Ignoring" << endl; } - m_agentTestHelper.reset(); - m_jsonPrinter.reset(); } void createAgent(std::string testFile = {}, ConfigOptions options = {}) diff --git a/test/reports/adapter_device_test_Report.diagsession b/test/reports/adapter_device_test_Report.diagsession new file mode 100644 index 00000000..fb37806b Binary files /dev/null and b/test/reports/adapter_device_test_Report.diagsession differ diff --git a/test/reports/adapter_test_Report.diagsession b/test/reports/adapter_test_Report.diagsession new file mode 100644 index 00000000..68a3f10a Binary files /dev/null and b/test/reports/adapter_test_Report.diagsession differ diff --git a/test/reports/agent_adapter_test_Report.diagsession b/test/reports/agent_adapter_test_Report.diagsession new file mode 100644 index 00000000..495a96cf Binary files /dev/null and b/test/reports/agent_adapter_test_Report.diagsession differ diff --git a/test/reports/assert_buffer_test_Report.diagsession b/test/reports/assert_buffer_test_Report.diagsession new file mode 100644 index 00000000..39efcd47 Binary files /dev/null and b/test/reports/assert_buffer_test_Report.diagsession differ diff --git a/test/reports/assert_hash_test_Report.diagsession b/test/reports/assert_hash_test_Report.diagsession new file mode 100644 index 00000000..63a70b0b Binary files /dev/null and b/test/reports/assert_hash_test_Report.diagsession differ diff --git a/test/reports/assert_test_Report.diagsession b/test/reports/assert_test_Report.diagsession new file mode 100644 index 00000000..b63b1093 Binary files /dev/null and b/test/reports/assert_test_Report.diagsession differ diff --git a/test/reports/change_observer_test_Report.diagsession b/test/reports/change_observer_test_Report.diagsession new file mode 100644 index 00000000..ced94fbf Binary files /dev/null and b/test/reports/change_observer_test_Report.diagsession differ diff --git a/test/reports/checkpoint_test_Report.diagsession b/test/reports/checkpoint_test_Report.diagsession new file mode 100644 index 00000000..bfc62c39 Binary files /dev/null and b/test/reports/checkpoint_test_Report.diagsession differ diff --git a/test/reports/circular_buffer_test_Report.diagsession b/test/reports/circular_buffer_test_Report.diagsession new file mode 100644 index 00000000..a8f52b92 Binary files /dev/null and b/test/reports/circular_buffer_test_Report.diagsession differ diff --git a/test/reports/component_parameters_test_Report.diagsession b/test/reports/component_parameters_test_Report.diagsession new file mode 100644 index 00000000..09ece6c3 Binary files /dev/null and b/test/reports/component_parameters_test_Report.diagsession differ diff --git a/test/reports/component_test_Report.diagsession b/test/reports/component_test_Report.diagsession new file mode 100644 index 00000000..66f9d58d Binary files /dev/null and b/test/reports/component_test_Report.diagsession differ diff --git a/test/reports/composition_test_Report.diagsession b/test/reports/composition_test_Report.diagsession new file mode 100644 index 00000000..3b60d8e9 Binary files /dev/null and b/test/reports/composition_test_Report.diagsession differ diff --git a/test/reports/config_parser_test_Report.diagsession b/test/reports/config_parser_test_Report.diagsession new file mode 100644 index 00000000..6de4e16c Binary files /dev/null and b/test/reports/config_parser_test_Report.diagsession differ diff --git a/test/reports/config_test_Report.diagsession b/test/reports/config_test_Report.diagsession new file mode 100644 index 00000000..dd6335e8 Binary files /dev/null and b/test/reports/config_test_Report.diagsession differ diff --git a/test/reports/connector_test_Report.diagsession b/test/reports/connector_test_Report.diagsession new file mode 100644 index 00000000..61985d35 Binary files /dev/null and b/test/reports/connector_test_Report.diagsession differ diff --git a/test/reports/coordinate_system_test_Report.diagsession b/test/reports/coordinate_system_test_Report.diagsession new file mode 100644 index 00000000..ecd70034 Binary files /dev/null and b/test/reports/coordinate_system_test_Report.diagsession differ diff --git a/test/reports/cutting_tool_test_Report.diagsession b/test/reports/cutting_tool_test_Report.diagsession new file mode 100644 index 00000000..9b7e3eb4 Binary files /dev/null and b/test/reports/cutting_tool_test_Report.diagsession differ diff --git a/test/reports/data_item_mapping_test_Report.diagsession b/test/reports/data_item_mapping_test_Report.diagsession new file mode 100644 index 00000000..e9c20dd4 Binary files /dev/null and b/test/reports/data_item_mapping_test_Report.diagsession differ diff --git a/test/reports/data_item_test_Report.diagsession b/test/reports/data_item_test_Report.diagsession new file mode 100644 index 00000000..50432681 Binary files /dev/null and b/test/reports/data_item_test_Report.diagsession differ diff --git a/test/reports/data_set_test_Report.diagsession b/test/reports/data_set_test_Report.diagsession new file mode 100644 index 00000000..b628e47f Binary files /dev/null and b/test/reports/data_set_test_Report.diagsession differ diff --git a/test/reports/device_test_Report.diagsession b/test/reports/device_test_Report.diagsession new file mode 100644 index 00000000..a18f903e Binary files /dev/null and b/test/reports/device_test_Report.diagsession differ diff --git a/test/reports/duplicate_filter_test_Report.diagsession b/test/reports/duplicate_filter_test_Report.diagsession new file mode 100644 index 00000000..3d135293 Binary files /dev/null and b/test/reports/duplicate_filter_test_Report.diagsession differ diff --git a/test/reports/entity_parser_test_Report.diagsession b/test/reports/entity_parser_test_Report.diagsession new file mode 100644 index 00000000..b4dfb4ae Binary files /dev/null and b/test/reports/entity_parser_test_Report.diagsession differ diff --git a/test/reports/entity_printer_test_Report.diagsession b/test/reports/entity_printer_test_Report.diagsession new file mode 100644 index 00000000..ef37aa3f Binary files /dev/null and b/test/reports/entity_printer_test_Report.diagsession differ diff --git a/test/reports/entity_test_Report.diagsession b/test/reports/entity_test_Report.diagsession new file mode 100644 index 00000000..86f74819 Binary files /dev/null and b/test/reports/entity_test_Report.diagsession differ diff --git a/test/reports/file_assert_test_Report.diagsession b/test/reports/file_assert_test_Report.diagsession new file mode 100644 index 00000000..27007d85 Binary files /dev/null and b/test/reports/file_assert_test_Report.diagsession differ diff --git a/test/reports/file_cache_test_Report.diagsession b/test/reports/file_cache_test_Report.diagsession new file mode 100644 index 00000000..ae3e7a85 Binary files /dev/null and b/test/reports/file_cache_test_Report.diagsession differ diff --git a/test/reports/globals_test_Report.diagsession b/test/reports/globals_test_Report.diagsession new file mode 100644 index 00000000..df8e01a1 Binary files /dev/null and b/test/reports/globals_test_Report.diagsession differ diff --git a/test/reports/http_server_test_Report.diagsession b/test/reports/http_server_test_Report.diagsession new file mode 100644 index 00000000..40a8ee3b Binary files /dev/null and b/test/reports/http_server_test_Report.diagsession differ diff --git a/test/reports/image_file_test_Report.diagsession b/test/reports/image_file_test_Report.diagsession new file mode 100644 index 00000000..559dc79e Binary files /dev/null and b/test/reports/image_file_test_Report.diagsession differ diff --git a/test/reports/json_parser_test_Report.diagsession b/test/reports/json_parser_test_Report.diagsession new file mode 100644 index 00000000..91f0ee66 Binary files /dev/null and b/test/reports/json_parser_test_Report.diagsession differ diff --git a/test/reports/json_printer_assert_test_Report.diagsession b/test/reports/json_printer_assert_test_Report.diagsession new file mode 100644 index 00000000..6c4f1169 Binary files /dev/null and b/test/reports/json_printer_assert_test_Report.diagsession differ diff --git a/test/reports/json_printer_error_test_Report.diagsession b/test/reports/json_printer_error_test_Report.diagsession new file mode 100644 index 00000000..4d4b34d5 Binary files /dev/null and b/test/reports/json_printer_error_test_Report.diagsession differ diff --git a/test/reports/json_printer_probe_test_Report.diagsession b/test/reports/json_printer_probe_test_Report.diagsession new file mode 100644 index 00000000..fe1581e8 Binary files /dev/null and b/test/reports/json_printer_probe_test_Report.diagsession differ diff --git a/test/reports/json_printer_steam_test_Report.diagsession b/test/reports/json_printer_steam_test_Report.diagsession new file mode 100644 index 00000000..91e74d91 Binary files /dev/null and b/test/reports/json_printer_steam_test_Report.diagsession differ diff --git a/test/reports/json_printer_test_Report.diagsession b/test/reports/json_printer_test_Report.diagsession new file mode 100644 index 00000000..7bd62a25 Binary files /dev/null and b/test/reports/json_printer_test_Report.diagsession differ diff --git a/test/reports/kinematics_test_Report.diagsession b/test/reports/kinematics_test_Report.diagsession new file mode 100644 index 00000000..d9a4a1e8 Binary files /dev/null and b/test/reports/kinematics_test_Report.diagsession differ diff --git a/test/reports/mqtt_adapter_test_Report.diagsession b/test/reports/mqtt_adapter_test_Report.diagsession new file mode 100644 index 00000000..98c51704 Binary files /dev/null and b/test/reports/mqtt_adapter_test_Report.diagsession differ diff --git a/test/reports/mqtt_isolated_test_Report.diagsession b/test/reports/mqtt_isolated_test_Report.diagsession new file mode 100644 index 00000000..9f9fda1b Binary files /dev/null and b/test/reports/mqtt_isolated_test_Report.diagsession differ diff --git a/test/reports/mqtt_sink_test_Report.diagsession b/test/reports/mqtt_sink_test_Report.diagsession new file mode 100644 index 00000000..2b29f015 Binary files /dev/null and b/test/reports/mqtt_sink_test_Report.diagsession differ diff --git a/test/reports/mtconnect_xml_transform_test_Report.diagsession b/test/reports/mtconnect_xml_transform_test_Report.diagsession new file mode 100644 index 00000000..66d1e9fd Binary files /dev/null and b/test/reports/mtconnect_xml_transform_test_Report.diagsession differ diff --git a/test/reports/observation_test_Report.diagsession b/test/reports/observation_test_Report.diagsession new file mode 100644 index 00000000..fe89f9c7 Binary files /dev/null and b/test/reports/observation_test_Report.diagsession differ diff --git a/test/reports/period_filter_test_Report.diagsession b/test/reports/period_filter_test_Report.diagsession new file mode 100644 index 00000000..329c278c Binary files /dev/null and b/test/reports/period_filter_test_Report.diagsession differ diff --git a/test/reports/pipeline_deliver_test_Report.diagsession b/test/reports/pipeline_deliver_test_Report.diagsession new file mode 100644 index 00000000..ca81a07a Binary files /dev/null and b/test/reports/pipeline_deliver_test_Report.diagsession differ diff --git a/test/reports/pipeline_edit_test_Report.diagsession b/test/reports/pipeline_edit_test_Report.diagsession new file mode 100644 index 00000000..f8ae14b6 Binary files /dev/null and b/test/reports/pipeline_edit_test_Report.diagsession differ diff --git a/test/reports/qif_document_test_Report.diagsession b/test/reports/qif_document_test_Report.diagsession new file mode 100644 index 00000000..192cb8e1 Binary files /dev/null and b/test/reports/qif_document_test_Report.diagsession differ diff --git a/test/reports/qname_test_Report.diagsession b/test/reports/qname_test_Report.diagsession new file mode 100644 index 00000000..f5ba966a Binary files /dev/null and b/test/reports/qname_test_Report.diagsession differ diff --git a/test/reports/raw_material_test_Report.diagsession b/test/reports/raw_material_test_Report.diagsession new file mode 100644 index 00000000..05a47624 Binary files /dev/null and b/test/reports/raw_material_test_Report.diagsession differ diff --git a/test/reports/references_test_Report.diagsession b/test/reports/references_test_Report.diagsession new file mode 100644 index 00000000..20667440 Binary files /dev/null and b/test/reports/references_test_Report.diagsession differ diff --git a/test/reports/relationship_test_Report.diagsession b/test/reports/relationship_test_Report.diagsession new file mode 100644 index 00000000..f6330e40 Binary files /dev/null and b/test/reports/relationship_test_Report.diagsession differ diff --git a/test/reports/response_document_test_Report.diagsession b/test/reports/response_document_test_Report.diagsession new file mode 100644 index 00000000..a4214077 Binary files /dev/null and b/test/reports/response_document_test_Report.diagsession differ diff --git a/test/reports/routing_test_Report.diagsession b/test/reports/routing_test_Report.diagsession new file mode 100644 index 00000000..9888389b Binary files /dev/null and b/test/reports/routing_test_Report.diagsession differ diff --git a/test/reports/sensor_configuration_test_Report.diagsession b/test/reports/sensor_configuration_test_Report.diagsession new file mode 100644 index 00000000..568c8645 Binary files /dev/null and b/test/reports/sensor_configuration_test_Report.diagsession differ diff --git a/test/reports/shdr_tokenizer_test_Report.diagsession b/test/reports/shdr_tokenizer_test_Report.diagsession new file mode 100644 index 00000000..9546de97 Binary files /dev/null and b/test/reports/shdr_tokenizer_test_Report.diagsession differ diff --git a/test/reports/solid_model_test_Report.diagsession b/test/reports/solid_model_test_Report.diagsession new file mode 100644 index 00000000..c047b310 Binary files /dev/null and b/test/reports/solid_model_test_Report.diagsession differ diff --git a/test/reports/specification_test_Report.diagsession b/test/reports/specification_test_Report.diagsession new file mode 100644 index 00000000..77ea4c5d Binary files /dev/null and b/test/reports/specification_test_Report.diagsession differ diff --git a/test/reports/table_test_Report.diagsession b/test/reports/table_test_Report.diagsession new file mode 100644 index 00000000..85b8bd24 Binary files /dev/null and b/test/reports/table_test_Report.diagsession differ diff --git a/test/reports/timestamp_extractor_test_Report.diagsession b/test/reports/timestamp_extractor_test_Report.diagsession new file mode 100644 index 00000000..59447f3f Binary files /dev/null and b/test/reports/timestamp_extractor_test_Report.diagsession differ diff --git a/test/reports/tls_http_server_test_Report.diagsession b/test/reports/tls_http_server_test_Report.diagsession new file mode 100644 index 00000000..7edf145d Binary files /dev/null and b/test/reports/tls_http_server_test_Report.diagsession differ diff --git a/test/reports/topic_mapping_test_Report.diagsession b/test/reports/topic_mapping_test_Report.diagsession new file mode 100644 index 00000000..5cc8bc5d Binary files /dev/null and b/test/reports/topic_mapping_test_Report.diagsession differ diff --git a/test/reports/unit_conversion_test_Report.diagsession b/test/reports/unit_conversion_test_Report.diagsession new file mode 100644 index 00000000..e73ae606 Binary files /dev/null and b/test/reports/unit_conversion_test_Report.diagsession differ diff --git a/test/reports/url_parser_test_Report.diagsession b/test/reports/url_parser_test_Report.diagsession new file mode 100644 index 00000000..e46dd7f8 Binary files /dev/null and b/test/reports/url_parser_test_Report.diagsession differ diff --git a/test/reports/xml_parser_test_Report.diagsession b/test/reports/xml_parser_test_Report.diagsession new file mode 100644 index 00000000..727098b3 Binary files /dev/null and b/test/reports/xml_parser_test_Report.diagsession differ diff --git a/test/reports/xml_printer_test_Report.diagsession b/test/reports/xml_printer_test_Report.diagsession new file mode 100644 index 00000000..ef717fe2 Binary files /dev/null and b/test/reports/xml_printer_test_Report.diagsession differ