diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 383fb5e0c..0202ae4ab 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -25,20 +25,27 @@ Multi-package colcon workspace under `src/`: ## Architecture +The package is organised in two named layers under `src/ros2_medkit_gateway/`: + +- **`include/.../core/`** + **`src/core/`** - middleware-neutral business logic. Compiles into the `gateway_core` STATIC library with no ROS dependencies. Hosts the HTTP routing, request handlers, JWT auth, fault model, peer aggregation, manifest parser, entity cache, and the neutral managers (lock, bulk-data, subscription, script, update, plugin). +- The remainder of `src/` - ROS adapter layer. Compiles into `gateway_ros2` (links `gateway_core` publicly). Hosts `gateway_node` (rclcpp::Node), the ROS-coupled managers (data access, operation, configuration, fault facade, log, trigger), `runtime_discovery`, `native_topic_sampler`, and ROS-specific provider implementations. + ``` -GatewayNode (src/ros2_medkit_gateway/src/gateway_node.cpp) +GatewayNode (src/main.cpp + src/gateway_node.cpp) [gateway_ros2] ├── DiscoveryManager - Entity discovery (runtime / manifest / hybrid) -│ └── EntityCache - Thread-safe in-memory entity store +│ └── EntityCache - Thread-safe in-memory entity store [core] ├── DataAccessManager - Topic sampling and publishing ├── OperationManager - Service calls and action goals ├── ConfigurationManager - ROS 2 parameter CRUD ├── FaultManager - Fault query/clear, SSE streams (delegates to fault_manager package) ├── LogManager - /rosout ring buffer + plugin delegation -├── PluginManager - Dynamic plugin loading (.so), provider interfaces -└── RESTServer - cpp-httplib HTTP server (separate thread) +├── PluginManager - Dynamic plugin loading (.so), provider interfaces [core] +└── RESTServer - cpp-httplib HTTP server (separate thread) [core] └── HandlerContext - Shared validation, entity lookup, error/JSON helpers ``` +The `gateway_core_purity` linter (greps for ROS includes under `core/`) and the `test_gateway_core_smoke` link-time test (compiles a TU against `gateway_core` alone) enforce the contract that the neutral layer carries no ROS coupling. + ### Entity Model (SOVD-aligned) Defined in `include/ros2_medkit_gateway/models/`: @@ -67,14 +74,14 @@ Each entity type supports specific collections: - **C++17** with `-Wall -Wextra -Wpedantic -Wshadow -Wconversion` - **Formatting**: Google-based clang-format, 120 cols, 2-space indent, middle pointer alignment (`Type * ptr`) - **Headers**: `#pragma once`, Apache 2.0 copyright (year 2026 for new files) -- **Namespace**: `ros2_medkit_gateway` +- **Namespace**: `medkit::` for code under `core/`, `medkit::` (via the `ros2_medkit_gateway = medkit` alias in `include/ros2_medkit_gateway/compat.hpp`) for everything else. Existing code referencing `ros2_medkit_gateway::` keeps compiling via the alias during the migration. - **Error handling**: `tl::expected` for fallible operations - NOT exceptions in handlers - **Thread safety**: Always get fresh `EntityCache` via `ctx_.node()->get_thread_safe_cache()` (in handlers) - **Header-only libs**: nlohmann::json, tl::expected, jwt-cpp, cpp-httplib ## Handler Pattern (follow for ALL new handlers) -Handlers live in `src/http/handlers/`, one file per group. All handlers take `HandlerContext&` in constructor. +Handlers live under `src/core/http/handlers/` (most groups - they are middleware-neutral) and `src/http/handlers/` (handlers that pull rclcpp transitively, currently `handler_context`, `fault_handlers`, `sse_fault_handler`, `cyclic_subscription_handlers`). One file per group. All handlers take `HandlerContext&` in constructor. ```cpp void ExampleHandlers::handle_request(const httplib::Request & req, httplib::Response & res) { @@ -148,7 +155,7 @@ Handler classes: `HealthHandlers`, `DiscoveryHandlers`, `DataHandlers`, `Operati ## Build System -**Static library pattern**: `gateway_lib` bundles all source for shared use between executable and tests. +**Static library pattern**: two layered targets - `gateway_core` (sources under `src/core/`, no ROS dependencies, links cpp-httplib + nlohmann/json + yaml-cpp + tl::expected + jwt-cpp + OpenSSL + SQLite + dl) and `gateway_ros2` (the remaining ROS-adapter sources, links `gateway_core` publicly via `medkit_target_dependencies()`). The `gateway_node` executable and existing test targets link `gateway_ros2` so they transitively get both layers. The link-only smoke test `test_gateway_core_smoke` deliberately links `gateway_core` plus GTest with no `ament_target_dependencies` to enforce the neutral contract. **CMake modules** in `cmake/`: - `ROS2MedkitCcache.cmake` - auto-detect ccache @@ -211,9 +218,13 @@ Plugins provide custom backends via provider interfaces: | Provider | Interface | Purpose | |----------|-----------|---------| -| `LogProvider` | `providers/log_provider.hpp` | Custom log backends | -| `UpdateProvider` | `providers/update_provider.hpp` | Software update management | -| `IntrospectionProvider` | `providers/introspection_provider.hpp` | Custom entity introspection | +| `DataProvider` | `core/providers/data_provider.hpp` | Per-entity data resource backend | +| `OperationProvider` | `core/providers/operation_provider.hpp` | Per-entity operation backend | +| `FaultProvider` | `core/providers/fault_provider.hpp` | Per-entity fault backend | +| `LogProvider` | `core/providers/log_provider.hpp` | Custom log backends | +| `UpdateProvider` | `core/providers/update_provider.hpp` | Software update management | +| `ScriptProvider` | `core/providers/script_provider.hpp` | Custom script execution backends | +| `IntrospectionProvider` | `core/providers/introspection_provider.hpp` | Custom entity introspection | Plugins loaded as `.so` files with `extern "C"` factory. Provider interfaces return typed C++ structs (not JSON) - manager layer handles serialization. Plugin failures are caught and isolated. @@ -263,8 +274,8 @@ When reviewing pull requests, apply these rules to the diff. Flag violations as Every code change must include corresponding tests. A feature without tests is not complete. **Unit tests (C++ GTest)** - required for all new logic: -- **Flag** new or modified files in `src/http/handlers/` without a corresponding `test/test_*_handlers.cpp` in the diff. Handler unit tests verify request validation, error responses, and edge cases without ROS 2 runtime. -- **Flag** new or modified manager classes (`src/*.cpp`) without corresponding `test/test_*.cpp`. Manager tests verify business logic in isolation. +- **Flag** new or modified files in `src/core/http/handlers/` or `src/http/handlers/` without a corresponding `test/test_*_handlers.cpp` in the diff. Handler unit tests verify request validation, error responses, and edge cases without ROS 2 runtime. +- **Flag** new or modified manager classes (`src/core/managers/*.cpp` or `src/*.cpp`) without corresponding `test/test_*.cpp`. Manager tests verify business logic in isolation. - **Flag** new utility functions or static methods without unit tests covering their behavior. **Integration tests (Python launch_testing)** - required for all endpoint changes: @@ -280,8 +291,9 @@ Every code change must include corresponding tests. A feature without tests is n ### Build & CMake -- **Flag** new `.cpp` source files that aren't added to the `gateway_lib` STATIC library target in CMakeLists.txt. -- **Flag** new test targets that don't link to `gateway_lib`. +- **Flag** new `.cpp` source files under `src/core/` that aren't picked up by `gateway_core`'s `GLOB_RECURSE` source list, or new ROS-adapter `.cpp` files that aren't added to the `gateway_ros2` STATIC library target in CMakeLists.txt. +- **Flag** any `#include ` or message-package include in a file under `core/` - the layer must stay middleware-neutral. The `gateway_core_purity` linter and `test_gateway_core_smoke` link test enforce this; do not paper over their failures. +- **Flag** new test targets that don't link to `gateway_ros2` (the default), unless the test is intentionally a core-only smoke test linking `gateway_core` directly. - **Flag** use of `ament_target_dependencies()` - use `medkit_target_dependencies()` instead (removed in Rolling). - **Flag** direct `find_package(yaml-cpp)` or `find_package(httplib)` - use `medkit_find_yaml_cpp()` / `medkit_find_cpp_httplib()` for multi-distro compatibility. diff --git a/docs/api/warning_codes.rst b/docs/api/warning_codes.rst index 1d96b3d4f..21902b6cc 100644 --- a/docs/api/warning_codes.rst +++ b/docs/api/warning_codes.rst @@ -18,7 +18,7 @@ Codes are stable machine-readable identifiers: renaming a code is a breaking change for downstream consumers that key on the string. The canonical list of codes is maintained in -``src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/warning_codes.hpp``; +``src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/warning_codes.hpp``; this page mirrors it for API consumers. .. list-table:: diff --git a/docs/tutorials/plugin-system.rst b/docs/tutorials/plugin-system.rst index 2d4be4599..0452db015 100644 --- a/docs/tutorials/plugin-system.rst +++ b/docs/tutorials/plugin-system.rst @@ -77,7 +77,7 @@ Writing a Plugin #include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" #include "ros2_medkit_gateway/plugins/plugin_types.hpp" - #include "ros2_medkit_gateway/updates/update_provider.hpp" + #include "ros2_medkit_gateway/core/providers/update_provider.hpp" using namespace ros2_medkit_gateway; @@ -148,7 +148,7 @@ implements the provider interface, even if the class inherits from it. .. code-block:: cmake add_library(my_plugin MODULE src/my_plugin.cpp) - target_link_libraries(my_plugin gateway_lib) + target_link_libraries(my_plugin gateway_ros2) 4. Install the ``.so`` and add its path to ``gateway_params.yaml``. @@ -162,7 +162,7 @@ A self-contained plugin implementing UpdateProvider (copy-paste starting point): // my_ota_plugin.cpp #include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" #include "ros2_medkit_gateway/plugins/plugin_types.hpp" - #include "ros2_medkit_gateway/updates/update_provider.hpp" + #include "ros2_medkit_gateway/core/providers/update_provider.hpp" #include @@ -566,7 +566,7 @@ execute, and control executions: .. code-block:: cpp #include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" - #include "ros2_medkit_gateway/scripts/script_provider.hpp" + #include "ros2_medkit_gateway/core/providers/script_provider.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/test/test_param_beacon_plugin.cpp b/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/test/test_param_beacon_plugin.cpp index a0453b63f..009a304a1 100644 --- a/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/test/test_param_beacon_plugin.cpp +++ b/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon/test/test_param_beacon_plugin.cpp @@ -47,7 +47,7 @@ extern "C" int plugin_api_version(); extern "C" GatewayPlugin * create_plugin(); extern "C" IntrospectionProvider * get_introspection_provider(GatewayPlugin * plugin); -// Stubs for PluginRequest/PluginResponse (implemented in gateway_lib, not linked into tests) +// Stubs for PluginRequest/PluginResponse (implemented in gateway_core, not linked into tests) namespace ros2_medkit_gateway { PluginRequest::PluginRequest(const void * impl) : impl_(impl) { } diff --git a/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/CMakeLists.txt b/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/CMakeLists.txt index a08de3876..eba92b8fb 100644 --- a/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/CMakeLists.txt +++ b/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/CMakeLists.txt @@ -34,7 +34,8 @@ find_package(diagnostic_msgs REQUIRED) find_package(nlohmann_json REQUIRED) # MODULE target: loaded via dlopen at runtime by PluginManager. -# Symbols from gateway_lib are resolved from the host process at runtime. +# Symbols from gateway_ros2 (and gateway_core transitively) are resolved +# from the host process at runtime. # We only need headers at compile time (via medkit_target_dependencies). add_library(topic_beacon_plugin MODULE src/topic_beacon_plugin.cpp diff --git a/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/test/test_topic_beacon_plugin.cpp b/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/test/test_topic_beacon_plugin.cpp index a3ad1ab39..c2dde4a7a 100644 --- a/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/test/test_topic_beacon_plugin.cpp +++ b/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon/test/test_topic_beacon_plugin.cpp @@ -44,7 +44,7 @@ extern "C" int plugin_api_version(); extern "C" GatewayPlugin * create_plugin(); extern "C" IntrospectionProvider * get_introspection_provider(GatewayPlugin * plugin); -// Stubs for PluginRequest/PluginResponse (implemented in gateway_lib, not linked into tests) +// Stubs for PluginRequest/PluginResponse (implemented in gateway_core, not linked into tests) namespace ros2_medkit_gateway { PluginRequest::PluginRequest(const void * impl) : impl_(impl) { } diff --git a/src/ros2_medkit_gateway/CMakeLists.txt b/src/ros2_medkit_gateway/CMakeLists.txt index ccfbedb2d..40fc7ef60 100644 --- a/src/ros2_medkit_gateway/CMakeLists.txt +++ b/src/ros2_medkit_gateway/CMakeLists.txt @@ -82,128 +82,140 @@ include_directories(SYSTEM src/vendored/mdns) # Include directories include_directories(include) -# Gateway library (shared between executable and tests for coverage) -add_library(gateway_lib STATIC - src/config.cpp - src/entity_validation.cpp - # ROS 2 shared subscription infrastructure - src/ros2_common/ros2_subscription_executor.cpp - src/ros2_common/ros2_subscription_slot.cpp - # Data domain (SOVD /data) - src/data/ros2_topic_data_provider.cpp - src/gateway_node.cpp - src/data_access_manager.cpp - src/type_introspection.cpp - src/operation_manager.cpp +# ─── Neutral core static library ─────────────────────────────────────────── +# Middleware-neutral business logic. No ROS dependencies. Compiled from +# sources under src/core/ which were relocated from the flat src/ layout +# during the layered-architecture refactor. +file(GLOB_RECURSE GATEWAY_CORE_SOURCES + CONFIGURE_DEPENDS + "src/core/*.cpp" +) + +add_library(gateway_core STATIC ${GATEWAY_CORE_SOURCES}) + +target_include_directories(gateway_core + PUBLIC + $ + $ + PRIVATE + # Private implementation headers for the openapi module (not installed) + $ +) + +target_link_libraries(gateway_core + PUBLIC + cpp_httplib_target + nlohmann_json::nlohmann_json + yaml-cpp::yaml-cpp + OpenSSL::SSL + OpenSSL::Crypto + tl::expected + jwt-cpp::jwt-cpp + SQLite::SQLite3 + ${CMAKE_DL_LIBS} +) + +set_target_properties(gateway_core PROPERTIES + POSITION_INDEPENDENT_CODE ON + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF +) + +# Pass version from package.xml to version.hpp +target_compile_definitions(gateway_core PUBLIC GATEWAY_VERSION_STRING="${GATEWAY_VERSION}") + +# Core PCH - heavy headers used across the neutral layer, no ROS includes. +# Speeds up full builds by ~30-40%. Disable with -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON. +target_precompile_headers(gateway_core PRIVATE + + + + + + + + + + + + + +) + +# ─── ROS adapter static library ──────────────────────────────────────────── +# Files that depend on rclcpp / rcl_interfaces / message-package interfaces. +# Layered atop gateway_core via PUBLIC link so the executable and tests +# transitively get both layers from a single dependency. +add_library(gateway_ros2 STATIC + src/aggregation/aggregation_manager.cpp src/configuration_manager.cpp - src/fault_manager.cpp - src/fault_manager_paths.cpp - src/log_manager.cpp - src/subscription_manager.cpp - src/lock_manager.cpp - src/resource_change_notifier.cpp - src/resource_sampler.cpp - src/subscription_transport.cpp - # Entity resource model - src/models/entity_types.cpp - src/models/entity_capabilities.cpp - src/models/thread_safe_entity_cache.cpp - src/models/aggregation_service.cpp - # Discovery module - src/discovery/discovery_enums.cpp + src/data_access_manager.cpp + src/data/ros2_topic_data_provider.cpp + src/default_script_provider.cpp src/discovery/discovery_manager.cpp - src/discovery/runtime_discovery.cpp src/discovery/hybrid_discovery.cpp - src/discovery/merge_pipeline.cpp src/discovery/layers/manifest_layer.cpp - src/discovery/layers/runtime_layer.cpp src/discovery/layers/plugin_layer.cpp - # Host info provider (default component from host system) - src/discovery/host_info_provider.cpp - # Discovery models (with .cpp serialization) - src/discovery/models/app.cpp - src/discovery/models/function.cpp - # Manifest parser, validator and manager - src/discovery/manifest/manifest_parser.cpp - src/discovery/manifest/manifest_validator.cpp + src/discovery/layers/runtime_layer.cpp src/discovery/manifest/manifest_manager.cpp + src/discovery/manifest/manifest_parser.cpp src/discovery/manifest/runtime_linker.cpp - # HTTP module (subfolder) - src/http/http_server.cpp - src/http/rest_server.cpp - src/http/rate_limiter.cpp - # HTTP handlers - discovery (unified) - src/http/handlers/discovery_handlers.cpp - # HTTP handlers - utilities - src/http/handlers/capability_builder.cpp - # HTTP handlers - resource handlers (unified across entity types) + src/discovery/merge_pipeline.cpp + src/discovery/runtime_discovery.cpp + src/fault_manager.cpp + src/fault_manager_paths.cpp + src/gateway_node.cpp + src/http/handlers/auth_handlers.cpp + src/http/handlers/bulkdata_handlers.cpp + src/http/handlers/config_handlers.cpp + src/http/handlers/cyclic_subscription_handlers.cpp src/http/handlers/data_handlers.cpp - # HTTP handlers - other + src/http/handlers/discovery_handlers.cpp + src/http/handlers/docs_handlers.cpp + src/http/handlers/fault_handlers.cpp src/http/handlers/handler_context.cpp src/http/handlers/health_handlers.cpp - src/http/handlers/operation_handlers.cpp - src/http/handlers/config_handlers.cpp - src/http/handlers/fault_handlers.cpp - src/http/handlers/log_handlers.cpp src/http/handlers/lock_handlers.cpp - src/http/handlers/bulkdata_handlers.cpp + src/http/handlers/log_handlers.cpp + src/http/handlers/operation_handlers.cpp + src/http/handlers/script_handlers.cpp src/http/handlers/sse_fault_handler.cpp - src/http/handlers/cyclic_subscription_handlers.cpp src/http/handlers/sse_transport_provider.cpp - src/http/handlers/auth_handlers.cpp - src/http/handlers/docs_handlers.cpp - # Bulk data storage - src/bulk_data_store.cpp - # HTTP utilities - src/http/x_medkit.cpp - src/http/entity_path_utils.cpp - # Auth module (subfolder) - src/auth/auth_config.cpp - src/auth/auth_models.cpp - src/auth/auth_manager.cpp - src/auth/auth_middleware.cpp - src/auth/auth_requirement_policy.cpp - # Updates module - src/updates/update_manager.cpp - # Scripts module - src/script_manager.cpp - src/default_script_provider.cpp - # HTTP handlers - scripts - src/http/handlers/script_handlers.cpp - # HTTP handlers - updates + src/http/handlers/trigger_handlers.cpp src/http/handlers/update_handlers.cpp - # Plugin framework + src/http/http_server.cpp + src/http/rest_server.cpp + src/log_manager.cpp + src/operation_manager.cpp + src/openapi/capability_generator.cpp + src/openapi/openapi_spec_builder.cpp + src/openapi/path_builder.cpp + src/openapi/schema_builder.cpp src/plugins/plugin_context.cpp + src/plugins/plugin_http_types.cpp src/plugins/plugin_loader.cpp src/plugins/plugin_manager.cpp - src/plugins/plugin_http_types.cpp - # OpenAPI documentation module - src/openapi/schema_builder.cpp - src/openapi/path_builder.cpp - src/openapi/openapi_spec_builder.cpp - src/openapi/path_resolver.cpp - src/openapi/capability_generator.cpp - src/openapi/route_registry.cpp - # Trigger persistence - src/sqlite_trigger_store.cpp - # Trigger management - src/trigger_manager.cpp - # Trigger fault subscriber (ROS 2 topic -> notifier bridge) + src/ros2_common/ros2_subscription_executor.cpp + src/ros2_common/ros2_subscription_slot.cpp + src/script_manager.cpp src/trigger_fault_subscriber.cpp - # Trigger topic subscriber (data triggers -> ROS 2 subscriptions) + src/trigger_manager.cpp src/trigger_topic_subscriber.cpp - # Trigger HTTP handlers - src/http/handlers/trigger_handlers.cpp - # Aggregation module - src/aggregation/peer_client.cpp - src/aggregation/entity_merger.cpp - src/aggregation/classification.cpp - src/aggregation/aggregation_manager.cpp - src/aggregation/mdns_discovery.cpp - src/aggregation/sse_stream_proxy.cpp + src/type_introspection.cpp ) -medkit_target_dependencies(gateway_lib +# Private implementation headers for openapi module (shared by both layers) +target_include_directories(gateway_ros2 PRIVATE + $ +) + +# Link gateway_core first using plain signature (before medkit_target_dependencies +# calls ament_target_dependencies which also uses the plain signature). This avoids +# the CMake "mixed plain/keyword target_link_libraries" error. +target_link_libraries(gateway_ros2 gateway_core) + +medkit_target_dependencies(gateway_ros2 rclcpp std_msgs std_srvs @@ -216,58 +228,34 @@ medkit_target_dependencies(gateway_lib rosidl_typesupport_introspection_cpp ) -target_link_libraries(gateway_lib - cpp_httplib_target - nlohmann_json::nlohmann_json - yaml-cpp::yaml-cpp - OpenSSL::SSL - OpenSSL::Crypto - tl::expected - jwt-cpp::jwt-cpp - SQLite::SQLite3 - ${CMAKE_DL_LIBS} +set_target_properties(gateway_ros2 PROPERTIES + POSITION_INDEPENDENT_CODE ON + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON ) -# Precompiled headers - heavy headers used across most translation units. -# Speeds up full builds by ~30-40%. Disable with -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON. -target_precompile_headers(gateway_lib PRIVATE - - - - - - - - - - +# ROS adapter PCH - extends core PCH with rclcpp on top. +target_precompile_headers(gateway_ros2 PRIVATE - - - ) -set_target_properties(gateway_lib PROPERTIES POSITION_INDEPENDENT_CODE ON) - -# Pass version from package.xml to version.hpp -target_compile_definitions(gateway_lib PUBLIC GATEWAY_VERSION_STRING="${GATEWAY_VERSION}") # Gateway node executable add_executable(gateway_node src/main.cpp) -target_link_libraries(gateway_node gateway_lib) +target_link_libraries(gateway_node gateway_ros2) # Export symbols to dlopen'd plugins (PluginContext::send_json, send_error, etc.) set_target_properties(gateway_node PROPERTIES ENABLE_EXPORTS ON) # Apply Swagger UI compile definition and embed assets if(ENABLE_SWAGGER_UI) - target_compile_definitions(gateway_lib PRIVATE ENABLE_SWAGGER_UI) + target_compile_definitions(gateway_ros2 PRIVATE ENABLE_SWAGGER_UI) target_compile_definitions(gateway_node PRIVATE ENABLE_SWAGGER_UI) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/SwaggerUI.cmake) - target_compile_definitions(gateway_lib PRIVATE SWAGGER_UI_VERSION="${SWAGGER_UI_VERSION}") + target_compile_definitions(gateway_ros2 PRIVATE SWAGGER_UI_VERSION="${SWAGGER_UI_VERSION}") endif() # Apply coverage flags to main targets if(ENABLE_COVERAGE) - foreach(_target gateway_lib gateway_node) + foreach(_target gateway_ros2 gateway_node) target_compile_options(${_target} PRIVATE --coverage -O0 -g) target_link_options(${_target} PRIVATE --coverage) endforeach() @@ -347,233 +335,264 @@ if(BUILD_TESTING) include(ROS2MedkitTestDomain) medkit_init_test_domains(START 30 END 89) + # ─── Core purity check ──────────────────────────────────────────────────── + # Fails the build if any file under include/ros2_medkit_gateway/core/ or + # src/core/ directly includes a ROS header. The neutral layer's contract + # is enforced both by the link-time smoke test (test_gateway_core_smoke) + # and by this grep-based scan that catches misuse before linkage. + add_test( + NAME gateway_core_purity + COMMAND bash "${CMAKE_CURRENT_SOURCE_DIR}/scripts/check_core_purity.sh" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + set_tests_properties(gateway_core_purity PROPERTIES LABELS "linter") + + # ─── gateway_core link-time smoke test ──────────────────────────────────── + # Compiles a translation unit including a sampling of core/ headers and + # links exclusively against gateway_core + GTest. No ament_target_dependencies + # are applied, so any rclcpp transitive include reaching this TU surfaces + # as a missing-symbol link error. + find_package(GTest REQUIRED) + add_executable(test_gateway_core_smoke test/test_gateway_core_smoke.cpp) + target_link_libraries(test_gateway_core_smoke + PRIVATE + gateway_core + GTest::gtest + GTest::gtest_main + ) + add_test( + NAME gateway_core_smoke + COMMAND $ + ) + set_tests_properties(gateway_core_smoke PROPERTIES LABELS "unit") + # Add GTest find_package(ament_cmake_gtest REQUIRED) find_package(rclcpp_action REQUIRED) find_package(example_interfaces REQUIRED) ament_add_gtest(test_gateway_node test/test_gateway_node.cpp) - target_link_libraries(test_gateway_node gateway_lib) + target_link_libraries(test_gateway_node gateway_ros2) medkit_set_test_domain(test_gateway_node) ament_add_gtest(test_entity_change_scope test/test_entity_change_scope.cpp) - target_link_libraries(test_entity_change_scope gateway_lib) + target_link_libraries(test_entity_change_scope gateway_ros2) ament_add_gtest(test_manifest_fragments test/test_manifest_fragments.cpp) - target_link_libraries(test_manifest_fragments gateway_lib) + target_link_libraries(test_manifest_fragments gateway_ros2) ament_add_gtest(test_plugin_notify_integration test/test_plugin_notify_integration.cpp) - target_link_libraries(test_plugin_notify_integration gateway_lib) + target_link_libraries(test_plugin_notify_integration gateway_ros2) medkit_set_test_domain(test_plugin_notify_integration) ament_add_gtest(test_auth_manager test/test_auth_manager.cpp) - target_link_libraries(test_auth_manager gateway_lib) + target_link_libraries(test_auth_manager gateway_ros2) ament_add_gtest(test_generic_client_compat test/test_generic_client_compat.cpp) - target_link_libraries(test_generic_client_compat gateway_lib) + target_link_libraries(test_generic_client_compat gateway_ros2) medkit_target_dependencies(test_generic_client_compat rclcpp std_srvs) medkit_set_test_domain(test_generic_client_compat) ament_add_gtest(test_operation_manager test/test_operation_manager.cpp) - target_link_libraries(test_operation_manager gateway_lib) + target_link_libraries(test_operation_manager gateway_ros2) medkit_set_test_domain(test_operation_manager) ament_add_gtest(test_configuration_manager test/test_configuration_manager.cpp) - target_link_libraries(test_configuration_manager gateway_lib) + target_link_libraries(test_configuration_manager gateway_ros2) medkit_set_test_domain(test_configuration_manager) find_package(std_msgs REQUIRED) # Add DiscoveryManager tests ament_add_gtest(test_discovery_manager test/test_discovery_manager.cpp) - target_link_libraries(test_discovery_manager gateway_lib) + target_link_libraries(test_discovery_manager gateway_ros2) medkit_target_dependencies(test_discovery_manager std_msgs) medkit_set_test_domain(test_discovery_manager) # Add RuntimeDiscoveryStrategy tests ament_add_gtest(test_runtime_discovery test/test_runtime_discovery.cpp) - target_link_libraries(test_runtime_discovery gateway_lib) + target_link_libraries(test_runtime_discovery gateway_ros2) medkit_set_test_domain(test_runtime_discovery) # Add TLS configuration tests ament_add_gtest(test_tls_config test/test_tls_config.cpp) - target_link_libraries(test_tls_config gateway_lib) + target_link_libraries(test_tls_config gateway_ros2) # Add FaultManager tests ament_add_gtest(test_fault_manager test/test_fault_manager.cpp) - target_link_libraries(test_fault_manager gateway_lib) + target_link_libraries(test_fault_manager gateway_ros2) medkit_target_dependencies(test_fault_manager rclcpp ros2_medkit_msgs) medkit_set_test_domain(test_fault_manager) # Add error info tests ament_add_gtest(test_error_info test/test_error_info.cpp) - target_link_libraries(test_error_info gateway_lib) + target_link_libraries(test_error_info gateway_ros2) # Add ROS 2 subscription executor tests ament_add_gtest(test_ros2_subscription_executor test/test_ros2_subscription_executor.cpp) - target_link_libraries(test_ros2_subscription_executor gateway_lib) + target_link_libraries(test_ros2_subscription_executor gateway_ros2) medkit_target_dependencies(test_ros2_subscription_executor rclcpp std_msgs) medkit_set_test_domain(test_ros2_subscription_executor) # Add ROS 2 subscription slot tests ament_add_gtest(test_ros2_subscription_slot test/test_ros2_subscription_slot.cpp) - target_link_libraries(test_ros2_subscription_slot gateway_lib) + target_link_libraries(test_ros2_subscription_slot gateway_ros2) medkit_target_dependencies(test_ros2_subscription_slot rclcpp std_msgs) medkit_set_test_domain(test_ros2_subscription_slot) # Add TopicDataProvider interface tests (pure C++, no rclcpp init required) ament_add_gtest(test_topic_data_provider_interface test/test_topic_data_provider_interface.cpp) - target_link_libraries(test_topic_data_provider_interface gateway_lib) + target_link_libraries(test_topic_data_provider_interface gateway_ros2) # Add Ros2TopicDataProvider tests (rclcpp required) ament_add_gtest(test_ros2_topic_data_provider test/test_ros2_topic_data_provider.cpp) - target_link_libraries(test_ros2_topic_data_provider gateway_lib) + target_link_libraries(test_ros2_topic_data_provider gateway_ros2) medkit_target_dependencies(test_ros2_topic_data_provider rclcpp std_msgs) medkit_set_test_domain(test_ros2_topic_data_provider) # Add discovery models tests ament_add_gtest(test_discovery_models test/test_discovery_models.cpp) - target_link_libraries(test_discovery_models gateway_lib) + target_link_libraries(test_discovery_models gateway_ros2) # Add host info provider tests ament_add_gtest(test_host_info_provider test/test_host_info_provider.cpp) - target_link_libraries(test_host_info_provider gateway_lib) + target_link_libraries(test_host_info_provider gateway_ros2) # Add discovery handlers tests ament_add_gtest(test_discovery_handlers test/test_discovery_handlers.cpp) - target_link_libraries(test_discovery_handlers gateway_lib) + target_link_libraries(test_discovery_handlers gateway_ros2) medkit_set_test_domain(test_discovery_handlers) # Add manifest parser tests ament_add_gtest(test_manifest_parser test/test_manifest_parser.cpp) - target_link_libraries(test_manifest_parser gateway_lib) + target_link_libraries(test_manifest_parser gateway_ros2) # Add manifest validator tests ament_add_gtest(test_manifest_validator test/test_manifest_validator.cpp) - target_link_libraries(test_manifest_validator gateway_lib) + target_link_libraries(test_manifest_validator gateway_ros2) # Add manifest manager tests ament_add_gtest(test_manifest_manager test/test_manifest_manager.cpp) - target_link_libraries(test_manifest_manager gateway_lib) + target_link_libraries(test_manifest_manager gateway_ros2) # Add runtime linker tests ament_add_gtest(test_runtime_linker test/test_runtime_linker.cpp) - target_link_libraries(test_runtime_linker gateway_lib) + target_link_libraries(test_runtime_linker gateway_ros2) # Add merge pipeline tests ament_add_gtest(test_merge_pipeline test/test_merge_pipeline.cpp) - target_link_libraries(test_merge_pipeline gateway_lib) + target_link_libraries(test_merge_pipeline gateway_ros2) # Add capability builder tests ament_add_gtest(test_capability_builder test/test_capability_builder.cpp) - target_link_libraries(test_capability_builder gateway_lib) + target_link_libraries(test_capability_builder gateway_ros2) # Add handler context tests ament_add_gtest(test_handler_context test/test_handler_context.cpp) - target_link_libraries(test_handler_context gateway_lib) + target_link_libraries(test_handler_context gateway_ros2) medkit_set_test_domain(test_handler_context) # Add x-medkit extension tests ament_add_gtest(test_x_medkit test/test_x_medkit.cpp) - target_link_libraries(test_x_medkit gateway_lib) + target_link_libraries(test_x_medkit gateway_ros2) # Add rate limiter tests ament_add_gtest(test_rate_limiter test/test_rate_limiter.cpp) - target_link_libraries(test_rate_limiter gateway_lib) + target_link_libraries(test_rate_limiter gateway_ros2) # Add auth config tests ament_add_gtest(test_auth_config test/test_auth_config.cpp) - target_link_libraries(test_auth_config gateway_lib) + target_link_libraries(test_auth_config gateway_ros2) # Add data access manager tests ament_add_gtest(test_data_access_manager test/test_data_access_manager.cpp) - target_link_libraries(test_data_access_manager gateway_lib) + target_link_libraries(test_data_access_manager gateway_ros2) medkit_target_dependencies(test_data_access_manager rclcpp std_msgs) medkit_set_test_domain(test_data_access_manager) # Add entity resource model tests ament_add_gtest(test_entity_resource_model test/test_entity_resource_model.cpp) - target_link_libraries(test_entity_resource_model gateway_lib) + target_link_libraries(test_entity_resource_model gateway_ros2) # Function/Area resource collection aggregation tests ament_add_gtest(test_function_resource_collections test/test_function_resource_collections.cpp) - target_link_libraries(test_function_resource_collections gateway_lib) + target_link_libraries(test_function_resource_collections gateway_ros2) # Add entity path utils tests ament_add_gtest(test_entity_path_utils test/test_entity_path_utils.cpp) - target_link_libraries(test_entity_path_utils gateway_lib) + target_link_libraries(test_entity_path_utils gateway_ros2) # Add fault handlers tests (SOVD response building) ament_add_gtest(test_fault_handlers test/test_fault_handlers.cpp) - target_link_libraries(test_fault_handlers gateway_lib) + target_link_libraries(test_fault_handlers gateway_ros2) # Add bulk data store tests ament_add_gtest(test_bulk_data_store test/test_bulk_data_store.cpp) - target_link_libraries(test_bulk_data_store gateway_lib) + target_link_libraries(test_bulk_data_store gateway_ros2) # Add bulk data handlers tests ament_add_gtest(test_bulkdata_handlers test/test_bulkdata_handlers.cpp) - target_link_libraries(test_bulkdata_handlers gateway_lib) + target_link_libraries(test_bulkdata_handlers gateway_ros2) # Add subscription manager tests ament_add_gtest(test_subscription_manager test/test_subscription_manager.cpp) - target_link_libraries(test_subscription_manager gateway_lib) + target_link_libraries(test_subscription_manager gateway_ros2) # Add resource sampler registry tests ament_add_gtest(test_resource_sampler_registry test/test_resource_sampler_registry.cpp) - target_link_libraries(test_resource_sampler_registry gateway_lib) + target_link_libraries(test_resource_sampler_registry gateway_ros2) # Add transport registry tests ament_add_gtest(test_transport_registry test/test_transport_registry.cpp) - target_link_libraries(test_transport_registry gateway_lib) + target_link_libraries(test_transport_registry gateway_ros2) # Add cyclic subscription handler tests ament_add_gtest(test_cyclic_subscription_handlers test/test_cyclic_subscription_handlers.cpp) - target_link_libraries(test_cyclic_subscription_handlers gateway_lib) + target_link_libraries(test_cyclic_subscription_handlers gateway_ros2) # Add SSE transport provider tests ament_add_gtest(test_sse_transport_provider test/test_sse_transport_provider.cpp) - target_link_libraries(test_sse_transport_provider gateway_lib) + target_link_libraries(test_sse_transport_provider gateway_ros2) # Add SSE fault handler tests ament_add_gtest(test_sse_fault_handler test/test_sse_fault_handler.cpp) - target_link_libraries(test_sse_fault_handler gateway_lib) + target_link_libraries(test_sse_fault_handler gateway_ros2) medkit_target_dependencies(test_sse_fault_handler rclcpp ros2_medkit_msgs) medkit_set_test_domain(test_sse_fault_handler) # Add update manager tests ament_add_gtest(test_update_manager test/test_update_manager.cpp) - target_link_libraries(test_update_manager gateway_lib) + target_link_libraries(test_update_manager gateway_ros2) # Add script manager tests ament_add_gtest(test_script_manager test/test_script_manager.cpp) - target_link_libraries(test_script_manager gateway_lib) + target_link_libraries(test_script_manager gateway_ros2) # Add default script provider tests ament_add_gtest(test_default_script_provider test/test_default_script_provider.cpp) - target_link_libraries(test_default_script_provider gateway_lib) + target_link_libraries(test_default_script_provider gateway_ros2) # Add script handler tests ament_add_gtest(test_script_handlers test/test_script_handlers.cpp) - target_link_libraries(test_script_handlers gateway_lib) + target_link_libraries(test_script_handlers gateway_ros2) medkit_set_test_domain(test_script_handlers) # Add data handler tests ament_add_gtest(test_data_handlers test/test_data_handlers.cpp) - target_link_libraries(test_data_handlers gateway_lib) + target_link_libraries(test_data_handlers gateway_ros2) # Add auth handler tests ament_add_gtest(test_auth_handlers test/test_auth_handlers.cpp) - target_link_libraries(test_auth_handlers gateway_lib) + target_link_libraries(test_auth_handlers gateway_ros2) # Add health handler tests ament_add_gtest(test_health_handlers test/test_health_handlers.cpp) - target_link_libraries(test_health_handlers gateway_lib) + target_link_libraries(test_health_handlers gateway_ros2) medkit_set_test_domain(test_health_handlers) # Add operation handler tests ament_add_gtest(test_operation_handlers test/test_operation_handlers.cpp) - target_link_libraries(test_operation_handlers gateway_lib) + target_link_libraries(test_operation_handlers gateway_ros2) medkit_target_dependencies(test_operation_handlers rclcpp rclcpp_action std_srvs example_interfaces) medkit_set_test_domain(test_operation_handlers) @@ -599,7 +618,7 @@ if(BUILD_TESTING) add_library(test_gateway_plugin MODULE test/demo_nodes/test_gateway_plugin.cpp ) - target_link_libraries(test_gateway_plugin gateway_lib) + target_link_libraries(test_gateway_plugin gateway_ros2) install(TARGETS test_gateway_plugin LIBRARY DESTINATION lib/${PROJECT_NAME} ) @@ -620,130 +639,130 @@ if(BUILD_TESTING) # Add plugin loader tests ament_add_gtest(test_plugin_loader test/test_plugin_loader.cpp) - target_link_libraries(test_plugin_loader gateway_lib) + target_link_libraries(test_plugin_loader gateway_ros2) medkit_target_dependencies(test_plugin_loader ament_index_cpp) # Plugin config from YAML tests ament_add_gtest(test_plugin_config test/test_plugin_config.cpp) - target_link_libraries(test_plugin_config gateway_lib) + target_link_libraries(test_plugin_config gateway_ros2) medkit_set_test_domain(test_plugin_config) # Plugin manager tests ament_add_gtest(test_plugin_manager test/test_plugin_manager.cpp) - target_link_libraries(test_plugin_manager gateway_lib) + target_link_libraries(test_plugin_manager gateway_ros2) # Plugin entity routing tests ament_add_gtest(test_plugin_entity_routing test/test_plugin_entity_routing.cpp) - target_link_libraries(test_plugin_entity_routing gateway_lib) + target_link_libraries(test_plugin_entity_routing gateway_ros2) # Plugin HTTP types tests ament_add_gtest(test_plugin_http_types test/test_plugin_http_types.cpp) - target_link_libraries(test_plugin_http_types gateway_lib) + target_link_libraries(test_plugin_http_types gateway_ros2) # Log manager tests # Dedicated ROS_DOMAIN_ID to prevent cross-talk with concurrent integration tests ament_add_gtest(test_log_manager test/test_log_manager.cpp) - target_link_libraries(test_log_manager gateway_lib) + target_link_libraries(test_log_manager gateway_ros2) medkit_set_test_domain(test_log_manager) # Log handlers tests ament_add_gtest(test_log_handlers test/test_log_handlers.cpp) - target_link_libraries(test_log_handlers gateway_lib) + target_link_libraries(test_log_handlers gateway_ros2) # Route descriptions tests (OpenAPI doc builder) ament_add_gtest(test_route_descriptions test/test_route_descriptions.cpp) - target_link_libraries(test_route_descriptions gateway_lib) + target_link_libraries(test_route_descriptions gateway_ros2) # Schema builder tests (OpenAPI schema generation) ament_add_gtest(test_schema_builder test/test_schema_builder.cpp) - target_link_libraries(test_schema_builder gateway_lib) + target_link_libraries(test_schema_builder gateway_ros2) # Path builder tests (OpenAPI path item generation) ament_add_gtest(test_path_builder test/test_path_builder.cpp) - target_link_libraries(test_path_builder gateway_lib) + target_link_libraries(test_path_builder gateway_ros2) # OpenAPI spec builder tests (full document assembly) ament_add_gtest(test_openapi_spec_builder test/test_openapi_spec_builder.cpp) - target_link_libraries(test_openapi_spec_builder gateway_lib) + target_link_libraries(test_openapi_spec_builder gateway_ros2) # Path resolver tests (OpenAPI path classification) ament_add_gtest(test_path_resolver test/test_path_resolver.cpp) - target_link_libraries(test_path_resolver gateway_lib) + target_link_libraries(test_path_resolver gateway_ros2) # Capability generator tests (OpenAPI spec generation engine) ament_add_gtest(test_capability_generator test/test_capability_generator.cpp) - target_link_libraries(test_capability_generator gateway_lib) + target_link_libraries(test_capability_generator gateway_ros2) medkit_set_test_domain(test_capability_generator) # Route registry tests (OpenAPI route registration and path conversion) ament_add_gtest(test_route_registry test/test_route_registry.cpp) - target_link_libraries(test_route_registry gateway_lib) + target_link_libraries(test_route_registry gateway_ros2) # Docs handlers tests (OpenAPI /docs endpoint handlers) ament_add_gtest(test_docs_handlers test/test_docs_handlers.cpp) - target_link_libraries(test_docs_handlers gateway_lib) + target_link_libraries(test_docs_handlers gateway_ros2) medkit_set_test_domain(test_docs_handlers) # Lock manager tests ament_add_gtest(test_lock_manager test/test_lock_manager.cpp) - target_link_libraries(test_lock_manager gateway_lib) + target_link_libraries(test_lock_manager gateway_ros2) # Lock handlers tests ament_add_gtest(test_lock_handlers test/test_lock_handlers.cpp) - target_link_libraries(test_lock_handlers gateway_lib) + target_link_libraries(test_lock_handlers gateway_ros2) medkit_set_test_domain(test_lock_handlers) # Condition evaluator tests (trigger condition interface + built-in evaluators) ament_add_gtest(test_condition_evaluator test/test_condition_evaluator.cpp) - target_link_libraries(test_condition_evaluator gateway_lib) + target_link_libraries(test_condition_evaluator gateway_ros2) # Resource change notifier tests (async notification hub for triggers) ament_add_gtest(test_resource_change_notifier test/test_resource_change_notifier.cpp TIMEOUT 180) - target_link_libraries(test_resource_change_notifier gateway_lib) + target_link_libraries(test_resource_change_notifier gateway_ros2) # Trigger store tests (SQLite persistence for triggers) ament_add_gtest(test_trigger_store test/test_trigger_store.cpp) - target_link_libraries(test_trigger_store gateway_lib) + target_link_libraries(test_trigger_store gateway_ros2) # Trigger manager tests (CRUD, condition eval, hierarchy matching) ament_add_gtest(test_trigger_manager test/test_trigger_manager.cpp) - target_link_libraries(test_trigger_manager gateway_lib) + target_link_libraries(test_trigger_manager gateway_ros2) # Trigger handler tests (REST endpoints for triggers) ament_add_gtest(test_trigger_handlers test/test_trigger_handlers.cpp) - target_link_libraries(test_trigger_handlers gateway_lib) + target_link_libraries(test_trigger_handlers gateway_ros2) # Peer client tests (aggregation module) ament_add_gtest(test_peer_client test/test_peer_client.cpp) - target_link_libraries(test_peer_client gateway_lib) + target_link_libraries(test_peer_client gateway_ros2) # Entity merger tests (aggregation module) ament_add_gtest(test_entity_merger test/test_entity_merger.cpp) - target_link_libraries(test_entity_merger gateway_lib) + target_link_libraries(test_entity_merger gateway_ros2) # Fan-out helper tests (shared URL encoding and peer merge utilities) ament_add_gtest(test_fan_out_helpers test/test_fan_out_helpers.cpp) - target_link_libraries(test_fan_out_helpers gateway_lib) + target_link_libraries(test_fan_out_helpers gateway_ros2) # Aggregation manager tests (aggregation module) ament_add_gtest(test_aggregation_manager test/test_aggregation_manager.cpp) - target_link_libraries(test_aggregation_manager gateway_lib) + target_link_libraries(test_aggregation_manager gateway_ros2) # Aggregation classification tests (hierarchical vs leaf Component routing) ament_add_gtest(test_aggregation_classification test/test_aggregation_classification.cpp) - target_link_libraries(test_aggregation_classification gateway_lib) + target_link_libraries(test_aggregation_classification gateway_ros2) # Stream proxy tests (SSE parsing, aggregation module) ament_add_gtest(test_stream_proxy test/test_stream_proxy.cpp) - target_link_libraries(test_stream_proxy gateway_lib) + target_link_libraries(test_stream_proxy gateway_ros2) # mDNS discovery tests (aggregation module) ament_add_gtest(test_mdns_discovery test/test_mdns_discovery.cpp) - target_link_libraries(test_mdns_discovery gateway_lib) + target_link_libraries(test_mdns_discovery gateway_ros2) # Network utility tests (URL parsing, local address collection) ament_add_gtest(test_network_utils test/test_network_utils.cpp) - target_link_libraries(test_network_utils gateway_lib) + target_link_libraries(test_network_utils gateway_ros2) # Apply coverage flags to test targets if(ENABLE_COVERAGE) diff --git a/src/ros2_medkit_gateway/README.md b/src/ros2_medkit_gateway/README.md index c4345fae9..a90c2234b 100644 --- a/src/ros2_medkit_gateway/README.md +++ b/src/ros2_medkit_gateway/README.md @@ -1431,6 +1431,18 @@ curl --cacert ./certs/ca.crt https://localhost:8443/api/v1 ## Architecture +### Build Layers + +The package compiles into two layered static libraries with a strict dependency direction: + +- **`gateway_core`** - middleware-neutral business logic. Sources live under `src/core/` and headers under `include/ros2_medkit_gateway/core/`. Links only header-only and C-level externals (cpp-httplib, nlohmann/json, yaml-cpp, tl::expected, jwt-cpp, OpenSSL, SQLite, dl). Carries no rclcpp / rcl_interfaces / message-package dependency. Hosts the neutral HTTP request handlers, JWT authentication, fault model (debounce, storage, cache, correlation), peer aggregation, manifest parsing, the entity cache, the neutral managers (lock, bulk-data, subscription, script, update, plugin), and every provider interface contract. +- **`gateway_ros2`** - ROS adapter layer. Compiles the remaining sources under `src/` and links `gateway_core` publicly via `medkit_target_dependencies`. Hosts `GatewayNode` (the `rclcpp::Node` entry point), the ROS-coupled managers (data access, operation, configuration, fault facade, log, trigger), runtime discovery, the native topic sampler, and the ROS-specific provider default implementations. + +The `gateway_node` executable and existing test targets link `gateway_ros2`, so they transitively get both layers from a single dependency. The neutral contract is enforced by two CTest checks: + +- `gateway_core_purity` (linter label) - greps `core/` for any ROS-package include and fails on any match. +- `test_gateway_core_smoke` (unit label) - compiles a translation unit that includes a sampling of `core/` headers and links exclusively against `gateway_core` + GTest with no `ament_target_dependencies`. Build failure indicates a transitive ROS coupling that the grep guard might miss. + ### Components - **Gateway Node**: Main ROS 2 node that runs the REST server diff --git a/src/ros2_medkit_gateway/cmake/SwaggerUI.cmake b/src/ros2_medkit_gateway/cmake/SwaggerUI.cmake index 6683c7b8d..2f7b70216 100644 --- a/src/ros2_medkit_gateway/cmake/SwaggerUI.cmake +++ b/src/ros2_medkit_gateway/cmake/SwaggerUI.cmake @@ -16,7 +16,8 @@ # # When ENABLE_SWAGGER_UI=ON, downloads swagger-ui-dist files from unpkg.com # and generates a C++ source file with embedded byte arrays. -# The generated file is added to the gateway_lib target. +# The generated file is added to the gateway_ros2 target (the ROS adapter +# layer that owns the HTTP server and Swagger UI integration). set(SWAGGER_UI_VERSION "5.17.14") set(SWAGGER_UI_URL "https://unpkg.com/swagger-ui-dist@${SWAGGER_UI_VERSION}") @@ -139,8 +140,8 @@ else() "or ensure network access to unpkg.com during CMake configure.") endif() -# Add generated source to gateway_lib and make the header findable -target_sources(gateway_lib PRIVATE "${SWAGGER_UI_ASSETS_CPP}") -target_include_directories(gateway_lib PRIVATE +# Add generated source to gateway_ros2 and make the header findable +target_sources(gateway_ros2 PRIVATE "${SWAGGER_UI_ASSETS_CPP}") +target_include_directories(gateway_ros2 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/http" ) diff --git a/src/ros2_medkit_gateway/design/index.rst b/src/ros2_medkit_gateway/design/index.rst index ed2a67ddd..b9c6e95fb 100644 --- a/src/ros2_medkit_gateway/design/index.rst +++ b/src/ros2_medkit_gateway/design/index.rst @@ -6,6 +6,45 @@ This section contains design documentation for the ros2_medkit_gateway project. Architecture ------------ +Build Layers +~~~~~~~~~~~~ + +The package compiles into two layered static libraries with a strict +dependency direction: + +* ``gateway_core`` - middleware-neutral business logic. Sources live under + ``src/core/`` and headers under ``include/ros2_medkit_gateway/core/``. + Links only header-only and C-level externals (cpp-httplib, + nlohmann/json, yaml-cpp, tl::expected, jwt-cpp, OpenSSL, SQLite, dl). + Carries no rclcpp / rcl_interfaces / message-package dependency. + Hosts the neutral HTTP request handlers, JWT authentication, + fault model (debounce, storage, cache, correlation), peer aggregation, + manifest parsing, the entity cache, the neutral managers (lock, + bulk-data, subscription, script, update, plugin), and every provider + interface contract. +* ``gateway_ros2`` - ROS adapter layer. Compiles the remaining sources + under ``src/`` and links ``gateway_core`` publicly via + ``medkit_target_dependencies``. Hosts ``GatewayNode`` (the + ``rclcpp::Node`` entry point), the ROS-coupled managers (data access, + operation, configuration, fault facade, log, trigger), runtime + discovery, the native topic sampler, and the ROS-specific provider + default implementations. + +The ``gateway_node`` executable and existing test targets link +``gateway_ros2``, so they transitively get both layers from a single +dependency. The neutral contract is enforced by two CTest checks: + +* ``gateway_core_purity`` (linter label) - greps ``core/`` for any + ROS-package include and fails on any match. +* ``test_gateway_core_smoke`` (unit label) - compiles a translation unit + including a sampling of ``core/`` headers and links exclusively against + ``gateway_core`` + GTest with no ``ament_target_dependencies``. Build + failure indicates a transitive ROS coupling that the grep guard might + miss when an include is reached through a third-party header. + +Class Diagram +~~~~~~~~~~~~~ + The following diagram shows the relationships between the main components of the gateway. .. plantuml:: @@ -28,6 +67,19 @@ The following diagram shows the relationships between the main components of the package "ros2_medkit_gateway" { + note as N_layer_split + This package compiles into two layered static libraries: + * gateway_core - middleware-neutral business logic (handlers, + auth, fault model, aggregation, neutral managers, providers, + entity model). Does not link rclcpp. + * gateway_ros2 - ROS adapter classes (GatewayNode, + DataAccessManager, OperationManager, ConfigurationManager, + FaultManager, LogManager, TriggerManager, RuntimeDiscovery, + NativeTopicSampler, TypeIntrospection). Publicly links + gateway_core. Class associations on this diagram remain valid; + the boundary affects build-time only. + end note + class GatewayNode { + get_entity_cache(): EntityCache + get_data_access_manager(): DataAccessManager* @@ -387,14 +439,18 @@ The following diagram shows the relationships between the main components of the Main Components --------------- -1. **GatewayNode** - The main ROS 2 node that orchestrates the system +Each entry below is tagged with the static library it compiles into: +``[gateway_core]`` (middleware-neutral, no ROS dependency) or +``[gateway_ros2]`` (links rclcpp / message packages). + +1. **GatewayNode** ``[gateway_ros2]`` - The main ROS 2 node that orchestrates the system - Extends ``rclcpp::Node`` - Manages periodic discovery and cache refresh - Runs the REST server in a separate thread - Provides thread-safe access to the entity cache - Manages periodic cleanup of old action goals (60s interval) -2. **DiscoveryManager** - Discovers ROS 2 entities and maps them to the SOVD hierarchy +2. **DiscoveryManager** ``[gateway_ros2]`` - Discovers ROS 2 entities and maps them to the SOVD hierarchy - Discovers Areas from node namespaces or manifest definitions - Discovers Components (synthetic groups from runtime, or explicit from manifest) - Discovers Apps from ROS 2 nodes (individual running processes) @@ -440,7 +496,7 @@ Main Components Before each layer's ``discover()`` call, the pipeline populates ``IntrospectionInput`` with entities from all previous layers, so plugins see the current manifest + runtime entity set -3. **OperationManager** - Executes ROS 2 operations (services and actions) using native APIs +3. **OperationManager** ``[gateway_ros2]`` - Executes ROS 2 operations (services and actions) using native APIs - Calls ROS 2 services via ``rclcpp::GenericClient`` with native serialization - Sends action goals via native action client interfaces - Tracks active action goals with status, feedback, and timestamps @@ -450,7 +506,7 @@ Main Components - Automatically cleans up completed goals older than 5 minutes - Uses ``ros2_medkit_serialization`` for JSON ↔ ROS 2 message conversion -4. **RESTServer** - Provides the HTTP/REST API +4. **RESTServer** ``[gateway_ros2]`` - Provides the HTTP/REST API (route table couples to gateway lifecycle; the individual handlers it dispatches to live in ``gateway_core``) - Discovery endpoints: ``/health``, ``/areas``, ``/components`` - Data endpoints: ``/components/{id}/data``, ``/components/{id}/data/{topic}`` - Operations endpoints: ``/apps/{id}/operations``, ``/apps/{id}/operations/{op}/executions`` @@ -463,14 +519,14 @@ Main Components - Uses ScriptManager for script upload and execution - Runs on configurable host and port with CORS support -5. **ConfigurationManager** - Manages ROS 2 node parameters +5. **ConfigurationManager** ``[gateway_ros2]`` - Manages ROS 2 node parameters - Lists all parameters for a node via ``rclcpp::SyncParametersClient`` - Gets/sets individual parameter values with type conversion - Provides parameter descriptors (description, constraints, read-only flag) - Caches parameter clients per node for efficiency - Converts between JSON and ROS 2 parameter types automatically -6. **DataAccessManager** - Reads and writes runtime data from/to ROS 2 topics +6. **DataAccessManager** ``[gateway_ros2]`` - Reads and writes runtime data from/to ROS 2 topics - Delegates topic sampling to the attached ``TopicDataProvider`` (pool-backed, race-free) - Checks publisher counts before sampling to skip idle topics instantly - Returns metadata (type, schema) for topics without publishers @@ -478,7 +534,7 @@ Main Components - Returns topic data as JSON with metadata (topic name, timestamp, type info) - Parallel topic sampling with configurable concurrency limit (``data_provider.max_parallel_samples`` on the TopicDataProvider, default: 8) -7. **TopicDataProvider** / **Ros2TopicDataProvider** - Transport-neutral SOVD data interface and its pool-backed ROS 2 default implementation +7. **TopicDataProvider** / **Ros2TopicDataProvider** ``[gateway_core / gateway_ros2]`` - The interface lives in the neutral layer (``core/providers/data_provider.hpp``); the pool-backed ROS 2 default implementation lives in the adapter layer - ``TopicDataProvider`` is a pure C++ interface consumed by HTTP handlers and managers, with no rclcpp headers required on the consumer side - ``Ros2TopicDataProvider`` keeps one shared subscription per topic and serves many sample calls from the cached latest message, avoiding the rcl hash-map race that short-lived per-sample subscriptions used to trigger - All subscription / callback-group creation and destruction runs on ``Ros2SubscriptionExecutor``'s single worker thread @@ -486,7 +542,7 @@ Main Components - Exposes pool + executor stats on ``GET /health`` under the ``x-medkit-subscription-executor`` and ``x-medkit-data-provider`` vendor-extension keys - See :doc:`ros2_subscription_architecture` for the full design -8. **JsonSerializer** (ros2_medkit_serialization) - Converts between JSON and ROS 2 messages +8. **JsonSerializer** (ros2_medkit_serialization) - Converts between JSON and ROS 2 messages (separate package, not part of the gateway layer split) - Uses ``dynmsg`` library for dynamic type introspection - Serializes JSON to CDR format for publishing via ``serialize()`` - Deserializes CDR to JSON for subscriptions via ``deserialize()`` @@ -494,7 +550,7 @@ Main Components - Provides static ``yaml_to_json()`` utility for YAML to JSON conversion - Thread-safe and stateless design -9. **LockManager** - SOVD resource locking (ISO 17978-3, Section 7.17) +9. **LockManager** ``[gateway_core]`` - SOVD resource locking (ISO 17978-3, Section 7.17) - Transport-agnostic lock store with ``shared_mutex`` for thread safety - Acquire, release, extend locks on components and apps - Scoped locks restrict protection to specific resource collections @@ -503,7 +559,7 @@ Main Components - Automatic expiry with cyclic subscription cleanup - Plugin access via ``PluginContext::check_lock/acquire_lock/release_lock`` -10. **Data Models** - Entity representations +10. **Data Models** ``[gateway_core]`` - Entity representations - ``Area`` - Physical or logical domain (namespace grouping) - ``Component`` - Logical grouping of Apps; can be ``synthetic`` (auto-created from namespace), ``topic`` (from topic-only namespace), or ``manifest`` (explicitly defined) - ``App`` - Software application (ROS 2 node); individual running process linked to parent Component @@ -511,7 +567,7 @@ Main Components - ``ActionInfo`` - Action metadata (path, name, type) - ``EntityCache`` - Thread-safe cache of discovered entities (areas, components, apps) -10. **ScriptManager** - Manages diagnostic script upload, storage, and execution (SOVD 7.15) +11. **ScriptManager** ``[gateway_ros2]`` - Manages diagnostic script upload, storage, and execution (SOVD 7.15) - Delegates to a pluggable ``ScriptProvider`` backend (set via ``set_backend()``) - Lists, uploads, and deletes scripts per entity - Starts script executions as POSIX subprocesses with timeout support @@ -526,7 +582,7 @@ Triggers The trigger subsystem implements SOVD condition-based resource change notifications. It consists of five main components: -1. **TriggerManager** - Central coordinator for trigger lifecycle (CRUD), condition +1. **TriggerManager** ``[gateway_ros2]`` - Central coordinator for trigger lifecycle (CRUD), condition evaluation, and event dispatch. - Subscribes to ``ResourceChangeNotifier`` for resource change events @@ -536,27 +592,27 @@ It consists of five main components: - Manages pending events for SSE stream pickup with per-trigger mutexes - Persists triggers via the ``TriggerStore`` interface -2. **ResourceChangeNotifier** - Async notification hub for resource changes. +2. **ResourceChangeNotifier** ``[gateway_core]`` - Async notification hub for resource changes. - Producers (FaultManager, DataAccessManager, UpdateManager, OperationManager, LogManager) call ``notify()`` - Observers (TriggerManager) register callbacks with filters - ``notify()`` is non-blocking - pushes to an internal queue processed by a dedicated worker thread - Filters support collection, entity_id, and resource_path matching -3. **ConditionRegistry** - Thread-safe registry for condition evaluators. +3. **ConditionRegistry** ``[gateway_core]`` - Thread-safe registry for condition evaluators. - Built-in SOVD types: ``OnChange``, ``OnChangeTo``, ``EnterRange``, ``LeaveRange`` - Plugins register custom evaluators with ``x-`` prefixed names - Uses ``shared_mutex`` for concurrent read access during evaluation -4. **TriggerStore** / **SqliteTriggerStore** - Persistence backend for triggers. +4. **TriggerStore** / **SqliteTriggerStore** ``[gateway_core]`` - Persistence backend for triggers. - Abstract ``TriggerStore`` interface allows plugin-provided backends - Default ``SqliteTriggerStore`` uses SQLite for persistent triggers - Stores trigger metadata, condition parameters, and evaluator state (previous values) - Supports partial updates for status changes and lifetime extensions -5. **TriggerTopicSubscriber** - Manages ROS 2 topic subscriptions for data triggers. +5. **TriggerTopicSubscriber** ``[gateway_ros2]`` - Manages ROS 2 topic subscriptions for data triggers. - Creates ``rclcpp::GenericSubscription`` instances for monitored data topics - Reference-counted: multiple triggers on the same topic share one subscription diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/aggregation_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/aggregation_manager.hpp index 93b5511c7..b860b4855 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/aggregation_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/aggregation_manager.hpp @@ -25,8 +25,8 @@ #include #include -#include "ros2_medkit_gateway/aggregation/classification.hpp" -#include "ros2_medkit_gateway/aggregation/peer_client.hpp" +#include "ros2_medkit_gateway/core/aggregation/classification.hpp" +#include "ros2_medkit_gateway/core/aggregation/peer_client.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/compat.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/compat.hpp new file mode 100644 index 000000000..fd58f7467 --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/compat.hpp @@ -0,0 +1,29 @@ +// Copyright 2026 bburda +// +// 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 + +// This header is reserved for the namespace migration to medkit::. +// +// A namespace alias of the form +// namespace medkit {} +// namespace ros2_medkit_gateway = medkit; +// would be ill-formed in any translation unit that subsequently opens +// `namespace ros2_medkit_gateway { ... }` (which every gateway header +// currently does). The migration to namespace medkit:: must therefore +// happen file-by-file in a dedicated follow-up; this header will then +// be repurposed to host the alias once all production code has been +// converted. +// +// Until then, including this header is a no-op. diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/configuration_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/configuration_manager.hpp index 912ea7c21..b83d4b96b 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/configuration_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/configuration_manager.hpp @@ -61,6 +61,11 @@ class ConfigurationManager { explicit ConfigurationManager(rclcpp::Node * node); ~ConfigurationManager(); + ConfigurationManager(const ConfigurationManager &) = delete; + ConfigurationManager & operator=(const ConfigurationManager &) = delete; + ConfigurationManager(ConfigurationManager &&) = delete; + ConfigurationManager & operator=(ConfigurationManager &&) = delete; + /// Clean up shared param node and cached clients before ROS 2 context shutdown. /// Must be called before rclcpp::shutdown() to prevent use-after-free. /// Idempotent - safe to call multiple times. diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/classification.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/classification.hpp similarity index 97% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/classification.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/classification.hpp index d044235ed..4a525652f 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/classification.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/classification.hpp @@ -19,7 +19,7 @@ #include #include -#include "ros2_medkit_gateway/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/entity_merger.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/entity_merger.hpp similarity index 93% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/entity_merger.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/entity_merger.hpp index a7cf96d72..e46e32eaa 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/entity_merger.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/entity_merger.hpp @@ -18,10 +18,10 @@ #include #include -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/mdns_discovery.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/mdns_discovery.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/mdns_discovery.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/mdns_discovery.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/network_utils.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/network_utils.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/network_utils.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/network_utils.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/peer_client.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/peer_client.hpp similarity index 94% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/peer_client.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/peer_client.hpp index 4ac147a60..bd9a8a058 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/peer_client.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/peer_client.hpp @@ -24,10 +24,10 @@ #include #include -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/stream_proxy.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/stream_proxy.hpp similarity index 95% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/stream_proxy.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/stream_proxy.hpp index b36ff15fc..a7a4fbd35 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/aggregation/stream_proxy.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/aggregation/stream_proxy.hpp @@ -90,6 +90,11 @@ class SSEStreamProxy : public StreamProxy { ~SSEStreamProxy() override; + SSEStreamProxy(const SSEStreamProxy &) = delete; + SSEStreamProxy & operator=(const SSEStreamProxy &) = delete; + SSEStreamProxy(SSEStreamProxy &&) = delete; + SSEStreamProxy & operator=(SSEStreamProxy &&) = delete; + void open() override; void close() override; bool is_connected() const override; diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth.hpp similarity index 73% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth.hpp index 07d0e7f2a..0fb303859 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth.hpp @@ -22,8 +22,8 @@ #pragma once -#include "ros2_medkit_gateway/auth/auth_config.hpp" -#include "ros2_medkit_gateway/auth/auth_manager.hpp" -#include "ros2_medkit_gateway/auth/auth_middleware.hpp" -#include "ros2_medkit_gateway/auth/auth_models.hpp" -#include "ros2_medkit_gateway/auth/auth_requirement_policy.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_manager.hpp" +#include "ros2_medkit_gateway/core/auth/auth_middleware.hpp" +#include "ros2_medkit_gateway/core/auth/auth_models.hpp" +#include "ros2_medkit_gateway/core/auth/auth_requirement_policy.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_config.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_config.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_config.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_config.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_manager.hpp similarity index 97% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_manager.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_manager.hpp index c141e986f..b8aaaa953 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_manager.hpp @@ -20,9 +20,9 @@ #include #include -#include "ros2_medkit_gateway/auth/auth_config.hpp" -#include "ros2_medkit_gateway/auth/auth_models.hpp" -#include "ros2_medkit_gateway/auth/auth_requirement_policy.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_models.hpp" +#include "ros2_medkit_gateway/core/auth/auth_requirement_policy.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_middleware.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_middleware.hpp similarity index 95% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_middleware.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_middleware.hpp index 9385c3adc..b8d03c1db 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_middleware.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_middleware.hpp @@ -20,9 +20,9 @@ #include #include -#include "ros2_medkit_gateway/auth/auth_config.hpp" -#include "ros2_medkit_gateway/auth/auth_manager.hpp" -#include "ros2_medkit_gateway/auth/auth_models.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_manager.hpp" +#include "ros2_medkit_gateway/core/auth/auth_models.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_models.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_models.hpp similarity index 99% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_models.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_models.hpp index 87e4cb551..68b4a8d9f 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_models.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_models.hpp @@ -21,7 +21,7 @@ #include #include -#include "ros2_medkit_gateway/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_requirement_policy.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_requirement_policy.hpp similarity index 99% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_requirement_policy.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_requirement_policy.hpp index 59a953c89..6e25328eb 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/auth/auth_requirement_policy.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/auth/auth_requirement_policy.hpp @@ -19,7 +19,7 @@ #include #include -#include "ros2_medkit_gateway/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/condition_evaluator.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/condition_evaluator.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/condition_evaluator.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/condition_evaluator.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/config.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/config.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/config.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/config.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/data_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/data/data_types.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/data_types.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/data/data_types.hpp index 8bde5ff92..4d456859b 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/data_types.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/data/data_types.hpp @@ -23,7 +23,7 @@ #include #include -#include "ros2_medkit_gateway/discovery/models/common.hpp" +#include "ros2_medkit_gateway/core/discovery/models/common.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/topic_data_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/data/topic_data_provider.hpp similarity index 96% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/topic_data_provider.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/data/topic_data_provider.hpp index 0978164e8..8b0aa194c 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/topic_data_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/data/topic_data_provider.hpp @@ -24,9 +24,9 @@ #include -#include "ros2_medkit_gateway/data/data_types.hpp" -#include "ros2_medkit_gateway/discovery/models/common.hpp" -#include "ros2_medkit_gateway/models/error_info.hpp" +#include "ros2_medkit_gateway/core/data/data_types.hpp" +#include "ros2_medkit_gateway/core/discovery/models/common.hpp" +#include "ros2_medkit_gateway/core/models/error_info.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/default_script_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/default_script_provider.hpp similarity index 94% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/default_script_provider.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/default_script_provider.hpp index a318f22e7..e5fe66589 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/default_script_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/default_script_provider.hpp @@ -22,8 +22,8 @@ #include -#include "ros2_medkit_gateway/script_types.hpp" -#include "ros2_medkit_gateway/scripts/script_provider.hpp" +#include "ros2_medkit_gateway/core/providers/script_provider.hpp" +#include "ros2_medkit_gateway/core/script_types.hpp" namespace ros2_medkit_gateway { @@ -71,6 +71,11 @@ class DefaultScriptProvider : public ScriptProvider { explicit DefaultScriptProvider(const ScriptsConfig & config); ~DefaultScriptProvider() override; + DefaultScriptProvider(const DefaultScriptProvider &) = delete; + DefaultScriptProvider & operator=(const DefaultScriptProvider &) = delete; + DefaultScriptProvider(DefaultScriptProvider &&) = delete; + DefaultScriptProvider & operator=(DefaultScriptProvider &&) = delete; + tl::expected, ScriptBackendErrorInfo> list_scripts(const std::string & entity_id) override; tl::expected get_script(const std::string & entity_id, diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_enums.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/discovery_enums.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_enums.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/discovery_enums.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_layer.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/discovery_layer.hpp similarity index 89% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_layer.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/discovery_layer.hpp index a8a44b194..45e277f6a 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_layer.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/discovery_layer.hpp @@ -14,11 +14,11 @@ #pragma once -#include "ros2_medkit_gateway/discovery/merge_types.hpp" -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/discovery/merge_types.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_strategy.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/discovery_strategy.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_strategy.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/discovery_strategy.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/manifest_layer.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/layers/manifest_layer.hpp similarity index 95% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/manifest_layer.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/layers/manifest_layer.hpp index 97bc0edee..0d9fc3151 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/manifest_layer.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/layers/manifest_layer.hpp @@ -14,7 +14,7 @@ #pragma once -#include "ros2_medkit_gateway/discovery/discovery_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_layer.hpp" #include "ros2_medkit_gateway/discovery/manifest/manifest_manager.hpp" #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/runtime_layer.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/layers/runtime_layer.hpp similarity index 94% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/runtime_layer.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/layers/runtime_layer.hpp index c8c8bcd99..6aa896032 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/runtime_layer.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/layers/runtime_layer.hpp @@ -14,8 +14,8 @@ #pragma once -#include "ros2_medkit_gateway/discovery/discovery_layer.hpp" -#include "ros2_medkit_gateway/discovery/merge_types.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/merge_types.hpp" #include "ros2_medkit_gateway/discovery/runtime_discovery.hpp" #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest.hpp similarity index 91% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest.hpp index b83828e58..579f4d924 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest.hpp @@ -14,11 +14,11 @@ #pragma once -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" -#include "ros2_medkit_gateway/script_types.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/script_types.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_parser.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest_parser.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_parser.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest_parser.hpp index 4bacb570c..ff85e5740 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_parser.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest_parser.hpp @@ -14,7 +14,7 @@ #pragma once -#include "ros2_medkit_gateway/discovery/manifest/manifest.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_validator.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest_validator.hpp similarity index 94% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_validator.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest_validator.hpp index a55f2b65e..6ce0736ea 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_validator.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/manifest_validator.hpp @@ -14,8 +14,8 @@ #pragma once -#include "ros2_medkit_gateway/discovery/manifest/manifest.hpp" -#include "ros2_medkit_gateway/discovery/manifest/validation_error.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/validation_error.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/validation_error.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/validation_error.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/validation_error.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/manifest/validation_error.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/merge_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/merge_types.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/merge_types.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/merge_types.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/app.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/app.hpp new file mode 100644 index 000000000..45955f38d --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/app.hpp @@ -0,0 +1,145 @@ +// Copyright 2026 bburda +// +// 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 "ros2_medkit_gateway/core/discovery/models/common.hpp" + +#include +#include +#include +#include + +namespace ros2_medkit_gateway { + +using json = nlohmann::json; + +/** + * @brief SOVD App entity - represents a software application + * + * In the ROS 2 context, an App typically corresponds to a ROS node. + * Apps are located on Components and can depend on other Apps. + * + * Apps can be: + * - Manifest-defined: Declared in YAML manifest with ROS binding + * - Runtime-discovered: Automatically created from ROS nodes (future) + */ +struct App { + // === Required fields === + std::string id; ///< Unique identifier + std::string name; ///< Human-readable name + + // === Optional SOVD fields === + std::string translation_id; ///< For i18n support + std::string description; ///< Detailed description + std::vector tags; ///< Tags for filtering + + // === Relationships === + std::string component_id; ///< is-located-on relationship + std::vector depends_on; ///< depends-on relationship (App IDs) + + // === ROS binding (for manifest) === + /** + * @brief ROS 2 binding configuration for manifest-defined apps + * + * Specifies how to bind this App to a ROS 2 node at runtime. + */ + struct RosBinding { + std::string node_name; ///< ROS node name to bind to + std::string namespace_pattern; ///< Namespace (can be "*" for wildcard) + std::string topic_namespace; ///< Alternative: bind by topic prefix + + bool is_empty() const { + return node_name.empty() && topic_namespace.empty(); + } + + json to_json() const { + json j; + if (!node_name.empty()) { + j["nodeName"] = node_name; + if (!namespace_pattern.empty()) { + j["namespace"] = namespace_pattern; + } + } + if (!topic_namespace.empty()) { + j["topicNamespace"] = topic_namespace; + } + return j; + } + }; + std::optional ros_binding; + + // === Runtime state (populated after linking) === + std::optional bound_fqn; ///< Bound ROS node FQN + bool is_online{false}; ///< Whether the bound node is running + bool external{false}; ///< True if not a ROS node + + /// Get effective FQN: bound_fqn if available, otherwise derived from ros_binding. + /// Returns empty string if neither is available. Used by handlers and samplers + /// to resolve the ROS node FQN in manifest_only mode where runtime linking + /// doesn't set bound_fqn. + /// @note namespace_pattern must be empty or an exact namespace path (e.g. "/perception"). + /// Glob patterns like "**" or "prefix*" are not supported and will produce empty FQN. + std::string effective_fqn() const { + if (bound_fqn.has_value() && !bound_fqn->empty()) { + return *bound_fqn; + } + if (ros_binding.has_value() && !ros_binding->node_name.empty()) { + const auto & ns = ros_binding->namespace_pattern; + // Wildcard or glob patterns cannot produce valid FQNs + if (ns.find('*') != std::string::npos) { + return ""; + } + if (ns.empty()) { + return "/" + ros_binding->node_name; + } + if (ns.back() != '/') { + return ns + "/" + ros_binding->node_name; + } + return ns + ros_binding->node_name; + } + return ""; + } + + // === Resources (populated from bound node) === + ComponentTopics topics; + std::vector services; + std::vector actions; + + // === Discovery metadata === + std::string source = "manifest"; ///< "manifest" or "runtime" + std::string original_id; ///< Pre-rename ID when collision-prefixed by aggregation + std::vector contributors; ///< Aggregation provenance: "local" and/or "peer:" + + // === Serialization methods === + + /** + * @brief Serialize to full JSON representation + */ + json to_json() const; + + /** + * @brief Create SOVD EntityReference format + * @param base_url Base URL for href (e.g., "/api/v1") + */ + json to_entity_reference(const std::string & base_url) const; + + /** + * @brief Create SOVD Entity Capabilities format + * @param base_url Base URL for capability URIs + */ + json to_capabilities(const std::string & base_url) const; +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/area.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/area.hpp new file mode 100644 index 000000000..b763d32df --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/area.hpp @@ -0,0 +1,132 @@ +// Copyright 2026 bburda +// +// 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 "ros2_medkit_gateway/core/discovery/models/common.hpp" + +#include +#include +#include + +namespace ros2_medkit_gateway { + +using json = nlohmann::json; + +/** + * @brief SOVD Area entity - represents a logical grouping (ROS 2 namespace) + * + * Areas are derived from ROS 2 namespaces or defined in manifests. + * They provide a hierarchical organization of components. + */ +struct Area { + std::string id; ///< Unique identifier (e.g., "powertrain") + std::string name; ///< Human-readable name (e.g., "Powertrain System") + std::string namespace_path; ///< ROS 2 namespace path (e.g., "/powertrain") + std::string type = "Area"; ///< Entity type (always "Area") + std::string translation_id; ///< Internationalization key + std::string description; ///< Human-readable description + std::vector tags; ///< Tags for filtering + std::string parent_area_id; ///< Parent area ID for sub-areas + std::string source; ///< Origin of this area (e.g., "manifest", "heuristic") + std::vector contributors; ///< Aggregation provenance: "local" and/or "peer:" + + /** + * @brief Convert to JSON representation + * @return JSON object with area data + * + * SOVD EntityReference fields: id, name, href, translation_id, tags + * ROS 2 extensions in x-medkit: namespace, type, description, parentAreaId + */ + json to_json() const { + // Base fields + json j = {{"id", id}}; + + if (!name.empty()) { + j["name"] = name; + } + if (!translation_id.empty()) { + j["translationId"] = translation_id; + } + if (!tags.empty()) { + j["tags"] = tags; + } + + // ROS 2 extensions in x-medkit (SOVD vendor extension) + json x_medkit = {{"entityType", type}, {"namespace", namespace_path}}; + if (!description.empty()) { + x_medkit["description"] = description; + } + if (!parent_area_id.empty()) { + x_medkit["parentAreaId"] = parent_area_id; + } + if (!source.empty()) { + x_medkit["source"] = source; + } + if (!contributors.empty()) { + x_medkit["contributors"] = sorted_contributors(contributors); + } + j["x-medkit"] = x_medkit; + + return j; + } + + /** + * @brief Create SOVD EntityReference format (strictly compliant) + * @param base_url Base URL for self links + * @return JSON object in EntityReference format: id, name, href, [translationId, tags] + */ + json to_entity_reference(const std::string & base_url) const { + json j = {{"id", id}, {"href", base_url + "/areas/" + id}}; + if (!name.empty()) { + j["name"] = name; + } + if (!translation_id.empty()) { + j["translationId"] = translation_id; + } + if (!tags.empty()) { + j["tags"] = tags; + } + return j; + } + + /** + * @brief Create SOVD Entity Capabilities format (strictly compliant) + * @param base_url Base URL for capability links + * @return JSON object listing available sub-resources + */ + json to_capabilities(const std::string & base_url) const { + std::string area_url = base_url + "/areas/" + id; + + // Capabilities response + json j = {{"id", id}}; + if (!name.empty()) { + j["name"] = name; + } + if (!translation_id.empty()) { + j["translationId"] = translation_id; + } + + // Capabilities as URI references (SOVD compliant) + j["subareas"] = area_url + "/subareas"; + j["related-components"] = area_url + "/related-components"; + + // x-medkit extension for ROS 2 specific info + j["x-medkit"] = {{"entityType", type}, {"namespace", namespace_path}}; + + return j; + } +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/common.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/common.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/common.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/common.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/component.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/component.hpp new file mode 100644 index 000000000..af2e48788 --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/component.hpp @@ -0,0 +1,175 @@ +// Copyright 2026 bburda +// +// 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 "ros2_medkit_gateway/core/discovery/models/common.hpp" + +#include +#include +#include +#include + +namespace ros2_medkit_gateway { + +using json = nlohmann::json; + +/** + * @brief SOVD Component entity - represents a software/hardware component (ROS 2 node) + * + * Components are derived from ROS 2 nodes or defined in manifests. + * They expose operations (services/actions), data (topics), and configurations (parameters). + */ +struct Component { + std::string id; ///< Unique identifier (node name) + std::string name; ///< Human-readable name + std::string namespace_path; ///< ROS 2 namespace path + std::string fqn; ///< Fully qualified name (namespace + id) + std::string type = "Component"; ///< Entity type (always "Component") + std::string area; ///< Parent area ID + std::string source = "node"; ///< Discovery source: "node", "topic", or "manifest" + std::string translation_id; ///< Internationalization key + std::string description; ///< Human-readable description + std::string variant; ///< Hardware variant identifier + std::vector tags; ///< Tags for filtering + std::string parent_component_id; ///< Parent component ID for sub-components + std::vector depends_on; ///< Component IDs this component depends on + std::vector contributors; ///< Aggregation provenance: "local" and/or "peer:" + std::vector services; ///< Services exposed by this component + std::vector actions; ///< Actions exposed by this component + ComponentTopics topics; ///< Topics this component publishes/subscribes + std::optional host_metadata; ///< Host system metadata (for runtime default component) + + /** + * @brief Convert to JSON representation + * @return JSON object with component data + * + * SOVD EntityReference fields: id, name, href, translation_id, tags + * ROS 2 extensions in x-medkit: namespace, fqn, entityType, area, source, variant, etc. + */ + json to_json() const { + // Base fields + json j = {{"id", id}}; + + if (!name.empty()) { + j["name"] = name; + } + if (!translation_id.empty()) { + j["translationId"] = translation_id; + } + if (!tags.empty()) { + j["tags"] = tags; + } + + // ROS 2 extensions in x-medkit (SOVD vendor extension) + json x_medkit = { + {"entityType", type}, {"namespace", namespace_path}, {"fqn", fqn}, {"area", area}, {"source", source}}; + if (!description.empty()) { + x_medkit["description"] = description; + } + if (!variant.empty()) { + x_medkit["variant"] = variant; + } + if (!parent_component_id.empty()) { + x_medkit["parentComponentId"] = parent_component_id; + } + if (!depends_on.empty()) { + x_medkit["dependsOn"] = depends_on; + } + if (!contributors.empty()) { + x_medkit["contributors"] = sorted_contributors(contributors); + } + x_medkit["topics"] = topics.to_json(); + if (host_metadata.has_value()) { + x_medkit["host"] = host_metadata.value(); + } + j["x-medkit"] = x_medkit; + + // Add operations array combining services and actions + json operations = json::array(); + for (const auto & svc : services) { + operations.push_back(svc.to_json()); + } + for (const auto & act : actions) { + operations.push_back(act.to_json()); + } + if (!operations.empty()) { + j["operations"] = operations; + } + + return j; + } + + /** + * @brief Create SOVD EntityReference format (strictly compliant) + * @param base_url Base URL for self links + * @return JSON object in EntityReference format: id, name, href, [translationId, tags] + */ + json to_entity_reference(const std::string & base_url) const { + json j = {{"id", id}, {"href", base_url + "/components/" + id}}; + if (!name.empty()) { + j["name"] = name; + } + if (!translation_id.empty()) { + j["translationId"] = translation_id; + } + if (!tags.empty()) { + j["tags"] = tags; + } + return j; + } + + /** + * @brief Create SOVD Entity Capabilities format (strictly compliant) + * @param base_url Base URL for capability links + * @return JSON object listing available sub-resources + */ + json to_capabilities(const std::string & base_url) const { + std::string component_url = base_url + "/components/" + id; + + // Capabilities response + json j = {{"id", id}}; + if (!name.empty()) { + j["name"] = name; + } + if (!translation_id.empty()) { + j["translationId"] = translation_id; + } + + // Capabilities as URI references (SOVD compliant) + if (!topics.publishes.empty() || !topics.subscribes.empty()) { + j["data"] = component_url + "/data"; + } + if (!services.empty() || !actions.empty()) { + j["operations"] = component_url + "/operations"; + } + // ROS 2 nodes always have parameters + if (source == "node") { + j["configurations"] = component_url + "/configurations"; + } + j["faults"] = component_url + "/faults"; + j["subcomponents"] = component_url + "/subcomponents"; + j["related-apps"] = component_url + "/related-apps"; + if (!depends_on.empty()) { + j["depends-on"] = component_url + "/depends-on"; + } + + // x-medkit extension for ROS 2 specific info + j["x-medkit"] = {{"entityType", type}, {"namespace", namespace_path}, {"fqn", fqn}, {"source", source}}; + + return j; + } +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/function.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/function.hpp new file mode 100644 index 000000000..2633c84aa --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/discovery/models/function.hpp @@ -0,0 +1,74 @@ +// Copyright 2026 bburda +// +// 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 "ros2_medkit_gateway/core/discovery/models/common.hpp" + +#include +#include +#include + +namespace ros2_medkit_gateway { + +using json = nlohmann::json; + +/** + * @brief SOVD Function entity - represents a functional group + * + * Functions are higher-level abstractions that group Apps and/or Components + * representing a complete capability (e.g., "Autonomous Navigation"). + * + * Functions can be manifest-defined or created at runtime from namespace grouping. + * They aggregate data, operations, and faults from their hosted entities. + */ +struct Function { + // === Required fields === + std::string id; ///< Unique identifier + std::string name; ///< Human-readable name + + // === Optional SOVD fields === + std::string translation_id; ///< For i18n support + std::string description; ///< Detailed description + std::vector tags; ///< Tags for filtering + + // === Relationships === + std::vector hosts; ///< App or Component IDs this function hosts + std::vector depends_on; ///< depends-on relationship (Function IDs) + + // === Discovery metadata === + std::string source = "manifest"; ///< Discovery source: manifest or runtime + std::vector contributors; ///< Aggregation provenance: "local" and/or "peer:" + + // === Serialization methods === + + /** + * @brief Serialize to full JSON representation + */ + json to_json() const; + + /** + * @brief Create SOVD EntityReference format + * @param base_url Base URL for href (e.g., "/api/v1") + */ + json to_entity_reference(const std::string & base_url) const; + + /** + * @brief Create SOVD Entity Capabilities format + * @param base_url Base URL for capability URIs + */ + json to_capabilities(const std::string & base_url) const; +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/entity_validation.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/entity_validation.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/entity_validation.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/entity_validation.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/exceptions.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/exceptions.hpp similarity index 97% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/exceptions.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/exceptions.hpp index 136e78a99..569d4f14d 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/exceptions.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/exceptions.hpp @@ -17,7 +17,7 @@ #include #include -#include "ros2_medkit_gateway/models/error_info.hpp" +#include "ros2_medkit_gateway/core/models/error_info.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/entity_path_utils.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/entity_path_utils.hpp similarity index 97% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/entity_path_utils.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/entity_path_utils.hpp index a44a0465b..0be179b63 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/entity_path_utils.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/entity_path_utils.hpp @@ -17,7 +17,7 @@ #include #include -#include "ros2_medkit_gateway/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/error_codes.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/error_codes.hpp new file mode 100644 index 000000000..92e478518 --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/error_codes.hpp @@ -0,0 +1,164 @@ +// Copyright 2026 bburda +// +// 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 + +namespace ros2_medkit_gateway { + +/** + * @brief SOVD Standard Error Codes + * + * These error codes follow the SOVD GenericError schema defined in + * sovd-openapi-spec/commons/errors.yaml. They should be used in all + * error responses to ensure compliance with the SOVD specification. + */ + +/// Invalid request format or missing required parameters +constexpr const char * ERR_INVALID_REQUEST = "invalid-request"; + +/// Entity (component, app, area, function) not found +constexpr const char * ERR_ENTITY_NOT_FOUND = "entity-not-found"; + +/// Resource (operation, configuration, data, fault) not found +constexpr const char * ERR_RESOURCE_NOT_FOUND = "resource-not-found"; + +/// Operation not found on entity +constexpr const char * ERR_OPERATION_NOT_FOUND = "operation-not-found"; + +/// Invalid parameter value or type +constexpr const char * ERR_INVALID_PARAMETER = "invalid-parameter"; + +/// Service temporarily unavailable +constexpr const char * ERR_SERVICE_UNAVAILABLE = "service-unavailable"; + +/// Internal server error +constexpr const char * ERR_INTERNAL_ERROR = "internal-error"; + +/// Collection not supported on entity type +constexpr const char * ERR_COLLECTION_NOT_SUPPORTED = "collection-not-supported"; + +/// Payload too large (used for file upload size limits) +constexpr const char * ERR_PAYLOAD_TOO_LARGE = "payload-too-large"; + +/// Feature not implemented (SOVD 501 Not Implemented) +constexpr const char * ERR_NOT_IMPLEMENTED = "not-implemented"; + +/// Authentication required +constexpr const char * ERR_UNAUTHORIZED = "unauthorized"; + +/// Access denied / insufficient permissions +constexpr const char * ERR_FORBIDDEN = "forbidden"; + +/// Rate limit exceeded (429 Too Many Requests) +constexpr const char * ERR_RATE_LIMIT_EXCEEDED = "rate-limit-exceeded"; + +/// Generic vendor-specific error (used with vendor_code field) +constexpr const char * ERR_VENDOR_ERROR = "vendor-error"; + +/** + * @brief ros2_medkit Vendor Error Codes (x-medkit-*) + * + * These are ros2_medkit-specific error codes that provide detailed + * information about ROS 2-specific failures. When used, the error + * response should include: + * - error_code: "vendor-error" + * - vendor_code: one of these x-medkit-* codes + */ + +/// ROS 2 service call timed out or service unavailable +constexpr const char * ERR_X_MEDKIT_ROS2_SERVICE_UNAVAILABLE = "x-medkit-ros2-service-unavailable"; + +/// ROS 2 action goal was rejected +constexpr const char * ERR_X_MEDKIT_ROS2_ACTION_REJECTED = "x-medkit-ros2-action-rejected"; + +/// ROS 2 parameter is read-only and cannot be modified +constexpr const char * ERR_X_MEDKIT_ROS2_PARAMETER_READ_ONLY = "x-medkit-ros2-parameter-read-only"; + +/// Dynamic type introspection failed for ROS 2 message +constexpr const char * ERR_X_MEDKIT_ROS2_TYPE_INTROSPECTION_FAILED = "x-medkit-ros2-type-introspection-failed"; + +/// ROS 2 node not available or not responding +constexpr const char * ERR_X_MEDKIT_ROS2_NODE_UNAVAILABLE = "x-medkit-ros2-node-unavailable"; + +/// ROS 2 topic not available +constexpr const char * ERR_X_MEDKIT_ROS2_TOPIC_UNAVAILABLE = "x-medkit-ros2-topic-unavailable"; + +/// ROS 2 action server not available +constexpr const char * ERR_X_MEDKIT_ROS2_ACTION_UNAVAILABLE = "x-medkit-ros2-action-unavailable"; + +/// Gateway is shutting down; request cannot be served +constexpr const char * ERR_X_MEDKIT_GATEWAY_SHUTDOWN = "x-medkit-gateway-shutdown"; + +/// Subscription creation in Ros2SubscriptionExecutor failed (rcl-level error) +constexpr const char * ERR_X_MEDKIT_SUBSCRIBE_FAILED = "x-medkit-subscribe-failed"; + +/// Concurrent cold-wait pool saturation; retry with backoff +constexpr const char * ERR_X_MEDKIT_COLD_WAIT_CAP_EXCEEDED = "x-medkit-cold-wait-cap-exceeded"; + +/// Software update package not found +constexpr const char * ERR_X_MEDKIT_UPDATE_NOT_FOUND = "x-medkit-update-not-found"; + +/// Duplicate update package ID on registration +constexpr const char * ERR_X_MEDKIT_UPDATE_ALREADY_EXISTS = "x-medkit-update-already-exists"; + +/// Cannot modify/delete update while operation is in progress +constexpr const char * ERR_X_MEDKIT_UPDATE_IN_PROGRESS = "x-medkit-update-in-progress"; + +/// Execute called before prepare completed +constexpr const char * ERR_X_MEDKIT_UPDATE_NOT_PREPARED = "x-medkit-update-not-prepared"; + +/// Automated mode not supported for this package +constexpr const char * ERR_X_MEDKIT_UPDATE_NOT_AUTOMATED = "x-medkit-update-not-automated"; + +/// Vendor-specific: invalid resource URI format for subscriptions +constexpr const char * ERR_X_MEDKIT_INVALID_RESOURCE_URI = "x-medkit-invalid-resource-uri"; + +/// Vendor-specific: collection not supported for entity type +constexpr const char * ERR_X_MEDKIT_COLLECTION_NOT_SUPPORTED = "x-medkit-collection-not-supported"; + +/// Vendor-specific: no data provider registered for collection +constexpr const char * ERR_X_MEDKIT_COLLECTION_NOT_AVAILABLE = "x-medkit-collection-not-available"; + +/// Vendor-specific: resource URI entity doesn't match route entity +constexpr const char * ERR_X_MEDKIT_ENTITY_MISMATCH = "x-medkit-entity-mismatch"; + +/// Vendor-specific: unsupported subscription protocol +constexpr const char * ERR_X_MEDKIT_UNSUPPORTED_PROTOCOL = "x-medkit-unsupported-protocol"; + +/// SOVD standard: client's lock was broken by another client (409) +constexpr const char * ERR_LOCK_BROKEN = "lock-broken"; + +// Script error codes (vendor-specific only; generic cases use ERR_RESOURCE_NOT_FOUND / ERR_INVALID_PARAMETER) +constexpr const char * ERR_SCRIPT_ALREADY_EXISTS = "x-medkit-script-already-exists"; +constexpr const char * ERR_SCRIPT_MANAGED = "x-medkit-managed-script"; +constexpr const char * ERR_SCRIPT_RUNNING = "x-medkit-script-running"; +constexpr const char * ERR_SCRIPT_NOT_RUNNING = "x-medkit-script-not-running"; +constexpr const char * ERR_SCRIPT_CONCURRENCY_LIMIT = "x-medkit-concurrency-limit"; +constexpr const char * ERR_SCRIPT_FILE_TOO_LARGE = "x-medkit-script-too-large"; + +/// Plugin provider returned an error (used for DataProvider/OperationProvider/FaultProvider errors) +constexpr const char * ERR_PLUGIN_ERROR = "x-medkit-plugin-error"; + +/** + * @brief Check if an error code is a vendor-specific code + * @param error_code Error code to check + * @return true if code starts with "x-medkit-" + */ +inline bool is_vendor_error_code(const std::string & error_code) { + return error_code.rfind("x-medkit-", 0) == 0; +} + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/fan_out_helpers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/fan_out_helpers.hpp similarity index 99% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/fan_out_helpers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/fan_out_helpers.hpp index 9d7e90391..406f96a6e 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/fan_out_helpers.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/fan_out_helpers.hpp @@ -23,7 +23,7 @@ #include #include "ros2_medkit_gateway/aggregation/aggregation_manager.hpp" -#include "ros2_medkit_gateway/http/x_medkit.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/auth_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/auth_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/auth_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/auth_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/bulkdata_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/bulkdata_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/bulkdata_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/bulkdata_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/capability_builder.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/capability_builder.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/capability_builder.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/capability_builder.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/config_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/config_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/config_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/config_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/data_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/data_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/data_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/data_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/discovery_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/discovery_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/discovery_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/discovery_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/docs_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/docs_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/docs_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/docs_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/handlers.hpp similarity index 56% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/handlers.hpp index b7e5239f3..a5a6c1767 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/handlers.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/handlers.hpp @@ -22,24 +22,24 @@ */ // Discovery handlers (unified for all entity types) -#include "ros2_medkit_gateway/http/handlers/discovery_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/discovery_handlers.hpp" // Resource handlers (unified across entity types) -#include "ros2_medkit_gateway/http/handlers/data_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/data_handlers.hpp" // Other handlers -#include "ros2_medkit_gateway/http/handlers/auth_handlers.hpp" -#include "ros2_medkit_gateway/http/handlers/bulkdata_handlers.hpp" -#include "ros2_medkit_gateway/http/handlers/config_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/auth_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/bulkdata_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/config_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/docs_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/health_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/lock_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/log_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/operation_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/script_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/trigger_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/update_handlers.hpp" #include "ros2_medkit_gateway/http/handlers/cyclic_subscription_handlers.hpp" -#include "ros2_medkit_gateway/http/handlers/docs_handlers.hpp" #include "ros2_medkit_gateway/http/handlers/fault_handlers.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/http/handlers/health_handlers.hpp" -#include "ros2_medkit_gateway/http/handlers/lock_handlers.hpp" -#include "ros2_medkit_gateway/http/handlers/log_handlers.hpp" -#include "ros2_medkit_gateway/http/handlers/operation_handlers.hpp" -#include "ros2_medkit_gateway/http/handlers/script_handlers.hpp" #include "ros2_medkit_gateway/http/handlers/sse_fault_handler.hpp" -#include "ros2_medkit_gateway/http/handlers/trigger_handlers.hpp" -#include "ros2_medkit_gateway/http/handlers/update_handlers.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/health_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/health_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/health_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/health_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/lock_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/lock_handlers.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/lock_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/lock_handlers.hpp index 0749853b9..914354109 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/lock_handlers.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/lock_handlers.hpp @@ -14,8 +14,8 @@ #pragma once +#include "ros2_medkit_gateway/core/managers/lock_manager.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/lock_manager.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/log_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/log_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/log_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/log_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/operation_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/operation_handlers.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/operation_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/operation_handlers.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/script_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/script_handlers.hpp similarity index 97% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/script_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/script_handlers.hpp index ef8015565..83f2f900a 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/script_handlers.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/script_handlers.hpp @@ -14,8 +14,8 @@ #pragma once +#include "ros2_medkit_gateway/core/managers/script_manager.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/script_manager.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/sse_transport_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/sse_transport_provider.hpp similarity index 93% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/sse_transport_provider.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/sse_transport_provider.hpp index 9c7d9a438..3c4997acb 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/sse_transport_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/sse_transport_provider.hpp @@ -19,8 +19,8 @@ #include #include -#include "ros2_medkit_gateway/http/sse_client_tracker.hpp" -#include "ros2_medkit_gateway/subscription_transport.hpp" +#include "ros2_medkit_gateway/core/http/sse_client_tracker.hpp" +#include "ros2_medkit_gateway/core/subscription_transport.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/trigger_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/trigger_handlers.hpp similarity index 96% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/trigger_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/trigger_handlers.hpp index 2ffcd9f6b..fafcf2e18 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/trigger_handlers.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/trigger_handlers.hpp @@ -22,9 +22,9 @@ #include +#include "ros2_medkit_gateway/core/http/sse_client_tracker.hpp" +#include "ros2_medkit_gateway/core/managers/trigger_manager.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/http/sse_client_tracker.hpp" -#include "ros2_medkit_gateway/trigger_manager.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/update_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/update_handlers.hpp similarity index 96% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/update_handlers.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/update_handlers.hpp index 236cb6ac2..c269542fd 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/update_handlers.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/handlers/update_handlers.hpp @@ -16,8 +16,8 @@ #include +#include "ros2_medkit_gateway/core/managers/update_manager.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/updates/update_manager.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/http_server.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/http_server.hpp similarity index 96% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/http_server.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/http_server.hpp index 2f3f56d5a..0dbbd61ec 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/http_server.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/http_server.hpp @@ -19,8 +19,8 @@ #include #include -#include "ros2_medkit_gateway/auth/auth_config.hpp" -#include "ros2_medkit_gateway/config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/config.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/http_utils.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/http_utils.hpp similarity index 99% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/http_utils.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/http_utils.hpp index b8054015f..75c8c27bf 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/http_utils.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/http_utils.hpp @@ -25,7 +25,7 @@ #include #include -#include "ros2_medkit_gateway/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/rate_limiter.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/rate_limiter.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/rate_limiter.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/rate_limiter.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/rest_server.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/rest_server.hpp similarity index 87% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/rest_server.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/rest_server.hpp index 69edb4278..114beb3ec 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/rest_server.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/rest_server.hpp @@ -22,14 +22,14 @@ #include #include -#include "ros2_medkit_gateway/auth/auth_config.hpp" -#include "ros2_medkit_gateway/auth/auth_manager.hpp" -#include "ros2_medkit_gateway/auth/auth_middleware.hpp" -#include "ros2_medkit_gateway/config.hpp" -#include "ros2_medkit_gateway/http/handlers/handlers.hpp" -#include "ros2_medkit_gateway/http/http_server.hpp" -#include "ros2_medkit_gateway/http/rate_limiter.hpp" -#include "ros2_medkit_gateway/http/sse_client_tracker.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_manager.hpp" +#include "ros2_medkit_gateway/core/auth/auth_middleware.hpp" +#include "ros2_medkit_gateway/core/config.hpp" +#include "ros2_medkit_gateway/core/http/handlers/handlers.hpp" +#include "ros2_medkit_gateway/core/http/http_server.hpp" +#include "ros2_medkit_gateway/core/http/rate_limiter.hpp" +#include "ros2_medkit_gateway/core/http/sse_client_tracker.hpp" // Forward declare RouteRegistry to avoid pulling in full header namespace ros2_medkit_gateway { @@ -65,6 +65,11 @@ class RESTServer { const TlsConfig & tls_config = TlsConfig{}); ~RESTServer(); + RESTServer(const RESTServer &) = delete; + RESTServer & operator=(const RESTServer &) = delete; + RESTServer(RESTServer &&) = delete; + RESTServer & operator=(RESTServer &&) = delete; + void start(); void stop(); diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/sse_client_tracker.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/sse_client_tracker.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/sse_client_tracker.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/sse_client_tracker.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/warning_codes.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/warning_codes.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/warning_codes.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/warning_codes.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/x_medkit.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/x_medkit.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/x_medkit.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/http/x_medkit.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/log_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/log_types.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/log_types.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/log_types.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/bulk_data_store.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/bulk_data_store.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/bulk_data_store.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/bulk_data_store.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/lock_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/lock_manager.hpp similarity index 99% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/lock_manager.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/lock_manager.hpp index b91618781..11a5ac47c 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/lock_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/lock_manager.hpp @@ -25,7 +25,7 @@ #include -#include "ros2_medkit_gateway/models/thread_safe_entity_cache.hpp" +#include "ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/script_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/script_manager.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/script_manager.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/script_manager.hpp index b9ed0989c..0483b07de 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/script_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/script_manager.hpp @@ -14,7 +14,7 @@ #pragma once -#include "ros2_medkit_gateway/scripts/script_provider.hpp" +#include "ros2_medkit_gateway/core/providers/script_provider.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/subscription_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/subscription_manager.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/subscription_manager.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/subscription_manager.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/trigger_manager.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_manager.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/trigger_manager.hpp index fc9f9dd8e..ac45da3c3 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/trigger_manager.hpp @@ -30,9 +30,9 @@ #include #include -#include "ros2_medkit_gateway/condition_evaluator.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" -#include "ros2_medkit_gateway/trigger_store.hpp" +#include "ros2_medkit_gateway/core/condition_evaluator.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/trigger_store.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/update_manager.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_manager.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/update_manager.hpp index 619957c1d..9e0ab4947 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/managers/update_manager.hpp @@ -25,7 +25,7 @@ #include #include -#include "ros2_medkit_gateway/updates/update_provider.hpp" +#include "ros2_medkit_gateway/core/providers/update_provider.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/aggregation_service.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/aggregation_service.hpp similarity index 97% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/aggregation_service.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/aggregation_service.hpp index ec16b9e3d..674c8b4ab 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/aggregation_service.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/aggregation_service.hpp @@ -14,8 +14,8 @@ #pragma once -#include "ros2_medkit_gateway/models/entity_types.hpp" -#include "ros2_medkit_gateway/models/thread_safe_entity_cache.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/entity_capabilities.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/entity_capabilities.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/entity_capabilities.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/entity_capabilities.hpp index 7228a9c0a..7d804d18f 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/entity_capabilities.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/entity_capabilities.hpp @@ -14,7 +14,7 @@ #pragma once -#include "ros2_medkit_gateway/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/entity_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/entity_types.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/entity_types.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/entity_types.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/error_info.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/error_info.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/error_info.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/error_info.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/thread_safe_entity_cache.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/thread_safe_entity_cache.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp index 82e9009a8..0e8c71249 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/models/thread_safe_entity_cache.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp @@ -14,11 +14,11 @@ #pragma once -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/openapi/route_descriptions.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/openapi/route_descriptions.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/openapi/route_descriptions.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/openapi/route_descriptions.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/entity_change_scope.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/entity_change_scope.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/entity_change_scope.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/entity_change_scope.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/gateway_plugin.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/gateway_plugin.hpp new file mode 100644 index 000000000..bb24aa58e --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/gateway_plugin.hpp @@ -0,0 +1,137 @@ +// Copyright 2026 bburda +// +// 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 +#include +#include +#include + +#include "ros2_medkit_gateway/core/plugins/plugin_http_types.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" + +namespace ros2_medkit_gateway { + +class PluginContext; + +/** + * @brief Base class for all gateway plugins + * + * Plugins are loaded as shared libraries (.so) via dlopen/dlsym. + * Each .so must export two extern "C" functions: + * int plugin_api_version(); // must return PLUGIN_API_VERSION + * GatewayPlugin* create_plugin(); // factory + * + * Plugins implement this base class plus one or more provider interfaces + * (UpdateProvider, IntrospectionProvider) via multiple inheritance. + * + * @see PluginManager for loading and lifecycle orchestration + * @see UpdateProvider, IntrospectionProvider for typed interfaces + */ +class GatewayPlugin { + public: + /// Describes a single REST route registered by a plugin + struct PluginRoute { + std::string method; ///< HTTP method ("GET", "POST", "PUT", "DELETE") + std::string pattern; ///< Regex pattern relative to api_prefix + std::function handler; + }; + + virtual ~GatewayPlugin() = default; + + /** + * @brief Unique name for this plugin + * @return Plugin name (e.g., "systemd", "procfs", "mender_ota") + */ + virtual std::string name() const = 0; + + /** + * @brief Configure the plugin + * + * Called once after loading with per-plugin config from YAML. + * + * @param config JSON configuration object + */ + virtual void configure(const nlohmann::json & config) = 0; + + /** + * @brief Receive gateway context + * + * Called after configure(). Provides access to the ROS 2 node, + * entity cache, fault data, and HTTP handler utilities. + * Store the reference if needed during runtime. + * + * @param context Gateway plugin context (outlives this plugin) + */ + virtual void set_context(PluginContext & /*context*/) { + } + + /** + * @brief Return custom REST routes for this plugin + * + * Called once during REST server setup. The gateway registers the returned + * routes on the HTTP server, wrapping PluginRequest/PluginResponse around + * the underlying library types. + * + * @return Routes to register (method, pattern, handler) + */ + virtual std::vector get_routes() { + return {}; + } + + /** + * @brief Shutdown hook for cleanup + * + * Called before the plugin is destroyed. Use for releasing + * resources, closing connections, etc. + */ + virtual void shutdown() { + } + + protected: + /// Log an informational message (routed to gateway's ROS 2 logger) + void log_info(const std::string & msg) const { + if (log_fn_) { + log_fn_(PluginLogLevel::kInfo, msg); + } + } + + /// Log a warning message + void log_warn(const std::string & msg) const { + if (log_fn_) { + log_fn_(PluginLogLevel::kWarn, msg); + } + } + + /// Log an error message + void log_error(const std::string & msg) const { + if (log_fn_) { + log_fn_(PluginLogLevel::kError, msg); + } + } + + private: + friend class PluginManager; // Sets log_fn_ after construction + + /// Logging callback set by PluginManager. Routes to rclcpp::get_logger("plugin."). + std::function log_fn_; + + /// Called by PluginManager to wire up logging + void set_logger(std::function fn) { + log_fn_ = std::move(fn); + } +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_context.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_context.hpp new file mode 100644 index 000000000..ced7a19bb --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_context.hpp @@ -0,0 +1,282 @@ +// Copyright 2026 bburda +// +// 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 "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/managers/lock_manager.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/plugins/entity_change_scope.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_http_types.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rclcpp { +class Node; +} + +namespace ros2_medkit_gateway { + +class ResourceSamplerRegistry; + +// Forward declarations for trigger-related types +class ResourceChangeNotifier; +class ConditionRegistry; + +/** + * @brief Entity information exposed to plugins + */ +struct PluginEntityInfo { + SovdEntityType type{SovdEntityType::UNKNOWN}; + std::string id; + std::string namespace_path; ///< ROS 2 namespace (for component fault filtering) + std::string fqn; ///< Fully qualified ROS 2 node name +}; + +/** + * @brief Context interface providing plugins access to gateway data and utilities + * + * Passed to plugins during lifecycle via set_context(). Replaces the old set_node() + * by providing both ROS 2 node access and gateway-level abstractions. + * + * @note This interface is versioned alongside PLUGIN_API_VERSION. New methods may + * be added in future versions (entity data access, configuration queries, etc.). + * + * @par Thread Safety + * All methods are safe to call from any thread. Entity and fault queries use + * the gateway's thread-safe caches internally. + */ +class PluginContext { + public: + virtual ~PluginContext() = default; + + // ---- ROS 2 access (replaces set_node) ---- + + /// Get ROS 2 node pointer for subscriptions, service clients, etc. + virtual rclcpp::Node * node() const = 0; + + // ---- Entity access (read-only) ---- + + /// Look up an entity by ID. Returns nullopt if not found. + virtual std::optional get_entity(const std::string & id) const = 0; + + /// Get all Apps belonging to a Component (for aggregation endpoints) + virtual std::vector get_child_apps(const std::string & component_id) const = 0; + + // ---- Fault access ---- + + /// List faults for a given entity. Returns JSON array of fault objects. + /// Empty array if entity has no faults or fault manager is unavailable. + virtual nlohmann::json list_entity_faults(const std::string & entity_id) const = 0; + + // ---- HTTP handler utilities (for entity-scoped routes) ---- + + /** + * @brief Validate entity exists and matches route type, sending SOVD error if not + * + * Use this in get_routes() handlers to validate entity IDs from path params. + * On failure, an appropriate SOVD GenericError response is sent automatically. + * + * @param req Plugin request (extracts expected entity type from path) + * @param res Plugin response (error sent here on failure) + * @param entity_id Entity ID from path parameter (e.g., req.path_param(1)) + * @return Entity info if valid, nullopt if error was sent + */ + virtual std::optional validate_entity_for_route(const PluginRequest & req, PluginResponse & res, + const std::string & entity_id) const = 0; + + // ---- Capability registration ---- + + /** + * @brief Register a custom capability for all entities of a given type + * + * The capability will appear in the entity's capabilities array with an + * auto-generated href. For example, registering "x-medkit-traces" for + * SovdEntityType::APP produces: {"name": "x-medkit-traces", "href": "/api/v1/apps/{id}/x-medkit-traces"} + * + * The plugin must also return a matching route from get_routes(). + * + * @param entity_type Entity type to add the capability to + * @param capability_name Capability name (use x- prefix for vendor extensions) + */ + virtual void register_capability(SovdEntityType entity_type, const std::string & capability_name) = 0; + + /** + * @brief Register a custom capability for a specific entity + * + * Like register_capability(entity_type, name) but scoped to a single entity. + * + * @param entity_id Specific entity ID + * @param capability_name Capability name (use x- prefix for vendor extensions) + */ + virtual void register_entity_capability(const std::string & entity_id, const std::string & capability_name) = 0; + + // ---- Capability query (used by discovery handlers) ---- + + /// Get plugin-registered capabilities for an entity type + virtual std::vector get_type_capabilities(SovdEntityType entity_type) const = 0; + + /// Get plugin-registered capabilities for a specific entity + virtual std::vector get_entity_capabilities(const std::string & entity_id) const = 0; + + // ---- Locking ---- + + /** + * @brief Check if a lock blocks access to a collection on an entity. + * + * @param entity_id Entity to check + * @param client_id Client requesting access + * @param collection Resource collection being accessed (e.g. "configurations") + * @return LockAccessResult with allowed/denied status and details + */ + virtual LockAccessResult check_lock(const std::string & entity_id, const std::string & client_id, + const std::string & collection) const = 0; + + /** + * @brief Acquire a lock on an entity. + * + * @param entity_id Entity to lock + * @param client_id Client acquiring the lock + * @param scopes Optional lock scopes (empty = all collections) + * @param expiration_seconds Lock TTL in seconds + * @return LockInfo on success, LockError on failure + */ + virtual tl::expected acquire_lock(const std::string & entity_id, const std::string & client_id, + const std::vector & scopes, + int expiration_seconds) = 0; + + /** + * @brief Release a lock on an entity. + * + * @param entity_id Entity to unlock + * @param client_id Client releasing the lock + * @return void on success, LockError on failure + */ + virtual tl::expected release_lock(const std::string & entity_id, const std::string & client_id) = 0; + + // ---- Entity bulk access ---- + + /// Get a snapshot of all discovered entities (areas, components, apps, functions). + /// Returns an IntrospectionInput populated from the current entity cache. + virtual IntrospectionInput get_entity_snapshot() const { + return {}; + } + + // ---- All-faults access ---- + + /// List all faults across all entities. Returns JSON with "faults" array. + /// Empty object if fault manager is unavailable. + virtual nlohmann::json list_all_faults() const { + return nlohmann::json::object(); + } + + // ---- Resource sampler registration ---- + + /// Register a cyclic subscription sampler for a custom collection. + virtual void register_sampler( + const std::string & /*collection*/, + const std::function(const std::string &, const std::string &)> & + /*fn*/) { + } + + // ---- Trigger infrastructure access ---- + + /** + * @brief Get the ResourceChangeNotifier for publishing or subscribing to resource changes. + * + * Always returns a valid pointer - ResourceChangeNotifier is created unconditionally + * in GatewayNode regardless of trigger configuration. + */ + virtual ResourceChangeNotifier * get_resource_change_notifier() = 0; + + /** + * @brief Get the ConditionRegistry for registering custom trigger condition evaluators. + * + * Always returns a valid pointer - ConditionRegistry is created unconditionally + * in GatewayNode regardless of trigger configuration. + */ + virtual ConditionRegistry * get_condition_registry() = 0; + + // ---- Entity surface notifications (plugin API v7) ---- + + /** + * @brief Tell the gateway that this plugin has finished mutating entities. + * + * Call this AFTER any change that adds, removes, or restructures entities + * on disk or in the running runtime (deploying a new node under a manifest + * fragment, removing a previously-deployed app, renaming a component). + * The gateway responds by re-reading its manifest sources (including any + * configured fragments directory) and running a discovery pass for the + * affected scope. By the time this returns, subsequent `get_entity` and + * HTTP discovery endpoints reflect the new surface. + * + * @param scope Hint that lets the gateway limit the rediscovery work. + * `EntityChangeScope::full_refresh()` asks for a global pass. + * + * @par Thread safety + * Safe to call from any thread. The v7 reference implementation is + * SYNCHRONOUS: the caller's thread drives the full manifest reload + + * discovery refresh before the call returns, under an internal refresh + * mutex that also serializes the periodic refresh timer. As a result: + * * the call may block for seconds on large manifests / slow plugins; + * * plugins MUST NOT hold their own mutexes across this call if any + * of their own callbacks (introspect, data/operation/fault providers) + * could try to reacquire that mutex - doing so deadlocks; + * * calling this method from within your own `IntrospectionProvider:: + * introspect()` callback is detected and skipped with a warning log + * (see `GatewayNode::handle_entity_change_notification`). The design + * assumes introspect already runs inside a refresh pass, so a nested + * notification would be redundant. + * + * @par Backwards compatibility + * Default implementation is a no-op. Plugin source written against plugin + * API v6 compiles unchanged against v7 headers (source-compatible) - no + * code changes are required. The plugin loader compares the exported + * `plugin_api_version()` against the gateway's `PLUGIN_API_VERSION` with + * strict equality, so a plugin `.so` pre-compiled against v6 IS rejected; + * recompilation against v7 headers is required. + * + * @par Fragment file contract (when used with discovery.manifest.fragments_dir) + * Plugins that deploy / remove manifest fragments on disk before calling + * this method MUST publish the final content atomically. The gateway's + * fragment scanner reads each file on the caller's thread once the + * notification arrives; a partially-written fragment causes the reload + * to fail, which rolls back the entire manifest merge (see the design + * doc's "all-or-nothing fragment contract" section). The recommended + * pattern is: write to `fragments_dir/.tmp-.yaml`, `fsync`, then + * `rename()` (POSIX atomic within the same filesystem) to + * `fragments_dir/.yaml`. The rename is the commit point that makes + * the fragment visible to the next reload. + */ + virtual void notify_entities_changed(const EntityChangeScope & /*scope*/) { + } +}; + +// Forward declarations +class GatewayNode; +class FaultManager; + +/// Factory for creating the concrete gateway plugin context +std::unique_ptr make_gateway_plugin_context(GatewayNode * node, FaultManager * fault_manager, + ResourceSamplerRegistry * sampler_registry = nullptr); + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_http_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_http_types.hpp new file mode 100644 index 000000000..643e43d42 --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_http_types.hpp @@ -0,0 +1,69 @@ +// Copyright 2026 bburda +// +// 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 +#include + +namespace ros2_medkit_gateway { + +/// Thin read-only wrapper over an HTTP request. +/// Hides the underlying HTTP library (currently cpp-httplib) from plugin code. +/// Constructed by the gateway per-request; plugins receive it by const reference. +class PluginRequest { + public: + /// Construct from opaque HTTP request pointer (gateway-internal). + explicit PluginRequest(const void * impl); + + /// Extract a path parameter by regex capture group index. + /// Index 0 is the full match; index 1 is the first capture group. + std::string path_param(size_t index) const; + + /// Get a request header value by name. Returns empty string if not present. + std::string header(const std::string & name) const; + + /// Full request path (e.g. "/api/v1/apps/my_app/data"). + const std::string & path() const; + + /// Request body (by reference - avoids copying large payloads). + const std::string & body() const; + + /// Get a query parameter value by name. Returns empty string if not present. + std::string query_param(const std::string & name) const; + + private: + const void * impl_; +}; + +/// Thin wrapper over an HTTP response. +/// Hides the underlying HTTP library from plugin code. +/// Constructed by the gateway per-request; plugins receive it by reference. +class PluginResponse { + public: + /// Construct from opaque HTTP response pointer (gateway-internal). + explicit PluginResponse(void * impl); + + /// Send a JSON success response (HTTP 200). + void send_json(const nlohmann::json & data); + + /// Send a SOVD-compliant error response. + void send_error(int status, const std::string & error_code, const std::string & message, + const nlohmann::json & parameters = {}); + + private: + void * impl_; +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_loader.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_loader.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_loader.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_loader.hpp index 88cd04bba..c280c8250 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_loader.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_loader.hpp @@ -14,7 +14,7 @@ #pragma once -#include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_manager.hpp similarity index 90% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_manager.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_manager.hpp index 85e53ec8a..079dea3c1 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_manager.hpp @@ -14,20 +14,20 @@ #pragma once -#include "ros2_medkit_gateway/discovery/introspection_provider.hpp" -#include "ros2_medkit_gateway/logs/log_provider.hpp" -#include "ros2_medkit_gateway/openapi/route_descriptions.hpp" -#include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" -#include "ros2_medkit_gateway/plugins/plugin_context.hpp" -#include "ros2_medkit_gateway/plugins/plugin_loader.hpp" -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" -#include "ros2_medkit_gateway/providers/data_provider.hpp" -#include "ros2_medkit_gateway/providers/fault_provider.hpp" -#include "ros2_medkit_gateway/providers/operation_provider.hpp" -#include "ros2_medkit_gateway/resource_sampler.hpp" -#include "ros2_medkit_gateway/scripts/script_provider.hpp" -#include "ros2_medkit_gateway/subscription_transport.hpp" -#include "ros2_medkit_gateway/updates/update_provider.hpp" +#include "ros2_medkit_gateway/core/openapi/route_descriptions.hpp" +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_context.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_loader.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" +#include "ros2_medkit_gateway/core/providers/data_provider.hpp" +#include "ros2_medkit_gateway/core/providers/fault_provider.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" +#include "ros2_medkit_gateway/core/providers/log_provider.hpp" +#include "ros2_medkit_gateway/core/providers/operation_provider.hpp" +#include "ros2_medkit_gateway/core/providers/script_provider.hpp" +#include "ros2_medkit_gateway/core/providers/update_provider.hpp" +#include "ros2_medkit_gateway/core/resource_sampler.hpp" +#include "ros2_medkit_gateway/core/subscription_transport.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_types.hpp new file mode 100644 index 000000000..d4598fbb3 --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/plugins/plugin_types.hpp @@ -0,0 +1,55 @@ +// Copyright 2026 bburda +// +// 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 +#include + +/// Visibility macro for plugin extern "C" exports. +/// Ensures symbols are exported even with -fvisibility=hidden builds. +#ifdef _WIN32 +#define GATEWAY_PLUGIN_EXPORT __declspec(dllexport) +#else +#define GATEWAY_PLUGIN_EXPORT __attribute__((visibility("default"))) +#endif + +namespace ros2_medkit_gateway { + +/// Current plugin API version. Plugins must export this value from plugin_api_version(). +/// +/// Version history: +/// - v6: ScriptProvider, locking API, extended PluginContext (entity snapshot, +/// fault listing, sampler registration). +/// - v7: PluginContext::notify_entities_changed(EntityChangeScope) for plugins +/// that mutate the entity surface at runtime. Default implementation is +/// a no-op so plugin SOURCE written against v6 compiles unchanged +/// against v7 headers (source-compatible). Binary compatibility is not +/// provided - `plugin_loader` uses strict equality against this value, +/// so a pre-compiled v6 `.so` is rejected. Out-of-tree plugins must be +/// recompiled against v7 headers; in-tree plugins that `return +/// PLUGIN_API_VERSION` pick up the bump automatically. +constexpr int PLUGIN_API_VERSION = 7; + +/// Log severity levels for plugin logging callback +enum class PluginLogLevel { kInfo, kWarn, kError }; + +/// Configuration for a single plugin loaded from YAML +struct PluginConfig { + std::string name; ///< Plugin key from YAML (used for parameter namespace) + std::string path; ///< Path to .so file + nlohmann::json config; ///< Per-plugin configuration (passed to configure()) +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/data_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/data_provider.hpp new file mode 100644 index 000000000..179fc8be9 --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/data_provider.hpp @@ -0,0 +1,84 @@ +// Copyright 2026 bburda +// +// 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 +#include +#include + +namespace ros2_medkit_gateway { + +enum class DataProviderError { + EntityNotFound, + ResourceNotFound, + ReadOnly, + WriteOnly, + TransportError, + Timeout, + InvalidValue, + Internal +}; + +struct DataProviderErrorInfo { + DataProviderError code; + std::string message; + int http_status{500}; ///< Suggested HTTP status code +}; + +/** + * @brief Provider interface for entity data resources + * + * Typed provider interface for plugins that serve SOVD data resources + * (GET /{entity_type}/{id}/data, GET /{entity_type}/{id}/data/{name}). + * Unlike LogProvider/ScriptProvider (singletons), multiple DataProvider + * plugins can coexist - each handles its own set of entities. + * + * Entity ownership is determined by IntrospectionProvider: entities + * created by a plugin's introspect() are routed to that plugin's + * DataProvider. + * + * @par Thread safety + * All methods may be called from multiple HTTP handler threads concurrently. + * Implementations must provide their own synchronization. + * + * @see GatewayPlugin for the base class all plugins must also implement + * @see OperationProvider for the operations counterpart + */ +class DataProvider { + public: + virtual ~DataProvider() = default; + + /// List available data resources for an entity + /// @param entity_id SOVD entity ID (e.g., "openbsw_demo_ecu") + /// @return JSON with {"items": [...]} array of data resource descriptors + virtual tl::expected list_data(const std::string & entity_id) = 0; + + /// Read a specific data resource + /// @param entity_id SOVD entity ID + /// @param resource_name Data resource name (e.g., "hardcoded_data") + /// @return JSON response body for the data resource + virtual tl::expected read_data(const std::string & entity_id, + const std::string & resource_name) = 0; + + /// Write a data resource value + /// @param entity_id SOVD entity ID + /// @param resource_name Data resource name + /// @param value JSON value to write + /// @return JSON response body confirming the write + virtual tl::expected + write_data(const std::string & entity_id, const std::string & resource_name, const nlohmann::json & value) = 0; +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/fault_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/fault_provider.hpp new file mode 100644 index 000000000..e129e0038 --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/fault_provider.hpp @@ -0,0 +1,71 @@ +// Copyright 2026 bburda +// +// 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 +#include +#include + +namespace ros2_medkit_gateway { + +enum class FaultProviderError { EntityNotFound, FaultNotFound, TransportError, Timeout, Internal }; + +struct FaultProviderErrorInfo { + FaultProviderError code; + std::string message; + int http_status{500}; ///< Suggested HTTP status code +}; + +/** + * @brief Provider interface for entity fault/DTC resources + * + * Typed provider interface for plugins that serve SOVD faults + * (GET /{entity_type}/{id}/faults, GET /{entity_type}/{id}/faults/{code}). + * Per-entity routing like DataProvider. + * + * Plugins implementing this interface query their backend (e.g., UDS + * ReadDTCInformation 0x19) on demand and return faults in SOVD format. + * + * @par Thread safety + * All methods may be called concurrently. Implementations must synchronize. + * + * @see GatewayPlugin for the base class all plugins must also implement + * @see DataProvider for the data counterpart + */ +class FaultProvider { + public: + virtual ~FaultProvider() = default; + + /// List faults for an entity + /// @param entity_id SOVD entity ID + /// @return JSON with {"items": [...]} array of fault descriptors + virtual tl::expected list_faults(const std::string & entity_id) = 0; + + /// Get a specific fault with environment data + /// @param entity_id SOVD entity ID + /// @param fault_code Fault code (e.g., DTC identifier) + /// @return JSON response with fault detail + environment data + virtual tl::expected get_fault(const std::string & entity_id, + const std::string & fault_code) = 0; + + /// Clear a fault + /// @param entity_id SOVD entity ID + /// @param fault_code Fault code to clear + /// @return JSON response confirming the clear + virtual tl::expected clear_fault(const std::string & entity_id, + const std::string & fault_code) = 0; +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/host_info_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/host_info_provider.hpp similarity index 97% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/host_info_provider.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/host_info_provider.hpp index 0ad691aea..7b17456c0 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/host_info_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/host_info_provider.hpp @@ -14,7 +14,7 @@ #pragma once -#include "ros2_medkit_gateway/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/introspection_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/introspection_provider.hpp new file mode 100644 index 000000000..3c6bf7a2f --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/introspection_provider.hpp @@ -0,0 +1,87 @@ +// Copyright 2026 bburda +// +// 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 +#include +#include +#include + +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" + +namespace ros2_medkit_gateway { + +/** + * @brief Snapshot of current discovery state, passed to introspection providers + */ +struct IntrospectionInput { + std::vector areas; + std::vector components; + std::vector apps; + std::vector functions; +}; + +/** + * @brief New entity definitions an introspection provider can introduce + */ +struct NewEntities { + std::vector areas; + std::vector components; + std::vector apps; + std::vector functions; +}; + +/** + * @brief Result returned by IntrospectionProvider::introspect() + */ +struct IntrospectionResult { + /// Per-entity metadata for plugin-internal use. Key = entity_id. + /// Plugins serve this data as SOVD vendor extension resources + /// via get_routes() and register_capability(). + std::unordered_map metadata; + + /// New entities discovered by this provider + NewEntities new_entities; +}; + +/** + * @brief Provider interface for platform-specific introspection + * + * Implementations enrich discovered entities with runtime metadata + * and can discover new entities from non-ROS sources. + * + * @see GatewayPlugin for the base class + * @see PluginManager for orchestration + */ +class IntrospectionProvider { + public: + virtual ~IntrospectionProvider() = default; + + /** + * @brief Core introspection method + * + * Called during each discovery cycle by the merge pipeline. + * Input contains entities from all higher-priority layers (manifest + runtime). + * + * @param input Snapshot of entities discovered by previous layers + * @return Metadata enrichments and new entities + */ + virtual IntrospectionResult introspect(const IntrospectionInput & input) = 0; +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/logs/log_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/log_provider.hpp similarity index 99% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/logs/log_provider.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/log_provider.hpp index 4d38e4ee4..1e00292ab 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/logs/log_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/log_provider.hpp @@ -14,12 +14,12 @@ #pragma once -#include "ros2_medkit_gateway/log_types.hpp" - #include #include #include +#include "ros2_medkit_gateway/core/log_types.hpp" + namespace ros2_medkit_gateway { /** diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/operation_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/operation_provider.hpp new file mode 100644 index 000000000..42374fe3d --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/operation_provider.hpp @@ -0,0 +1,94 @@ +// Copyright 2026 bburda +// +// 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 +#include +#include + +namespace ros2_medkit_gateway { + +enum class OperationProviderError { + EntityNotFound, + OperationNotFound, + InvalidParameters, + TransportError, + Timeout, + Rejected, + Internal +}; + +struct OperationProviderErrorInfo { + OperationProviderError code; + std::string message; + int http_status{500}; ///< Suggested HTTP status code +}; + +/** + * @brief Provider interface for entity operations + * + * Typed provider interface for plugins that serve SOVD operations + * (GET /{entity_type}/{id}/operations, POST /{entity_type}/{id}/operations/{name}). + * Per-entity routing like DataProvider. + * + * @par Thread safety + * All methods may be called concurrently. Implementations must synchronize. + * + * @see GatewayPlugin for the base class all plugins must also implement + * @see DataProvider for the data counterpart + */ +class OperationProvider { + public: + virtual ~OperationProvider() = default; + + /// List available operations for an entity + /// @param entity_id SOVD entity ID + /// @return JSON with {"items": [...]} array of operation descriptors + virtual tl::expected list_operations(const std::string & entity_id) = 0; + + /// Get a specific operation by name + /// @param entity_id SOVD entity ID + /// @param operation_name Operation name + /// @return JSON with operation detail, or OperationNotFound error + /// @note Default implementation calls list_operations + linear scan. + /// Override for O(1) lookup in plugins with many operations. + virtual tl::expected get_operation(const std::string & entity_id, + const std::string & operation_name) { + auto result = list_operations(entity_id); + if (!result) { + return tl::make_unexpected(result.error()); + } + if (result->contains("items") && (*result)["items"].is_array()) { + for (const auto & item : (*result)["items"]) { + if (item.value("id", "") == operation_name) { + return tl::expected{item}; + } + } + } + return tl::make_unexpected( + OperationProviderErrorInfo{OperationProviderError::OperationNotFound, "Operation not found", 404}); + } + + /// Execute an operation + /// @param entity_id SOVD entity ID + /// @param operation_name Operation name (e.g., "session_control") + /// @param parameters JSON parameters from request body + /// @return JSON response body with operation result + virtual tl::expected + execute_operation(const std::string & entity_id, const std::string & operation_name, + const nlohmann::json & parameters) = 0; +}; + +} // namespace ros2_medkit_gateway diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/scripts/script_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/script_provider.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/scripts/script_provider.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/script_provider.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/update_provider.hpp similarity index 98% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_provider.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/update_provider.hpp index e26648d4b..fdb8398b1 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/update_provider.hpp @@ -14,7 +14,7 @@ #pragma once -#include "ros2_medkit_gateway/updates/update_types.hpp" +#include "ros2_medkit_gateway/core/providers/update_types.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/update_types.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_types.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/providers/update_types.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/resource_change_notifier.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/resource_change_notifier.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/resource_change_notifier.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/resource_change_notifier.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/resource_sampler.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/resource_sampler.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/resource_sampler.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/resource_sampler.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/script_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/script_types.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/script_types.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/script_types.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/sqlite_trigger_store.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/sqlite_trigger_store.hpp similarity index 97% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/sqlite_trigger_store.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/sqlite_trigger_store.hpp index 7715dab34..4f6504d91 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/sqlite_trigger_store.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/sqlite_trigger_store.hpp @@ -19,7 +19,7 @@ #include #include -#include "ros2_medkit_gateway/trigger_store.hpp" +#include "ros2_medkit_gateway/core/trigger_store.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/subscription_transport.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/subscription_transport.hpp similarity index 96% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/subscription_transport.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/subscription_transport.hpp index a461e18ab..e19f3df1d 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/subscription_transport.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/subscription_transport.hpp @@ -23,8 +23,8 @@ #include -#include "ros2_medkit_gateway/resource_sampler.hpp" -#include "ros2_medkit_gateway/subscription_manager.hpp" +#include "ros2_medkit_gateway/core/managers/subscription_manager.hpp" +#include "ros2_medkit_gateway/core/resource_sampler.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_store.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/trigger_store.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_store.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/trigger_store.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_transport_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/trigger_transport_provider.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_transport_provider.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/trigger_transport_provider.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/type_introspection.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/type_introspection.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/type_introspection.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/type_introspection.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/version.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/version.hpp similarity index 100% rename from src/ros2_medkit_gateway/include/ros2_medkit_gateway/version.hpp rename to src/ros2_medkit_gateway/include/ros2_medkit_gateway/core/version.hpp diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/ros2_topic_data_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/ros2_topic_data_provider.hpp index b9fe65fe3..70e3e3df5 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/ros2_topic_data_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data/ros2_topic_data_provider.hpp @@ -28,7 +28,7 @@ #include -#include "ros2_medkit_gateway/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/data/topic_data_provider.hpp" #include "ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp" #include "ros2_medkit_gateway/ros2_common/ros2_subscription_slot.hpp" #include "ros2_medkit_serialization/json_serializer.hpp" @@ -99,6 +99,11 @@ class Ros2TopicDataProvider final : public TopicDataProvider { std::shared_ptr serializer, Config cfg = Config()); ~Ros2TopicDataProvider() override; + Ros2TopicDataProvider(const Ros2TopicDataProvider &) = delete; + Ros2TopicDataProvider & operator=(const Ros2TopicDataProvider &) = delete; + Ros2TopicDataProvider(Ros2TopicDataProvider &&) = delete; + Ros2TopicDataProvider & operator=(Ros2TopicDataProvider &&) = delete; + // ---- TopicDataProvider overrides ---- tl::expected sample(const std::string & topic, diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data_access_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data_access_manager.hpp index 980ea4e2f..1c5d12e8f 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data_access_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/data_access_manager.hpp @@ -23,8 +23,8 @@ #include #include -#include "ros2_medkit_gateway/data/data_types.hpp" -#include "ros2_medkit_gateway/type_introspection.hpp" +#include "ros2_medkit_gateway/core/data/data_types.hpp" +#include "ros2_medkit_gateway/core/type_introspection.hpp" #include "ros2_medkit_serialization/json_serializer.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_manager.hpp index efe827e30..03cdc578f 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/discovery_manager.hpp @@ -14,17 +14,17 @@ #pragma once -#include "ros2_medkit_gateway/discovery/discovery_enums.hpp" -#include "ros2_medkit_gateway/discovery/discovery_strategy.hpp" -#include "ros2_medkit_gateway/discovery/host_info_provider.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_enums.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_strategy.hpp" +#include "ros2_medkit_gateway/core/discovery/merge_types.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/common.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/providers/host_info_provider.hpp" #include "ros2_medkit_gateway/discovery/hybrid_discovery.hpp" #include "ros2_medkit_gateway/discovery/manifest/manifest_manager.hpp" -#include "ros2_medkit_gateway/discovery/merge_types.hpp" -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/common.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" #include "ros2_medkit_gateway/discovery/runtime_discovery.hpp" #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/hybrid_discovery.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/hybrid_discovery.hpp index c3521092b..5009c1dc8 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/hybrid_discovery.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/hybrid_discovery.hpp @@ -14,8 +14,8 @@ #pragma once -#include "ros2_medkit_gateway/discovery/discovery_layer.hpp" -#include "ros2_medkit_gateway/discovery/discovery_strategy.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_strategy.hpp" #include "ros2_medkit_gateway/discovery/merge_pipeline.hpp" #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/introspection_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/introspection_provider.hpp index 9bc41f10c..5d822dec5 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/introspection_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/introspection_provider.hpp @@ -14,74 +14,6 @@ #pragma once -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" - -#include -#include -#include -#include - -namespace ros2_medkit_gateway { - -/** - * @brief Snapshot of current discovery state, passed to introspection providers - */ -struct IntrospectionInput { - std::vector areas; - std::vector components; - std::vector apps; - std::vector functions; -}; - -/** - * @brief New entity definitions an introspection provider can introduce - */ -struct NewEntities { - std::vector areas; - std::vector components; - std::vector apps; - std::vector functions; -}; - -/** - * @brief Result returned by IntrospectionProvider::introspect() - */ -struct IntrospectionResult { - /// Per-entity metadata for plugin-internal use. Key = entity_id. - /// Plugins serve this data as SOVD vendor extension resources - /// via get_routes() and register_capability(). - std::unordered_map metadata; - - /// New entities discovered by this provider - NewEntities new_entities; -}; - -/** - * @brief Provider interface for platform-specific introspection - * - * Implementations enrich discovered entities with runtime metadata - * and can discover new entities from non-ROS sources. - * - * @see GatewayPlugin for the base class - * @see PluginManager for orchestration - */ -class IntrospectionProvider { - public: - virtual ~IntrospectionProvider() = default; - - /** - * @brief Core introspection method - * - * Called during each discovery cycle by the merge pipeline. - * Input contains entities from all higher-priority layers (manifest + runtime). - * - * @param input Snapshot of entities discovered by previous layers - * @return Metadata enrichments and new entities - */ - virtual IntrospectionResult introspect(const IntrospectionInput & input) = 0; -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/providers/. Remove once +// all downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/plugin_layer.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/plugin_layer.hpp index b51b8d7db..9daf028a0 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/plugin_layer.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/layers/plugin_layer.hpp @@ -14,8 +14,8 @@ #pragma once -#include "ros2_medkit_gateway/discovery/discovery_layer.hpp" -#include "ros2_medkit_gateway/discovery/introspection_provider.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_layer.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_manager.hpp index 91e8379ba..e74f58fb6 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/manifest_manager.hpp @@ -14,10 +14,10 @@ #pragma once -#include "ros2_medkit_gateway/discovery/manifest/manifest.hpp" -#include "ros2_medkit_gateway/discovery/manifest/manifest_parser.hpp" -#include "ros2_medkit_gateway/discovery/manifest/manifest_validator.hpp" -#include "ros2_medkit_gateway/discovery/manifest/validation_error.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest_parser.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest_validator.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/validation_error.hpp" #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/runtime_linker.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/runtime_linker.hpp index 1a9ed2a4e..b10644deb 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/runtime_linker.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/manifest/runtime_linker.hpp @@ -14,8 +14,8 @@ #pragma once -#include "ros2_medkit_gateway/discovery/manifest/manifest.hpp" -#include "ros2_medkit_gateway/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/merge_pipeline.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/merge_pipeline.hpp index 229ba7d92..2a880c767 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/merge_pipeline.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/merge_pipeline.hpp @@ -14,10 +14,10 @@ #pragma once -#include "ros2_medkit_gateway/discovery/discovery_layer.hpp" -#include "ros2_medkit_gateway/discovery/manifest/manifest.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest.hpp" +#include "ros2_medkit_gateway/core/discovery/merge_types.hpp" #include "ros2_medkit_gateway/discovery/manifest/runtime_linker.hpp" -#include "ros2_medkit_gateway/discovery/merge_types.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/app.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/app.hpp index 151b72c1a..37631d2fa 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/app.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/app.hpp @@ -14,132 +14,6 @@ #pragma once -#include "ros2_medkit_gateway/discovery/models/common.hpp" - -#include -#include -#include -#include - -namespace ros2_medkit_gateway { - -using json = nlohmann::json; - -/** - * @brief SOVD App entity - represents a software application - * - * In the ROS 2 context, an App typically corresponds to a ROS node. - * Apps are located on Components and can depend on other Apps. - * - * Apps can be: - * - Manifest-defined: Declared in YAML manifest with ROS binding - * - Runtime-discovered: Automatically created from ROS nodes (future) - */ -struct App { - // === Required fields === - std::string id; ///< Unique identifier - std::string name; ///< Human-readable name - - // === Optional SOVD fields === - std::string translation_id; ///< For i18n support - std::string description; ///< Detailed description - std::vector tags; ///< Tags for filtering - - // === Relationships === - std::string component_id; ///< is-located-on relationship - std::vector depends_on; ///< depends-on relationship (App IDs) - - // === ROS binding (for manifest) === - /** - * @brief ROS 2 binding configuration for manifest-defined apps - * - * Specifies how to bind this App to a ROS 2 node at runtime. - */ - struct RosBinding { - std::string node_name; ///< ROS node name to bind to - std::string namespace_pattern; ///< Namespace (can be "*" for wildcard) - std::string topic_namespace; ///< Alternative: bind by topic prefix - - bool is_empty() const { - return node_name.empty() && topic_namespace.empty(); - } - - json to_json() const { - json j; - if (!node_name.empty()) { - j["nodeName"] = node_name; - if (!namespace_pattern.empty()) { - j["namespace"] = namespace_pattern; - } - } - if (!topic_namespace.empty()) { - j["topicNamespace"] = topic_namespace; - } - return j; - } - }; - std::optional ros_binding; - - // === Runtime state (populated after linking) === - std::optional bound_fqn; ///< Bound ROS node FQN - bool is_online{false}; ///< Whether the bound node is running - bool external{false}; ///< True if not a ROS node - - /// Get effective FQN: bound_fqn if available, otherwise derived from ros_binding. - /// Returns empty string if neither is available. Used by handlers and samplers - /// to resolve the ROS node FQN in manifest_only mode where runtime linking - /// doesn't set bound_fqn. - /// @note namespace_pattern must be empty or an exact namespace path (e.g. "/perception"). - /// Glob patterns like "**" or "prefix*" are not supported and will produce empty FQN. - std::string effective_fqn() const { - if (bound_fqn.has_value() && !bound_fqn->empty()) { - return *bound_fqn; - } - if (ros_binding.has_value() && !ros_binding->node_name.empty()) { - const auto & ns = ros_binding->namespace_pattern; - // Wildcard or glob patterns cannot produce valid FQNs - if (ns.find('*') != std::string::npos) { - return ""; - } - if (ns.empty()) { - return "/" + ros_binding->node_name; - } - if (ns.back() != '/') { - return ns + "/" + ros_binding->node_name; - } - return ns + ros_binding->node_name; - } - return ""; - } - - // === Resources (populated from bound node) === - ComponentTopics topics; - std::vector services; - std::vector actions; - - // === Discovery metadata === - std::string source = "manifest"; ///< "manifest" or "runtime" - std::string original_id; ///< Pre-rename ID when collision-prefixed by aggregation - std::vector contributors; ///< Aggregation provenance: "local" and/or "peer:" - - // === Serialization methods === - - /** - * @brief Serialize to full JSON representation - */ - json to_json() const; - - /** - * @brief Create SOVD EntityReference format - * @param base_url Base URL for href (e.g., "/api/v1") - */ - json to_entity_reference(const std::string & base_url) const; - - /** - * @brief Create SOVD Entity Capabilities format - * @param base_url Base URL for capability URIs - */ - json to_capabilities(const std::string & base_url) const; -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/area.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/area.hpp index 78c14ee6a..41441b956 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/area.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/area.hpp @@ -14,119 +14,6 @@ #pragma once -#include "ros2_medkit_gateway/discovery/models/common.hpp" - -#include -#include -#include - -namespace ros2_medkit_gateway { - -using json = nlohmann::json; - -/** - * @brief SOVD Area entity - represents a logical grouping (ROS 2 namespace) - * - * Areas are derived from ROS 2 namespaces or defined in manifests. - * They provide a hierarchical organization of components. - */ -struct Area { - std::string id; ///< Unique identifier (e.g., "powertrain") - std::string name; ///< Human-readable name (e.g., "Powertrain System") - std::string namespace_path; ///< ROS 2 namespace path (e.g., "/powertrain") - std::string type = "Area"; ///< Entity type (always "Area") - std::string translation_id; ///< Internationalization key - std::string description; ///< Human-readable description - std::vector tags; ///< Tags for filtering - std::string parent_area_id; ///< Parent area ID for sub-areas - std::string source; ///< Origin of this area (e.g., "manifest", "heuristic") - std::vector contributors; ///< Aggregation provenance: "local" and/or "peer:" - - /** - * @brief Convert to JSON representation - * @return JSON object with area data - * - * SOVD EntityReference fields: id, name, href, translation_id, tags - * ROS 2 extensions in x-medkit: namespace, type, description, parentAreaId - */ - json to_json() const { - // Base fields - json j = {{"id", id}}; - - if (!name.empty()) { - j["name"] = name; - } - if (!translation_id.empty()) { - j["translationId"] = translation_id; - } - if (!tags.empty()) { - j["tags"] = tags; - } - - // ROS 2 extensions in x-medkit (SOVD vendor extension) - json x_medkit = {{"entityType", type}, {"namespace", namespace_path}}; - if (!description.empty()) { - x_medkit["description"] = description; - } - if (!parent_area_id.empty()) { - x_medkit["parentAreaId"] = parent_area_id; - } - if (!source.empty()) { - x_medkit["source"] = source; - } - if (!contributors.empty()) { - x_medkit["contributors"] = sorted_contributors(contributors); - } - j["x-medkit"] = x_medkit; - - return j; - } - - /** - * @brief Create SOVD EntityReference format (strictly compliant) - * @param base_url Base URL for self links - * @return JSON object in EntityReference format: id, name, href, [translationId, tags] - */ - json to_entity_reference(const std::string & base_url) const { - json j = {{"id", id}, {"href", base_url + "/areas/" + id}}; - if (!name.empty()) { - j["name"] = name; - } - if (!translation_id.empty()) { - j["translationId"] = translation_id; - } - if (!tags.empty()) { - j["tags"] = tags; - } - return j; - } - - /** - * @brief Create SOVD Entity Capabilities format (strictly compliant) - * @param base_url Base URL for capability links - * @return JSON object listing available sub-resources - */ - json to_capabilities(const std::string & base_url) const { - std::string area_url = base_url + "/areas/" + id; - - // Capabilities response - json j = {{"id", id}}; - if (!name.empty()) { - j["name"] = name; - } - if (!translation_id.empty()) { - j["translationId"] = translation_id; - } - - // Capabilities as URI references (SOVD compliant) - j["subareas"] = area_url + "/subareas"; - j["related-components"] = area_url + "/related-components"; - - // x-medkit extension for ROS 2 specific info - j["x-medkit"] = {{"entityType", type}, {"namespace", namespace_path}}; - - return j; - } -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/component.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/component.hpp index 387554e3b..bd84074d1 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/component.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/component.hpp @@ -14,162 +14,6 @@ #pragma once -#include "ros2_medkit_gateway/discovery/models/common.hpp" - -#include -#include -#include -#include - -namespace ros2_medkit_gateway { - -using json = nlohmann::json; - -/** - * @brief SOVD Component entity - represents a software/hardware component (ROS 2 node) - * - * Components are derived from ROS 2 nodes or defined in manifests. - * They expose operations (services/actions), data (topics), and configurations (parameters). - */ -struct Component { - std::string id; ///< Unique identifier (node name) - std::string name; ///< Human-readable name - std::string namespace_path; ///< ROS 2 namespace path - std::string fqn; ///< Fully qualified name (namespace + id) - std::string type = "Component"; ///< Entity type (always "Component") - std::string area; ///< Parent area ID - std::string source = "node"; ///< Discovery source: "node", "topic", or "manifest" - std::string translation_id; ///< Internationalization key - std::string description; ///< Human-readable description - std::string variant; ///< Hardware variant identifier - std::vector tags; ///< Tags for filtering - std::string parent_component_id; ///< Parent component ID for sub-components - std::vector depends_on; ///< Component IDs this component depends on - std::vector contributors; ///< Aggregation provenance: "local" and/or "peer:" - std::vector services; ///< Services exposed by this component - std::vector actions; ///< Actions exposed by this component - ComponentTopics topics; ///< Topics this component publishes/subscribes - std::optional host_metadata; ///< Host system metadata (for runtime default component) - - /** - * @brief Convert to JSON representation - * @return JSON object with component data - * - * SOVD EntityReference fields: id, name, href, translation_id, tags - * ROS 2 extensions in x-medkit: namespace, fqn, entityType, area, source, variant, etc. - */ - json to_json() const { - // Base fields - json j = {{"id", id}}; - - if (!name.empty()) { - j["name"] = name; - } - if (!translation_id.empty()) { - j["translationId"] = translation_id; - } - if (!tags.empty()) { - j["tags"] = tags; - } - - // ROS 2 extensions in x-medkit (SOVD vendor extension) - json x_medkit = { - {"entityType", type}, {"namespace", namespace_path}, {"fqn", fqn}, {"area", area}, {"source", source}}; - if (!description.empty()) { - x_medkit["description"] = description; - } - if (!variant.empty()) { - x_medkit["variant"] = variant; - } - if (!parent_component_id.empty()) { - x_medkit["parentComponentId"] = parent_component_id; - } - if (!depends_on.empty()) { - x_medkit["dependsOn"] = depends_on; - } - if (!contributors.empty()) { - x_medkit["contributors"] = sorted_contributors(contributors); - } - x_medkit["topics"] = topics.to_json(); - if (host_metadata.has_value()) { - x_medkit["host"] = host_metadata.value(); - } - j["x-medkit"] = x_medkit; - - // Add operations array combining services and actions - json operations = json::array(); - for (const auto & svc : services) { - operations.push_back(svc.to_json()); - } - for (const auto & act : actions) { - operations.push_back(act.to_json()); - } - if (!operations.empty()) { - j["operations"] = operations; - } - - return j; - } - - /** - * @brief Create SOVD EntityReference format (strictly compliant) - * @param base_url Base URL for self links - * @return JSON object in EntityReference format: id, name, href, [translationId, tags] - */ - json to_entity_reference(const std::string & base_url) const { - json j = {{"id", id}, {"href", base_url + "/components/" + id}}; - if (!name.empty()) { - j["name"] = name; - } - if (!translation_id.empty()) { - j["translationId"] = translation_id; - } - if (!tags.empty()) { - j["tags"] = tags; - } - return j; - } - - /** - * @brief Create SOVD Entity Capabilities format (strictly compliant) - * @param base_url Base URL for capability links - * @return JSON object listing available sub-resources - */ - json to_capabilities(const std::string & base_url) const { - std::string component_url = base_url + "/components/" + id; - - // Capabilities response - json j = {{"id", id}}; - if (!name.empty()) { - j["name"] = name; - } - if (!translation_id.empty()) { - j["translationId"] = translation_id; - } - - // Capabilities as URI references (SOVD compliant) - if (!topics.publishes.empty() || !topics.subscribes.empty()) { - j["data"] = component_url + "/data"; - } - if (!services.empty() || !actions.empty()) { - j["operations"] = component_url + "/operations"; - } - // ROS 2 nodes always have parameters - if (source == "node") { - j["configurations"] = component_url + "/configurations"; - } - j["faults"] = component_url + "/faults"; - j["subcomponents"] = component_url + "/subcomponents"; - j["related-apps"] = component_url + "/related-apps"; - if (!depends_on.empty()) { - j["depends-on"] = component_url + "/depends-on"; - } - - // x-medkit extension for ROS 2 specific info - j["x-medkit"] = {{"entityType", type}, {"namespace", namespace_path}, {"fqn", fqn}, {"source", source}}; - - return j; - } -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/function.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/function.hpp index 030e85edb..15e3f6ebc 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/function.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/models/function.hpp @@ -14,61 +14,6 @@ #pragma once -#include "ros2_medkit_gateway/discovery/models/common.hpp" - -#include -#include -#include - -namespace ros2_medkit_gateway { - -using json = nlohmann::json; - -/** - * @brief SOVD Function entity - represents a functional group - * - * Functions are higher-level abstractions that group Apps and/or Components - * representing a complete capability (e.g., "Autonomous Navigation"). - * - * Functions can be manifest-defined or created at runtime from namespace grouping. - * They aggregate data, operations, and faults from their hosted entities. - */ -struct Function { - // === Required fields === - std::string id; ///< Unique identifier - std::string name; ///< Human-readable name - - // === Optional SOVD fields === - std::string translation_id; ///< For i18n support - std::string description; ///< Detailed description - std::vector tags; ///< Tags for filtering - - // === Relationships === - std::vector hosts; ///< App or Component IDs this function hosts - std::vector depends_on; ///< depends-on relationship (Function IDs) - - // === Discovery metadata === - std::string source = "manifest"; ///< Discovery source: manifest or runtime - std::vector contributors; ///< Aggregation provenance: "local" and/or "peer:" - - // === Serialization methods === - - /** - * @brief Serialize to full JSON representation - */ - json to_json() const; - - /** - * @brief Create SOVD EntityReference format - * @param base_url Base URL for href (e.g., "/api/v1") - */ - json to_entity_reference(const std::string & base_url) const; - - /** - * @brief Create SOVD Entity Capabilities format - * @param base_url Base URL for capability URIs - */ - json to_capabilities(const std::string & base_url) const; -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/runtime_discovery.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/runtime_discovery.hpp index 89814ac6a..c25ce9c6b 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/runtime_discovery.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/discovery/runtime_discovery.hpp @@ -14,14 +14,14 @@ #pragma once -#include "ros2_medkit_gateway/data/topic_data_provider.hpp" -#include "ros2_medkit_gateway/discovery/discovery_strategy.hpp" -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/common.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" -#include "ros2_medkit_gateway/type_introspection.hpp" +#include "ros2_medkit_gateway/core/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_strategy.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/common.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/type_introspection.hpp" #include #include diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/gateway_node.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/gateway_node.hpp index 1411db2e1..e07b50fdf 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/gateway_node.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/gateway_node.hpp @@ -21,36 +21,36 @@ #include #include "ros2_medkit_gateway/aggregation/aggregation_manager.hpp" -#include "ros2_medkit_gateway/aggregation/mdns_discovery.hpp" -#include "ros2_medkit_gateway/auth/auth_config.hpp" -#include "ros2_medkit_gateway/bulk_data_store.hpp" -#include "ros2_medkit_gateway/condition_evaluator.hpp" -#include "ros2_medkit_gateway/config.hpp" #include "ros2_medkit_gateway/configuration_manager.hpp" -#include "ros2_medkit_gateway/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/aggregation/mdns_discovery.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/condition_evaluator.hpp" +#include "ros2_medkit_gateway/core/config.hpp" +#include "ros2_medkit_gateway/core/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/default_script_provider.hpp" +#include "ros2_medkit_gateway/core/http/rate_limiter.hpp" +#include "ros2_medkit_gateway/core/http/rest_server.hpp" +#include "ros2_medkit_gateway/core/http/sse_client_tracker.hpp" +#include "ros2_medkit_gateway/core/managers/bulk_data_store.hpp" +#include "ros2_medkit_gateway/core/managers/lock_manager.hpp" +#include "ros2_medkit_gateway/core/managers/script_manager.hpp" +#include "ros2_medkit_gateway/core/managers/subscription_manager.hpp" +#include "ros2_medkit_gateway/core/managers/trigger_manager.hpp" +#include "ros2_medkit_gateway/core/managers/update_manager.hpp" +#include "ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp" +#include "ros2_medkit_gateway/core/plugins/entity_change_scope.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/resource_sampler.hpp" +#include "ros2_medkit_gateway/core/subscription_transport.hpp" +#include "ros2_medkit_gateway/core/trigger_store.hpp" #include "ros2_medkit_gateway/data_access_manager.hpp" -#include "ros2_medkit_gateway/default_script_provider.hpp" #include "ros2_medkit_gateway/discovery/discovery_manager.hpp" #include "ros2_medkit_gateway/fault_manager.hpp" -#include "ros2_medkit_gateway/http/rate_limiter.hpp" -#include "ros2_medkit_gateway/http/rest_server.hpp" -#include "ros2_medkit_gateway/http/sse_client_tracker.hpp" -#include "ros2_medkit_gateway/lock_manager.hpp" #include "ros2_medkit_gateway/log_manager.hpp" -#include "ros2_medkit_gateway/models/thread_safe_entity_cache.hpp" #include "ros2_medkit_gateway/operation_manager.hpp" -#include "ros2_medkit_gateway/plugins/entity_change_scope.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" -#include "ros2_medkit_gateway/resource_sampler.hpp" -#include "ros2_medkit_gateway/script_manager.hpp" -#include "ros2_medkit_gateway/subscription_manager.hpp" -#include "ros2_medkit_gateway/subscription_transport.hpp" #include "ros2_medkit_gateway/trigger_fault_subscriber.hpp" -#include "ros2_medkit_gateway/trigger_manager.hpp" -#include "ros2_medkit_gateway/trigger_store.hpp" #include "ros2_medkit_gateway/trigger_topic_subscriber.hpp" -#include "ros2_medkit_gateway/updates/update_manager.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/error_codes.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/error_codes.hpp index 34b347410..272097e63 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/error_codes.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/error_codes.hpp @@ -1,4 +1,4 @@ -// Copyright 2025 bburda +// Copyright 2026 bburda // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,151 +14,6 @@ #pragma once -#include - -namespace ros2_medkit_gateway { - -/** - * @brief SOVD Standard Error Codes - * - * These error codes follow the SOVD GenericError schema defined in - * sovd-openapi-spec/commons/errors.yaml. They should be used in all - * error responses to ensure compliance with the SOVD specification. - */ - -/// Invalid request format or missing required parameters -constexpr const char * ERR_INVALID_REQUEST = "invalid-request"; - -/// Entity (component, app, area, function) not found -constexpr const char * ERR_ENTITY_NOT_FOUND = "entity-not-found"; - -/// Resource (operation, configuration, data, fault) not found -constexpr const char * ERR_RESOURCE_NOT_FOUND = "resource-not-found"; - -/// Operation not found on entity -constexpr const char * ERR_OPERATION_NOT_FOUND = "operation-not-found"; - -/// Invalid parameter value or type -constexpr const char * ERR_INVALID_PARAMETER = "invalid-parameter"; - -/// Service temporarily unavailable -constexpr const char * ERR_SERVICE_UNAVAILABLE = "service-unavailable"; - -/// Internal server error -constexpr const char * ERR_INTERNAL_ERROR = "internal-error"; - -/// Collection not supported on entity type -constexpr const char * ERR_COLLECTION_NOT_SUPPORTED = "collection-not-supported"; - -/// Payload too large (used for file upload size limits) -constexpr const char * ERR_PAYLOAD_TOO_LARGE = "payload-too-large"; - -/// Feature not implemented (SOVD 501 Not Implemented) -constexpr const char * ERR_NOT_IMPLEMENTED = "not-implemented"; - -/// Authentication required -constexpr const char * ERR_UNAUTHORIZED = "unauthorized"; - -/// Access denied / insufficient permissions -constexpr const char * ERR_FORBIDDEN = "forbidden"; - -/// Rate limit exceeded (429 Too Many Requests) -constexpr const char * ERR_RATE_LIMIT_EXCEEDED = "rate-limit-exceeded"; - -/// Generic vendor-specific error (used with vendor_code field) -constexpr const char * ERR_VENDOR_ERROR = "vendor-error"; - -/** - * @brief ros2_medkit Vendor Error Codes (x-medkit-*) - * - * These are ros2_medkit-specific error codes that provide detailed - * information about ROS 2-specific failures. When used, the error - * response should include: - * - error_code: "vendor-error" - * - vendor_code: one of these x-medkit-* codes - */ - -/// ROS 2 service call timed out or service unavailable -constexpr const char * ERR_X_MEDKIT_ROS2_SERVICE_UNAVAILABLE = "x-medkit-ros2-service-unavailable"; - -/// ROS 2 action goal was rejected -constexpr const char * ERR_X_MEDKIT_ROS2_ACTION_REJECTED = "x-medkit-ros2-action-rejected"; - -/// ROS 2 parameter is read-only and cannot be modified -constexpr const char * ERR_X_MEDKIT_ROS2_PARAMETER_READ_ONLY = "x-medkit-ros2-parameter-read-only"; - -/// Dynamic type introspection failed for ROS 2 message -constexpr const char * ERR_X_MEDKIT_ROS2_TYPE_INTROSPECTION_FAILED = "x-medkit-ros2-type-introspection-failed"; - -/// ROS 2 node not available or not responding -constexpr const char * ERR_X_MEDKIT_ROS2_NODE_UNAVAILABLE = "x-medkit-ros2-node-unavailable"; - -/// ROS 2 topic not available -constexpr const char * ERR_X_MEDKIT_ROS2_TOPIC_UNAVAILABLE = "x-medkit-ros2-topic-unavailable"; - -/// ROS 2 action server not available -constexpr const char * ERR_X_MEDKIT_ROS2_ACTION_UNAVAILABLE = "x-medkit-ros2-action-unavailable"; - -/// Gateway is shutting down; request cannot be served -constexpr const char * ERR_X_MEDKIT_GATEWAY_SHUTDOWN = "x-medkit-gateway-shutdown"; - -/// Subscription creation in Ros2SubscriptionExecutor failed (rcl-level error) -constexpr const char * ERR_X_MEDKIT_SUBSCRIBE_FAILED = "x-medkit-subscribe-failed"; - -/// Concurrent cold-wait pool saturation; retry with backoff -constexpr const char * ERR_X_MEDKIT_COLD_WAIT_CAP_EXCEEDED = "x-medkit-cold-wait-cap-exceeded"; - -/// Software update package not found -constexpr const char * ERR_X_MEDKIT_UPDATE_NOT_FOUND = "x-medkit-update-not-found"; - -/// Duplicate update package ID on registration -constexpr const char * ERR_X_MEDKIT_UPDATE_ALREADY_EXISTS = "x-medkit-update-already-exists"; - -/// Cannot modify/delete update while operation is in progress -constexpr const char * ERR_X_MEDKIT_UPDATE_IN_PROGRESS = "x-medkit-update-in-progress"; - -/// Execute called before prepare completed -constexpr const char * ERR_X_MEDKIT_UPDATE_NOT_PREPARED = "x-medkit-update-not-prepared"; - -/// Automated mode not supported for this package -constexpr const char * ERR_X_MEDKIT_UPDATE_NOT_AUTOMATED = "x-medkit-update-not-automated"; - -/// Vendor-specific: invalid resource URI format for subscriptions -constexpr const char * ERR_X_MEDKIT_INVALID_RESOURCE_URI = "x-medkit-invalid-resource-uri"; - -/// Vendor-specific: collection not supported for entity type -constexpr const char * ERR_X_MEDKIT_COLLECTION_NOT_SUPPORTED = "x-medkit-collection-not-supported"; - -/// Vendor-specific: no data provider registered for collection -constexpr const char * ERR_X_MEDKIT_COLLECTION_NOT_AVAILABLE = "x-medkit-collection-not-available"; - -/// Vendor-specific: resource URI entity doesn't match route entity -constexpr const char * ERR_X_MEDKIT_ENTITY_MISMATCH = "x-medkit-entity-mismatch"; - -/// Vendor-specific: unsupported subscription protocol -constexpr const char * ERR_X_MEDKIT_UNSUPPORTED_PROTOCOL = "x-medkit-unsupported-protocol"; - -/// SOVD standard: client's lock was broken by another client (409) -constexpr const char * ERR_LOCK_BROKEN = "lock-broken"; - -// Script error codes (vendor-specific only; generic cases use ERR_RESOURCE_NOT_FOUND / ERR_INVALID_PARAMETER) -constexpr const char * ERR_SCRIPT_ALREADY_EXISTS = "x-medkit-script-already-exists"; -constexpr const char * ERR_SCRIPT_MANAGED = "x-medkit-managed-script"; -constexpr const char * ERR_SCRIPT_RUNNING = "x-medkit-script-running"; -constexpr const char * ERR_SCRIPT_NOT_RUNNING = "x-medkit-script-not-running"; -constexpr const char * ERR_SCRIPT_CONCURRENCY_LIMIT = "x-medkit-concurrency-limit"; -constexpr const char * ERR_SCRIPT_FILE_TOO_LARGE = "x-medkit-script-too-large"; - -/// Plugin provider returned an error (used for DataProvider/OperationProvider/FaultProvider errors) -constexpr const char * ERR_PLUGIN_ERROR = "x-medkit-plugin-error"; - -/** - * @brief Check if an error code is a vendor-specific code - * @param error_code Error code to check - * @return true if code starts with "x-medkit-" - */ -inline bool is_vendor_error_code(const std::string & error_code) { - return error_code.rfind("x-medkit-", 0) == 0; -} - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/http/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/http/error_codes.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/cyclic_subscription_handlers.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/cyclic_subscription_handlers.hpp index 3611502d6..d677b0cbd 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/cyclic_subscription_handlers.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/cyclic_subscription_handlers.hpp @@ -19,10 +19,10 @@ #include #include +#include "ros2_medkit_gateway/core/managers/subscription_manager.hpp" +#include "ros2_medkit_gateway/core/resource_sampler.hpp" +#include "ros2_medkit_gateway/core/subscription_transport.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/resource_sampler.hpp" -#include "ros2_medkit_gateway/subscription_manager.hpp" -#include "ros2_medkit_gateway/subscription_transport.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/handler_context.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/handler_context.hpp index 987d0717f..9b581e4ec 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/handler_context.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/handler_context.hpp @@ -25,13 +25,13 @@ #include #include -#include "ros2_medkit_gateway/auth/auth_config.hpp" -#include "ros2_medkit_gateway/auth/auth_manager.hpp" -#include "ros2_medkit_gateway/config.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/models/entity_capabilities.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_manager.hpp" +#include "ros2_medkit_gateway/core/config.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/models/entity_capabilities.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/sse_fault_handler.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/sse_fault_handler.hpp index 33ab0f71c..5b7298a92 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/sse_fault_handler.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/handlers/sse_fault_handler.hpp @@ -23,8 +23,8 @@ #include #include "rclcpp/rclcpp.hpp" +#include "ros2_medkit_gateway/core/http/sse_client_tracker.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/http/sse_client_tracker.hpp" #include "ros2_medkit_msgs/msg/fault_event.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/log_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/log_manager.hpp index 4c4ae6973..a23610098 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/log_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/log_manager.hpp @@ -27,8 +27,8 @@ #include #include -#include "ros2_medkit_gateway/log_types.hpp" -#include "ros2_medkit_gateway/logs/log_provider.hpp" +#include "ros2_medkit_gateway/core/log_types.hpp" +#include "ros2_medkit_gateway/core/providers/log_provider.hpp" namespace ros2_medkit_gateway { @@ -78,6 +78,11 @@ class LogManager { ~LogManager(); + LogManager(const LogManager &) = delete; + LogManager & operator=(const LogManager &) = delete; + LogManager(LogManager &&) = delete; + LogManager & operator=(LogManager &&) = delete; + /** * @brief Query log entries for a set of node FQNs * diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/operation_manager.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/operation_manager.hpp index 0ef598d73..7e366368c 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/operation_manager.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/operation_manager.hpp @@ -29,8 +29,8 @@ #include #include "ros2_medkit_gateway/compat/generic_client_compat.hpp" +#include "ros2_medkit_gateway/core/discovery/models/common.hpp" #include "ros2_medkit_gateway/discovery/discovery_manager.hpp" -#include "ros2_medkit_gateway/discovery/models/common.hpp" #include "ros2_medkit_serialization/json_serializer.hpp" #include "ros2_medkit_serialization/service_action_types.hpp" @@ -104,6 +104,11 @@ class OperationManager { ~OperationManager(); + OperationManager(const OperationManager &) = delete; + OperationManager & operator=(const OperationManager &) = delete; + OperationManager(OperationManager &&) = delete; + OperationManager & operator=(OperationManager &&) = delete; + /// Explicitly release subscriptions, clients, and tracked goals. /// Call while executor is still running to allow safe callback cleanup. /// Called automatically by destructor, but GatewayNode calls it earlier diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/gateway_plugin.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/gateway_plugin.hpp index 229d57c72..55ad1841a 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/gateway_plugin.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/gateway_plugin.hpp @@ -14,124 +14,6 @@ #pragma once -#include "ros2_medkit_gateway/plugins/plugin_http_types.hpp" -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" - -#include -#include -#include -#include - -namespace ros2_medkit_gateway { - -class PluginContext; - -/** - * @brief Base class for all gateway plugins - * - * Plugins are loaded as shared libraries (.so) via dlopen/dlsym. - * Each .so must export two extern "C" functions: - * int plugin_api_version(); // must return PLUGIN_API_VERSION - * GatewayPlugin* create_plugin(); // factory - * - * Plugins implement this base class plus one or more provider interfaces - * (UpdateProvider, IntrospectionProvider) via multiple inheritance. - * - * @see PluginManager for loading and lifecycle orchestration - * @see UpdateProvider, IntrospectionProvider for typed interfaces - */ -class GatewayPlugin { - public: - /// Describes a single REST route registered by a plugin - struct PluginRoute { - std::string method; ///< HTTP method ("GET", "POST", "PUT", "DELETE") - std::string pattern; ///< Regex pattern relative to api_prefix - std::function handler; - }; - - virtual ~GatewayPlugin() = default; - - /** - * @brief Unique name for this plugin - * @return Plugin name (e.g., "systemd", "procfs", "mender_ota") - */ - virtual std::string name() const = 0; - - /** - * @brief Configure the plugin - * - * Called once after loading with per-plugin config from YAML. - * - * @param config JSON configuration object - */ - virtual void configure(const nlohmann::json & config) = 0; - - /** - * @brief Receive gateway context - * - * Called after configure(). Provides access to the ROS 2 node, - * entity cache, fault data, and HTTP handler utilities. - * Store the reference if needed during runtime. - * - * @param context Gateway plugin context (outlives this plugin) - */ - virtual void set_context(PluginContext & /*context*/) { - } - - /** - * @brief Return custom REST routes for this plugin - * - * Called once during REST server setup. The gateway registers the returned - * routes on the HTTP server, wrapping PluginRequest/PluginResponse around - * the underlying library types. - * - * @return Routes to register (method, pattern, handler) - */ - virtual std::vector get_routes() { - return {}; - } - - /** - * @brief Shutdown hook for cleanup - * - * Called before the plugin is destroyed. Use for releasing - * resources, closing connections, etc. - */ - virtual void shutdown() { - } - - protected: - /// Log an informational message (routed to gateway's ROS 2 logger) - void log_info(const std::string & msg) const { - if (log_fn_) { - log_fn_(PluginLogLevel::kInfo, msg); - } - } - - /// Log a warning message - void log_warn(const std::string & msg) const { - if (log_fn_) { - log_fn_(PluginLogLevel::kWarn, msg); - } - } - - /// Log an error message - void log_error(const std::string & msg) const { - if (log_fn_) { - log_fn_(PluginLogLevel::kError, msg); - } - } - - private: - friend class PluginManager; // Sets log_fn_ after construction - - /// Logging callback set by PluginManager. Routes to rclcpp::get_logger("plugin."). - std::function log_fn_; - - /// Called by PluginManager to wire up logging - void set_logger(std::function fn) { - log_fn_ = std::move(fn); - } -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_context.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_context.hpp index c53d2da15..6f2aea053 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_context.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_context.hpp @@ -14,269 +14,6 @@ #pragma once -#include "ros2_medkit_gateway/discovery/introspection_provider.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/lock_manager.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" -#include "ros2_medkit_gateway/plugins/entity_change_scope.hpp" -#include "ros2_medkit_gateway/plugins/plugin_http_types.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace rclcpp { -class Node; -} - -namespace ros2_medkit_gateway { - -class ResourceSamplerRegistry; - -// Forward declarations for trigger-related types -class ResourceChangeNotifier; -class ConditionRegistry; - -/** - * @brief Entity information exposed to plugins - */ -struct PluginEntityInfo { - SovdEntityType type{SovdEntityType::UNKNOWN}; - std::string id; - std::string namespace_path; ///< ROS 2 namespace (for component fault filtering) - std::string fqn; ///< Fully qualified ROS 2 node name -}; - -/** - * @brief Context interface providing plugins access to gateway data and utilities - * - * Passed to plugins during lifecycle via set_context(). Replaces the old set_node() - * by providing both ROS 2 node access and gateway-level abstractions. - * - * @note This interface is versioned alongside PLUGIN_API_VERSION. New methods may - * be added in future versions (entity data access, configuration queries, etc.). - * - * @par Thread Safety - * All methods are safe to call from any thread. Entity and fault queries use - * the gateway's thread-safe caches internally. - */ -class PluginContext { - public: - virtual ~PluginContext() = default; - - // ---- ROS 2 access (replaces set_node) ---- - - /// Get ROS 2 node pointer for subscriptions, service clients, etc. - virtual rclcpp::Node * node() const = 0; - - // ---- Entity access (read-only) ---- - - /// Look up an entity by ID. Returns nullopt if not found. - virtual std::optional get_entity(const std::string & id) const = 0; - - /// Get all Apps belonging to a Component (for aggregation endpoints) - virtual std::vector get_child_apps(const std::string & component_id) const = 0; - - // ---- Fault access ---- - - /// List faults for a given entity. Returns JSON array of fault objects. - /// Empty array if entity has no faults or fault manager is unavailable. - virtual nlohmann::json list_entity_faults(const std::string & entity_id) const = 0; - - // ---- HTTP handler utilities (for entity-scoped routes) ---- - - /** - * @brief Validate entity exists and matches route type, sending SOVD error if not - * - * Use this in get_routes() handlers to validate entity IDs from path params. - * On failure, an appropriate SOVD GenericError response is sent automatically. - * - * @param req Plugin request (extracts expected entity type from path) - * @param res Plugin response (error sent here on failure) - * @param entity_id Entity ID from path parameter (e.g., req.path_param(1)) - * @return Entity info if valid, nullopt if error was sent - */ - virtual std::optional validate_entity_for_route(const PluginRequest & req, PluginResponse & res, - const std::string & entity_id) const = 0; - - // ---- Capability registration ---- - - /** - * @brief Register a custom capability for all entities of a given type - * - * The capability will appear in the entity's capabilities array with an - * auto-generated href. For example, registering "x-medkit-traces" for - * SovdEntityType::APP produces: {"name": "x-medkit-traces", "href": "/api/v1/apps/{id}/x-medkit-traces"} - * - * The plugin must also return a matching route from get_routes(). - * - * @param entity_type Entity type to add the capability to - * @param capability_name Capability name (use x- prefix for vendor extensions) - */ - virtual void register_capability(SovdEntityType entity_type, const std::string & capability_name) = 0; - - /** - * @brief Register a custom capability for a specific entity - * - * Like register_capability(entity_type, name) but scoped to a single entity. - * - * @param entity_id Specific entity ID - * @param capability_name Capability name (use x- prefix for vendor extensions) - */ - virtual void register_entity_capability(const std::string & entity_id, const std::string & capability_name) = 0; - - // ---- Capability query (used by discovery handlers) ---- - - /// Get plugin-registered capabilities for an entity type - virtual std::vector get_type_capabilities(SovdEntityType entity_type) const = 0; - - /// Get plugin-registered capabilities for a specific entity - virtual std::vector get_entity_capabilities(const std::string & entity_id) const = 0; - - // ---- Locking ---- - - /** - * @brief Check if a lock blocks access to a collection on an entity. - * - * @param entity_id Entity to check - * @param client_id Client requesting access - * @param collection Resource collection being accessed (e.g. "configurations") - * @return LockAccessResult with allowed/denied status and details - */ - virtual LockAccessResult check_lock(const std::string & entity_id, const std::string & client_id, - const std::string & collection) const = 0; - - /** - * @brief Acquire a lock on an entity. - * - * @param entity_id Entity to lock - * @param client_id Client acquiring the lock - * @param scopes Optional lock scopes (empty = all collections) - * @param expiration_seconds Lock TTL in seconds - * @return LockInfo on success, LockError on failure - */ - virtual tl::expected acquire_lock(const std::string & entity_id, const std::string & client_id, - const std::vector & scopes, - int expiration_seconds) = 0; - - /** - * @brief Release a lock on an entity. - * - * @param entity_id Entity to unlock - * @param client_id Client releasing the lock - * @return void on success, LockError on failure - */ - virtual tl::expected release_lock(const std::string & entity_id, const std::string & client_id) = 0; - - // ---- Entity bulk access ---- - - /// Get a snapshot of all discovered entities (areas, components, apps, functions). - /// Returns an IntrospectionInput populated from the current entity cache. - virtual IntrospectionInput get_entity_snapshot() const { - return {}; - } - - // ---- All-faults access ---- - - /// List all faults across all entities. Returns JSON with "faults" array. - /// Empty object if fault manager is unavailable. - virtual nlohmann::json list_all_faults() const { - return nlohmann::json::object(); - } - - // ---- Resource sampler registration ---- - - /// Register a cyclic subscription sampler for a custom collection. - virtual void register_sampler( - const std::string & /*collection*/, - const std::function(const std::string &, const std::string &)> & - /*fn*/) { - } - - // ---- Trigger infrastructure access ---- - - /** - * @brief Get the ResourceChangeNotifier for publishing or subscribing to resource changes. - * - * Always returns a valid pointer - ResourceChangeNotifier is created unconditionally - * in GatewayNode regardless of trigger configuration. - */ - virtual ResourceChangeNotifier * get_resource_change_notifier() = 0; - - /** - * @brief Get the ConditionRegistry for registering custom trigger condition evaluators. - * - * Always returns a valid pointer - ConditionRegistry is created unconditionally - * in GatewayNode regardless of trigger configuration. - */ - virtual ConditionRegistry * get_condition_registry() = 0; - - // ---- Entity surface notifications (plugin API v7) ---- - - /** - * @brief Tell the gateway that this plugin has finished mutating entities. - * - * Call this AFTER any change that adds, removes, or restructures entities - * on disk or in the running runtime (deploying a new node under a manifest - * fragment, removing a previously-deployed app, renaming a component). - * The gateway responds by re-reading its manifest sources (including any - * configured fragments directory) and running a discovery pass for the - * affected scope. By the time this returns, subsequent `get_entity` and - * HTTP discovery endpoints reflect the new surface. - * - * @param scope Hint that lets the gateway limit the rediscovery work. - * `EntityChangeScope::full_refresh()` asks for a global pass. - * - * @par Thread safety - * Safe to call from any thread. The v7 reference implementation is - * SYNCHRONOUS: the caller's thread drives the full manifest reload + - * discovery refresh before the call returns, under an internal refresh - * mutex that also serializes the periodic refresh timer. As a result: - * * the call may block for seconds on large manifests / slow plugins; - * * plugins MUST NOT hold their own mutexes across this call if any - * of their own callbacks (introspect, data/operation/fault providers) - * could try to reacquire that mutex - doing so deadlocks; - * * calling this method from within your own `IntrospectionProvider:: - * introspect()` callback is detected and skipped with a warning log - * (see `GatewayNode::handle_entity_change_notification`). The design - * assumes introspect already runs inside a refresh pass, so a nested - * notification would be redundant. - * - * @par Backwards compatibility - * Default implementation is a no-op. Plugin source written against plugin - * API v6 compiles unchanged against v7 headers (source-compatible) - no - * code changes are required. The plugin loader compares the exported - * `plugin_api_version()` against the gateway's `PLUGIN_API_VERSION` with - * strict equality, so a plugin `.so` pre-compiled against v6 IS rejected; - * recompilation against v7 headers is required. - * - * @par Fragment file contract (when used with discovery.manifest.fragments_dir) - * Plugins that deploy / remove manifest fragments on disk before calling - * this method MUST publish the final content atomically. The gateway's - * fragment scanner reads each file on the caller's thread once the - * notification arrives; a partially-written fragment causes the reload - * to fail, which rolls back the entire manifest merge (see the design - * doc's "all-or-nothing fragment contract" section). The recommended - * pattern is: write to `fragments_dir/.tmp-.yaml`, `fsync`, then - * `rename()` (POSIX atomic within the same filesystem) to - * `fragments_dir/.yaml`. The rename is the commit point that makes - * the fragment visible to the next reload. - */ - virtual void notify_entities_changed(const EntityChangeScope & /*scope*/) { - } -}; - -// Forward declarations -class GatewayNode; -class FaultManager; - -/// Factory for creating the concrete gateway plugin context -std::unique_ptr make_gateway_plugin_context(GatewayNode * node, FaultManager * fault_manager, - ResourceSamplerRegistry * sampler_registry = nullptr); - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/plugins/plugin_context.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_http_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_http_types.hpp index 643e43d42..6c9e197a0 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_http_types.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_http_types.hpp @@ -14,56 +14,6 @@ #pragma once -#include -#include - -namespace ros2_medkit_gateway { - -/// Thin read-only wrapper over an HTTP request. -/// Hides the underlying HTTP library (currently cpp-httplib) from plugin code. -/// Constructed by the gateway per-request; plugins receive it by const reference. -class PluginRequest { - public: - /// Construct from opaque HTTP request pointer (gateway-internal). - explicit PluginRequest(const void * impl); - - /// Extract a path parameter by regex capture group index. - /// Index 0 is the full match; index 1 is the first capture group. - std::string path_param(size_t index) const; - - /// Get a request header value by name. Returns empty string if not present. - std::string header(const std::string & name) const; - - /// Full request path (e.g. "/api/v1/apps/my_app/data"). - const std::string & path() const; - - /// Request body (by reference - avoids copying large payloads). - const std::string & body() const; - - /// Get a query parameter value by name. Returns empty string if not present. - std::string query_param(const std::string & name) const; - - private: - const void * impl_; -}; - -/// Thin wrapper over an HTTP response. -/// Hides the underlying HTTP library from plugin code. -/// Constructed by the gateway per-request; plugins receive it by reference. -class PluginResponse { - public: - /// Construct from opaque HTTP response pointer (gateway-internal). - explicit PluginResponse(void * impl); - - /// Send a JSON success response (HTTP 200). - void send_json(const nlohmann::json & data); - - /// Send a SOVD-compliant error response. - void send_error(int status, const std::string & error_code, const std::string & message, - const nlohmann::json & parameters = {}); - - private: - void * impl_; -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/plugins/plugin_http_types.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_types.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_types.hpp index d4598fbb3..c08583bb5 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_types.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/plugins/plugin_types.hpp @@ -14,42 +14,6 @@ #pragma once -#include -#include - -/// Visibility macro for plugin extern "C" exports. -/// Ensures symbols are exported even with -fvisibility=hidden builds. -#ifdef _WIN32 -#define GATEWAY_PLUGIN_EXPORT __declspec(dllexport) -#else -#define GATEWAY_PLUGIN_EXPORT __attribute__((visibility("default"))) -#endif - -namespace ros2_medkit_gateway { - -/// Current plugin API version. Plugins must export this value from plugin_api_version(). -/// -/// Version history: -/// - v6: ScriptProvider, locking API, extended PluginContext (entity snapshot, -/// fault listing, sampler registration). -/// - v7: PluginContext::notify_entities_changed(EntityChangeScope) for plugins -/// that mutate the entity surface at runtime. Default implementation is -/// a no-op so plugin SOURCE written against v6 compiles unchanged -/// against v7 headers (source-compatible). Binary compatibility is not -/// provided - `plugin_loader` uses strict equality against this value, -/// so a pre-compiled v6 `.so` is rejected. Out-of-tree plugins must be -/// recompiled against v7 headers; in-tree plugins that `return -/// PLUGIN_API_VERSION` pick up the bump automatically. -constexpr int PLUGIN_API_VERSION = 7; - -/// Log severity levels for plugin logging callback -enum class PluginLogLevel { kInfo, kWarn, kError }; - -/// Configuration for a single plugin loaded from YAML -struct PluginConfig { - std::string name; ///< Plugin key from YAML (used for parameter namespace) - std::string path; ///< Path to .so file - nlohmann::json config; ///< Per-plugin configuration (passed to configure()) -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/data_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/data_provider.hpp index 179fc8be9..4edbd70f2 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/data_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/data_provider.hpp @@ -14,71 +14,6 @@ #pragma once -#include -#include -#include - -namespace ros2_medkit_gateway { - -enum class DataProviderError { - EntityNotFound, - ResourceNotFound, - ReadOnly, - WriteOnly, - TransportError, - Timeout, - InvalidValue, - Internal -}; - -struct DataProviderErrorInfo { - DataProviderError code; - std::string message; - int http_status{500}; ///< Suggested HTTP status code -}; - -/** - * @brief Provider interface for entity data resources - * - * Typed provider interface for plugins that serve SOVD data resources - * (GET /{entity_type}/{id}/data, GET /{entity_type}/{id}/data/{name}). - * Unlike LogProvider/ScriptProvider (singletons), multiple DataProvider - * plugins can coexist - each handles its own set of entities. - * - * Entity ownership is determined by IntrospectionProvider: entities - * created by a plugin's introspect() are routed to that plugin's - * DataProvider. - * - * @par Thread safety - * All methods may be called from multiple HTTP handler threads concurrently. - * Implementations must provide their own synchronization. - * - * @see GatewayPlugin for the base class all plugins must also implement - * @see OperationProvider for the operations counterpart - */ -class DataProvider { - public: - virtual ~DataProvider() = default; - - /// List available data resources for an entity - /// @param entity_id SOVD entity ID (e.g., "openbsw_demo_ecu") - /// @return JSON with {"items": [...]} array of data resource descriptors - virtual tl::expected list_data(const std::string & entity_id) = 0; - - /// Read a specific data resource - /// @param entity_id SOVD entity ID - /// @param resource_name Data resource name (e.g., "hardcoded_data") - /// @return JSON response body for the data resource - virtual tl::expected read_data(const std::string & entity_id, - const std::string & resource_name) = 0; - - /// Write a data resource value - /// @param entity_id SOVD entity ID - /// @param resource_name Data resource name - /// @param value JSON value to write - /// @return JSON response body confirming the write - virtual tl::expected - write_data(const std::string & entity_id, const std::string & resource_name, const nlohmann::json & value) = 0; -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/providers/data_provider.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/fault_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/fault_provider.hpp index e129e0038..551feb72a 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/fault_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/fault_provider.hpp @@ -14,58 +14,6 @@ #pragma once -#include -#include -#include - -namespace ros2_medkit_gateway { - -enum class FaultProviderError { EntityNotFound, FaultNotFound, TransportError, Timeout, Internal }; - -struct FaultProviderErrorInfo { - FaultProviderError code; - std::string message; - int http_status{500}; ///< Suggested HTTP status code -}; - -/** - * @brief Provider interface for entity fault/DTC resources - * - * Typed provider interface for plugins that serve SOVD faults - * (GET /{entity_type}/{id}/faults, GET /{entity_type}/{id}/faults/{code}). - * Per-entity routing like DataProvider. - * - * Plugins implementing this interface query their backend (e.g., UDS - * ReadDTCInformation 0x19) on demand and return faults in SOVD format. - * - * @par Thread safety - * All methods may be called concurrently. Implementations must synchronize. - * - * @see GatewayPlugin for the base class all plugins must also implement - * @see DataProvider for the data counterpart - */ -class FaultProvider { - public: - virtual ~FaultProvider() = default; - - /// List faults for an entity - /// @param entity_id SOVD entity ID - /// @return JSON with {"items": [...]} array of fault descriptors - virtual tl::expected list_faults(const std::string & entity_id) = 0; - - /// Get a specific fault with environment data - /// @param entity_id SOVD entity ID - /// @param fault_code Fault code (e.g., DTC identifier) - /// @return JSON response with fault detail + environment data - virtual tl::expected get_fault(const std::string & entity_id, - const std::string & fault_code) = 0; - - /// Clear a fault - /// @param entity_id SOVD entity ID - /// @param fault_code Fault code to clear - /// @return JSON response confirming the clear - virtual tl::expected clear_fault(const std::string & entity_id, - const std::string & fault_code) = 0; -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/providers/fault_provider.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/introspection_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/introspection_provider.hpp new file mode 100644 index 000000000..d9144dec2 --- /dev/null +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/introspection_provider.hpp @@ -0,0 +1,19 @@ +// Copyright 2026 bburda +// +// 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 + +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/operation_provider.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/operation_provider.hpp index 42374fe3d..512e74ff2 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/operation_provider.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/providers/operation_provider.hpp @@ -14,81 +14,6 @@ #pragma once -#include -#include -#include - -namespace ros2_medkit_gateway { - -enum class OperationProviderError { - EntityNotFound, - OperationNotFound, - InvalidParameters, - TransportError, - Timeout, - Rejected, - Internal -}; - -struct OperationProviderErrorInfo { - OperationProviderError code; - std::string message; - int http_status{500}; ///< Suggested HTTP status code -}; - -/** - * @brief Provider interface for entity operations - * - * Typed provider interface for plugins that serve SOVD operations - * (GET /{entity_type}/{id}/operations, POST /{entity_type}/{id}/operations/{name}). - * Per-entity routing like DataProvider. - * - * @par Thread safety - * All methods may be called concurrently. Implementations must synchronize. - * - * @see GatewayPlugin for the base class all plugins must also implement - * @see DataProvider for the data counterpart - */ -class OperationProvider { - public: - virtual ~OperationProvider() = default; - - /// List available operations for an entity - /// @param entity_id SOVD entity ID - /// @return JSON with {"items": [...]} array of operation descriptors - virtual tl::expected list_operations(const std::string & entity_id) = 0; - - /// Get a specific operation by name - /// @param entity_id SOVD entity ID - /// @param operation_name Operation name - /// @return JSON with operation detail, or OperationNotFound error - /// @note Default implementation calls list_operations + linear scan. - /// Override for O(1) lookup in plugins with many operations. - virtual tl::expected get_operation(const std::string & entity_id, - const std::string & operation_name) { - auto result = list_operations(entity_id); - if (!result) { - return tl::make_unexpected(result.error()); - } - if (result->contains("items") && (*result)["items"].is_array()) { - for (const auto & item : (*result)["items"]) { - if (item.value("id", "") == operation_name) { - return tl::expected{item}; - } - } - } - return tl::make_unexpected( - OperationProviderErrorInfo{OperationProviderError::OperationNotFound, "Operation not found", 404}); - } - - /// Execute an operation - /// @param entity_id SOVD entity ID - /// @param operation_name Operation name (e.g., "session_control") - /// @param parameters JSON parameters from request body - /// @return JSON response body with operation result - virtual tl::expected - execute_operation(const std::string & entity_id, const std::string & operation_name, - const nlohmann::json & parameters) = 0; -}; - -} // namespace ros2_medkit_gateway +// Backwards-compatibility shim - header moved to core/. Remove once all +// downstream consumers have migrated to the new path. +#include "ros2_medkit_gateway/core/providers/operation_provider.hpp" diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_fault_subscriber.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_fault_subscriber.hpp index fec986578..89ec97791 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_fault_subscriber.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_fault_subscriber.hpp @@ -19,7 +19,7 @@ #include #include "rclcpp/rclcpp.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" #include "ros2_medkit_msgs/msg/fault_event.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_topic_subscriber.hpp b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_topic_subscriber.hpp index b45d5f290..7c1f67b41 100644 --- a/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_topic_subscriber.hpp +++ b/src/ros2_medkit_gateway/include/ros2_medkit_gateway/trigger_topic_subscriber.hpp @@ -25,7 +25,7 @@ #include -#include "ros2_medkit_gateway/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" #include "ros2_medkit_serialization/json_serializer.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/scripts/check_core_purity.sh b/src/ros2_medkit_gateway/scripts/check_core_purity.sh new file mode 100755 index 000000000..c21713fcd --- /dev/null +++ b/src/ros2_medkit_gateway/scripts/check_core_purity.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Copyright 2026 bburda +# +# 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. + +# Verifies that the neutral core layer has no ROS includes. +# Run from the package root directory. + +set -euo pipefail + +CORE_DIRS=( + "include/ros2_medkit_gateway/core" + "src/core" +) + +FORBIDDEN_PATTERN='#include[[:space:]]*[<"](rclcpp|rcl_interfaces|rosidl|action_msgs|std_msgs|sensor_msgs|geometry_msgs|builtin_interfaces|ros2_medkit_msgs|rcutils|rmw)[/_]' + +violations=0 +for dir in "${CORE_DIRS[@]}"; do + if [ ! -d "$dir" ]; then + continue + fi + while IFS= read -r match; do + echo "FORBIDDEN ROS INCLUDE: $match" + violations=$((violations + 1)) + done < <(grep -rEn "$FORBIDDEN_PATTERN" "$dir" 2>/dev/null || true) +done + +if [ "$violations" -gt 0 ]; then + echo "" + echo "Core purity check failed: $violations ROS-include violation(s) detected." + echo "The core/ layer is the middleware-neutral business-logic layer." + echo "ROS-specific code belongs under src/ (or a future ros2/ subdirectory)." + exit 1 +fi + +echo "Core purity check OK." +exit 0 diff --git a/src/ros2_medkit_gateway/src/aggregation/aggregation_manager.cpp b/src/ros2_medkit_gateway/src/aggregation/aggregation_manager.cpp index 244bd27e8..fd0d9369c 100644 --- a/src/ros2_medkit_gateway/src/aggregation/aggregation_manager.cpp +++ b/src/ros2_medkit_gateway/src/aggregation/aggregation_manager.cpp @@ -26,8 +26,8 @@ #include -#include "ros2_medkit_gateway/aggregation/entity_merger.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/aggregation/entity_merger.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/aggregation/classification.cpp b/src/ros2_medkit_gateway/src/core/aggregation/classification.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/aggregation/classification.cpp rename to src/ros2_medkit_gateway/src/core/aggregation/classification.cpp index ed060f049..097587f8d 100644 --- a/src/ros2_medkit_gateway/src/aggregation/classification.cpp +++ b/src/ros2_medkit_gateway/src/core/aggregation/classification.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/aggregation/classification.hpp" +#include "ros2_medkit_gateway/core/aggregation/classification.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/aggregation/entity_merger.cpp b/src/ros2_medkit_gateway/src/core/aggregation/entity_merger.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/aggregation/entity_merger.cpp rename to src/ros2_medkit_gateway/src/core/aggregation/entity_merger.cpp index 9fe925fb8..581d90fef 100644 --- a/src/ros2_medkit_gateway/src/aggregation/entity_merger.cpp +++ b/src/ros2_medkit_gateway/src/core/aggregation/entity_merger.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/aggregation/entity_merger.hpp" +#include "ros2_medkit_gateway/core/aggregation/entity_merger.hpp" #include diff --git a/src/ros2_medkit_gateway/src/aggregation/mdns_discovery.cpp b/src/ros2_medkit_gateway/src/core/aggregation/mdns_discovery.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/aggregation/mdns_discovery.cpp rename to src/ros2_medkit_gateway/src/core/aggregation/mdns_discovery.cpp index 173274657..5c815f35f 100644 --- a/src/ros2_medkit_gateway/src/aggregation/mdns_discovery.cpp +++ b/src/ros2_medkit_gateway/src/core/aggregation/mdns_discovery.cpp @@ -25,7 +25,7 @@ #include "mdns.h" #pragma GCC diagnostic pop -#include "ros2_medkit_gateway/aggregation/mdns_discovery.hpp" +#include "ros2_medkit_gateway/core/aggregation/mdns_discovery.hpp" #include #include @@ -40,7 +40,7 @@ #include #include -#include "ros2_medkit_gateway/discovery/host_info_provider.hpp" +#include "ros2_medkit_gateway/core/providers/host_info_provider.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/aggregation/peer_client.cpp b/src/ros2_medkit_gateway/src/core/aggregation/peer_client.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/aggregation/peer_client.cpp rename to src/ros2_medkit_gateway/src/core/aggregation/peer_client.cpp index b7e00a011..d39cbfa89 100644 --- a/src/ros2_medkit_gateway/src/aggregation/peer_client.cpp +++ b/src/ros2_medkit_gateway/src/core/aggregation/peer_client.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/aggregation/peer_client.hpp" +#include "ros2_medkit_gateway/core/aggregation/peer_client.hpp" #include #include @@ -21,7 +21,7 @@ #include #include -#include "ros2_medkit_gateway/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/aggregation/sse_stream_proxy.cpp b/src/ros2_medkit_gateway/src/core/aggregation/sse_stream_proxy.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/aggregation/sse_stream_proxy.cpp rename to src/ros2_medkit_gateway/src/core/aggregation/sse_stream_proxy.cpp index 0c493e180..3e2f1a5a9 100644 --- a/src/ros2_medkit_gateway/src/aggregation/sse_stream_proxy.cpp +++ b/src/ros2_medkit_gateway/src/core/aggregation/sse_stream_proxy.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/aggregation/stream_proxy.hpp" +#include "ros2_medkit_gateway/core/aggregation/stream_proxy.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/auth/auth_config.cpp b/src/ros2_medkit_gateway/src/core/auth/auth_config.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/auth/auth_config.cpp rename to src/ros2_medkit_gateway/src/core/auth/auth_config.cpp index 6b652c783..8f4c65984 100644 --- a/src/ros2_medkit_gateway/src/auth/auth_config.cpp +++ b/src/ros2_medkit_gateway/src/core/auth/auth_config.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/auth/auth_config.hpp" +#include "ros2_medkit_gateway/core/auth/auth_config.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/auth/auth_manager.cpp b/src/ros2_medkit_gateway/src/core/auth/auth_manager.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/auth/auth_manager.cpp rename to src/ros2_medkit_gateway/src/core/auth/auth_manager.cpp index 9eda63450..a0e313d8a 100644 --- a/src/ros2_medkit_gateway/src/auth/auth_manager.cpp +++ b/src/ros2_medkit_gateway/src/core/auth/auth_manager.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/auth/auth_manager.hpp" +#include "ros2_medkit_gateway/core/auth/auth_manager.hpp" #include diff --git a/src/ros2_medkit_gateway/src/auth/auth_middleware.cpp b/src/ros2_medkit_gateway/src/core/auth/auth_middleware.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/auth/auth_middleware.cpp rename to src/ros2_medkit_gateway/src/core/auth/auth_middleware.cpp index 45073f28a..d83f2b021 100644 --- a/src/ros2_medkit_gateway/src/auth/auth_middleware.cpp +++ b/src/ros2_medkit_gateway/src/core/auth/auth_middleware.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/auth/auth_middleware.hpp" +#include "ros2_medkit_gateway/core/auth/auth_middleware.hpp" #include diff --git a/src/ros2_medkit_gateway/src/auth/auth_models.cpp b/src/ros2_medkit_gateway/src/core/auth/auth_models.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/auth/auth_models.cpp rename to src/ros2_medkit_gateway/src/core/auth/auth_models.cpp index f7a5c3af7..9663a5b42 100644 --- a/src/ros2_medkit_gateway/src/auth/auth_models.cpp +++ b/src/ros2_medkit_gateway/src/core/auth/auth_models.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/auth/auth_models.hpp" +#include "ros2_medkit_gateway/core/auth/auth_models.hpp" #include diff --git a/src/ros2_medkit_gateway/src/auth/auth_requirement_policy.cpp b/src/ros2_medkit_gateway/src/core/auth/auth_requirement_policy.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/auth/auth_requirement_policy.cpp rename to src/ros2_medkit_gateway/src/core/auth/auth_requirement_policy.cpp index ca7ad116f..16393f3b8 100644 --- a/src/ros2_medkit_gateway/src/auth/auth_requirement_policy.cpp +++ b/src/ros2_medkit_gateway/src/core/auth/auth_requirement_policy.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/auth/auth_requirement_policy.hpp" +#include "ros2_medkit_gateway/core/auth/auth_requirement_policy.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/config.cpp b/src/ros2_medkit_gateway/src/core/config.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/config.cpp rename to src/ros2_medkit_gateway/src/core/config.cpp index 3fccc9c9c..b140bd110 100644 --- a/src/ros2_medkit_gateway/src/config.cpp +++ b/src/ros2_medkit_gateway/src/core/config.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/config.hpp" +#include "ros2_medkit_gateway/core/config.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/discovery/discovery_enums.cpp b/src/ros2_medkit_gateway/src/core/discovery/discovery_enums.cpp similarity index 94% rename from src/ros2_medkit_gateway/src/discovery/discovery_enums.cpp rename to src/ros2_medkit_gateway/src/core/discovery/discovery_enums.cpp index d7591b9a3..2a5d2eed5 100644 --- a/src/ros2_medkit_gateway/src/discovery/discovery_enums.cpp +++ b/src/ros2_medkit_gateway/src/core/discovery/discovery_enums.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/discovery_enums.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_enums.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/discovery/host_info_provider.cpp b/src/ros2_medkit_gateway/src/core/discovery/host_info_provider.cpp similarity index 97% rename from src/ros2_medkit_gateway/src/discovery/host_info_provider.cpp rename to src/ros2_medkit_gateway/src/core/discovery/host_info_provider.cpp index 2acb92b91..3952d75c7 100644 --- a/src/ros2_medkit_gateway/src/discovery/host_info_provider.cpp +++ b/src/ros2_medkit_gateway/src/core/discovery/host_info_provider.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/host_info_provider.hpp" +#include "ros2_medkit_gateway/core/providers/host_info_provider.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/discovery/manifest/manifest_validator.cpp b/src/ros2_medkit_gateway/src/core/discovery/manifest/manifest_validator.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/discovery/manifest/manifest_validator.cpp rename to src/ros2_medkit_gateway/src/core/discovery/manifest/manifest_validator.cpp index ec05f648c..80df42ffa 100644 --- a/src/ros2_medkit_gateway/src/discovery/manifest/manifest_validator.cpp +++ b/src/ros2_medkit_gateway/src/core/discovery/manifest/manifest_validator.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/manifest/manifest_validator.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest_validator.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/discovery/models/app.cpp b/src/ros2_medkit_gateway/src/core/discovery/models/app.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/discovery/models/app.cpp rename to src/ros2_medkit_gateway/src/core/discovery/models/app.cpp index d10e39761..2048d8af5 100644 --- a/src/ros2_medkit_gateway/src/discovery/models/app.cpp +++ b/src/ros2_medkit_gateway/src/core/discovery/models/app.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/discovery/models/function.cpp b/src/ros2_medkit_gateway/src/core/discovery/models/function.cpp similarity index 97% rename from src/ros2_medkit_gateway/src/discovery/models/function.cpp rename to src/ros2_medkit_gateway/src/core/discovery/models/function.cpp index 1be3fc1ea..b6f763cfe 100644 --- a/src/ros2_medkit_gateway/src/discovery/models/function.cpp +++ b/src/ros2_medkit_gateway/src/core/discovery/models/function.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/entity_validation.cpp b/src/ros2_medkit_gateway/src/core/entity_validation.cpp similarity index 97% rename from src/ros2_medkit_gateway/src/entity_validation.cpp rename to src/ros2_medkit_gateway/src/core/entity_validation.cpp index b026d6010..360884ede 100644 --- a/src/ros2_medkit_gateway/src/entity_validation.cpp +++ b/src/ros2_medkit_gateway/src/core/entity_validation.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/entity_validation.hpp" +#include "ros2_medkit_gateway/core/entity_validation.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/http/entity_path_utils.cpp b/src/ros2_medkit_gateway/src/core/http/entity_path_utils.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/http/entity_path_utils.cpp rename to src/ros2_medkit_gateway/src/core/http/entity_path_utils.cpp index 204c74d88..ff1d1668c 100644 --- a/src/ros2_medkit_gateway/src/http/entity_path_utils.cpp +++ b/src/ros2_medkit_gateway/src/core/http/entity_path_utils.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/entity_path_utils.hpp" +#include "ros2_medkit_gateway/core/http/entity_path_utils.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/http/handlers/capability_builder.cpp b/src/ros2_medkit_gateway/src/core/http/handlers/capability_builder.cpp similarity index 97% rename from src/ros2_medkit_gateway/src/http/handlers/capability_builder.cpp rename to src/ros2_medkit_gateway/src/core/http/handlers/capability_builder.cpp index c69fdfd5b..bc8448d70 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/capability_builder.cpp +++ b/src/ros2_medkit_gateway/src/core/http/handlers/capability_builder.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/capability_builder.hpp" +#include "ros2_medkit_gateway/core/http/handlers/capability_builder.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/src/http/rate_limiter.cpp b/src/ros2_medkit_gateway/src/core/http/rate_limiter.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/http/rate_limiter.cpp rename to src/ros2_medkit_gateway/src/core/http/rate_limiter.cpp index e202af287..5f2e4c569 100644 --- a/src/ros2_medkit_gateway/src/http/rate_limiter.cpp +++ b/src/ros2_medkit_gateway/src/core/http/rate_limiter.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/rate_limiter.hpp" +#include "ros2_medkit_gateway/core/http/rate_limiter.hpp" #include #include @@ -20,7 +20,7 @@ #include #include -#include "ros2_medkit_gateway/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/http/x_medkit.cpp b/src/ros2_medkit_gateway/src/core/http/x_medkit.cpp similarity index 96% rename from src/ros2_medkit_gateway/src/http/x_medkit.cpp rename to src/ros2_medkit_gateway/src/core/http/x_medkit.cpp index a41f23a74..f3c6187d7 100644 --- a/src/ros2_medkit_gateway/src/http/x_medkit.cpp +++ b/src/ros2_medkit_gateway/src/core/http/x_medkit.cpp @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/x_medkit.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" -#include "ros2_medkit_gateway/discovery/models/common.hpp" +#include "ros2_medkit_gateway/core/discovery/models/common.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/bulk_data_store.cpp b/src/ros2_medkit_gateway/src/core/managers/bulk_data_store.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/bulk_data_store.cpp rename to src/ros2_medkit_gateway/src/core/managers/bulk_data_store.cpp index 831b75ac2..27e8384b1 100644 --- a/src/ros2_medkit_gateway/src/bulk_data_store.cpp +++ b/src/ros2_medkit_gateway/src/core/managers/bulk_data_store.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/bulk_data_store.hpp" +#include "ros2_medkit_gateway/core/managers/bulk_data_store.hpp" #include #include @@ -20,7 +20,7 @@ #include #include -#include "ros2_medkit_gateway/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" namespace ros2_medkit_gateway { @@ -74,7 +74,7 @@ std::string BulkDataStore::generate_id(const std::string & category) { auto ns = std::chrono::duration_cast(now.time_since_epoch()).count(); // Generate 8 hex chars from random - // gateway_lib.a is compiled with POSITION_INDEPENDENT_CODE (fPIC), so the compiler + // gateway_core.a is compiled with POSITION_INDEPENDENT_CODE (fPIC), so the compiler // emits global-dynamic TLS which works in both executables and shared objects. static thread_local std::mt19937 gen(std::random_device{}()); std::uniform_int_distribution dist(0, 0xFFFFFFFF); diff --git a/src/ros2_medkit_gateway/src/lock_manager.cpp b/src/ros2_medkit_gateway/src/core/managers/lock_manager.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/lock_manager.cpp rename to src/ros2_medkit_gateway/src/core/managers/lock_manager.cpp index fe7a9b9a1..ebe115106 100644 --- a/src/ros2_medkit_gateway/src/lock_manager.cpp +++ b/src/ros2_medkit_gateway/src/core/managers/lock_manager.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/lock_manager.hpp" +#include "ros2_medkit_gateway/core/managers/lock_manager.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/subscription_manager.cpp b/src/ros2_medkit_gateway/src/core/managers/subscription_manager.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/subscription_manager.cpp rename to src/ros2_medkit_gateway/src/core/managers/subscription_manager.cpp index a8941820f..274ba6054 100644 --- a/src/ros2_medkit_gateway/src/subscription_manager.cpp +++ b/src/ros2_medkit_gateway/src/core/managers/subscription_manager.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/subscription_manager.hpp" +#include "ros2_medkit_gateway/core/managers/subscription_manager.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/updates/update_manager.cpp b/src/ros2_medkit_gateway/src/core/managers/update_manager.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/updates/update_manager.cpp rename to src/ros2_medkit_gateway/src/core/managers/update_manager.cpp index 631894288..78ac81e4b 100644 --- a/src/ros2_medkit_gateway/src/updates/update_manager.cpp +++ b/src/ros2_medkit_gateway/src/core/managers/update_manager.cpp @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/updates/update_manager.hpp" +#include "ros2_medkit_gateway/core/managers/update_manager.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/models/aggregation_service.cpp b/src/ros2_medkit_gateway/src/core/models/aggregation_service.cpp similarity index 97% rename from src/ros2_medkit_gateway/src/models/aggregation_service.cpp rename to src/ros2_medkit_gateway/src/core/models/aggregation_service.cpp index c0b503e2c..1c85c1a34 100644 --- a/src/ros2_medkit_gateway/src/models/aggregation_service.cpp +++ b/src/ros2_medkit_gateway/src/core/models/aggregation_service.cpp @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/models/aggregation_service.hpp" +#include "ros2_medkit_gateway/core/models/aggregation_service.hpp" -#include "ros2_medkit_gateway/models/entity_capabilities.hpp" +#include "ros2_medkit_gateway/core/models/entity_capabilities.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/models/entity_capabilities.cpp b/src/ros2_medkit_gateway/src/core/models/entity_capabilities.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/models/entity_capabilities.cpp rename to src/ros2_medkit_gateway/src/core/models/entity_capabilities.cpp index ef02c363a..99dad755e 100644 --- a/src/ros2_medkit_gateway/src/models/entity_capabilities.cpp +++ b/src/ros2_medkit_gateway/src/core/models/entity_capabilities.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/models/entity_capabilities.hpp" +#include "ros2_medkit_gateway/core/models/entity_capabilities.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/models/entity_types.cpp b/src/ros2_medkit_gateway/src/core/models/entity_types.cpp similarity index 98% rename from src/ros2_medkit_gateway/src/models/entity_types.cpp rename to src/ros2_medkit_gateway/src/core/models/entity_types.cpp index 9c476eab5..429f8f44f 100644 --- a/src/ros2_medkit_gateway/src/models/entity_types.cpp +++ b/src/ros2_medkit_gateway/src/core/models/entity_types.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/models/thread_safe_entity_cache.cpp b/src/ros2_medkit_gateway/src/core/models/thread_safe_entity_cache.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/models/thread_safe_entity_cache.cpp rename to src/ros2_medkit_gateway/src/core/models/thread_safe_entity_cache.cpp index 4478cfa6a..c1947b171 100644 --- a/src/ros2_medkit_gateway/src/models/thread_safe_entity_cache.cpp +++ b/src/ros2_medkit_gateway/src/core/models/thread_safe_entity_cache.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/models/thread_safe_entity_cache.hpp" +#include "ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/openapi/path_resolver.cpp b/src/ros2_medkit_gateway/src/core/openapi/path_resolver.cpp similarity index 100% rename from src/ros2_medkit_gateway/src/openapi/path_resolver.cpp rename to src/ros2_medkit_gateway/src/core/openapi/path_resolver.cpp diff --git a/src/ros2_medkit_gateway/src/openapi/route_registry.cpp b/src/ros2_medkit_gateway/src/core/openapi/route_registry.cpp similarity index 100% rename from src/ros2_medkit_gateway/src/openapi/route_registry.cpp rename to src/ros2_medkit_gateway/src/core/openapi/route_registry.cpp diff --git a/src/ros2_medkit_gateway/src/resource_change_notifier.cpp b/src/ros2_medkit_gateway/src/core/resource_change_notifier.cpp similarity index 94% rename from src/ros2_medkit_gateway/src/resource_change_notifier.cpp rename to src/ros2_medkit_gateway/src/core/resource_change_notifier.cpp index c2b33b605..5b0f40259 100644 --- a/src/ros2_medkit_gateway/src/resource_change_notifier.cpp +++ b/src/ros2_medkit_gateway/src/core/resource_change_notifier.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" #include #include @@ -48,12 +48,18 @@ void ResourceChangeNotifier::notify(const std::string & collection, const std::s active_notify_count_.fetch_add(1); struct NotifyGuard { ResourceChangeNotifier & self; + explicit NotifyGuard(ResourceChangeNotifier & s) : self(s) { + } ~NotifyGuard() { if (self.active_notify_count_.fetch_sub(1) == 1) { std::lock_guard lk(self.drain_mutex_); self.drain_cv_.notify_one(); } } + NotifyGuard(const NotifyGuard &) = delete; + NotifyGuard & operator=(const NotifyGuard &) = delete; + NotifyGuard(NotifyGuard &&) = delete; + NotifyGuard & operator=(NotifyGuard &&) = delete; } guard{*this}; if (shutdown_flag_.load()) { diff --git a/src/ros2_medkit_gateway/src/resource_sampler.cpp b/src/ros2_medkit_gateway/src/core/resource_sampler.cpp similarity index 96% rename from src/ros2_medkit_gateway/src/resource_sampler.cpp rename to src/ros2_medkit_gateway/src/core/resource_sampler.cpp index cc462c5f4..b71efffea 100644 --- a/src/ros2_medkit_gateway/src/resource_sampler.cpp +++ b/src/ros2_medkit_gateway/src/core/resource_sampler.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/resource_sampler.hpp" +#include "ros2_medkit_gateway/core/resource_sampler.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/sqlite_trigger_store.cpp b/src/ros2_medkit_gateway/src/core/sqlite_trigger_store.cpp similarity index 99% rename from src/ros2_medkit_gateway/src/sqlite_trigger_store.cpp rename to src/ros2_medkit_gateway/src/core/sqlite_trigger_store.cpp index cebab16a2..4d5b309e8 100644 --- a/src/ros2_medkit_gateway/src/sqlite_trigger_store.cpp +++ b/src/ros2_medkit_gateway/src/core/sqlite_trigger_store.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/sqlite_trigger_store.hpp" +#include "ros2_medkit_gateway/core/sqlite_trigger_store.hpp" #include #include @@ -42,6 +42,8 @@ class SqliteStatement { SqliteStatement(const SqliteStatement &) = delete; SqliteStatement & operator=(const SqliteStatement &) = delete; + SqliteStatement(SqliteStatement &&) = delete; + SqliteStatement & operator=(SqliteStatement &&) = delete; sqlite3_stmt * get() const { return stmt_; diff --git a/src/ros2_medkit_gateway/src/subscription_transport.cpp b/src/ros2_medkit_gateway/src/core/subscription_transport.cpp similarity index 96% rename from src/ros2_medkit_gateway/src/subscription_transport.cpp rename to src/ros2_medkit_gateway/src/core/subscription_transport.cpp index 7e4df0ccd..2144def53 100644 --- a/src/ros2_medkit_gateway/src/subscription_transport.cpp +++ b/src/ros2_medkit_gateway/src/core/subscription_transport.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/subscription_transport.hpp" +#include "ros2_medkit_gateway/core/subscription_transport.hpp" #include diff --git a/src/ros2_medkit_gateway/src/data/ros2_topic_data_provider.cpp b/src/ros2_medkit_gateway/src/data/ros2_topic_data_provider.cpp index 3faa4bfe6..40197df15 100644 --- a/src/ros2_medkit_gateway/src/data/ros2_topic_data_provider.cpp +++ b/src/ros2_medkit_gateway/src/data/ros2_topic_data_provider.cpp @@ -26,7 +26,7 @@ #include #include -#include "ros2_medkit_gateway/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" #include "ros2_medkit_serialization/serialization_error.hpp" // Lock order (must be observed by every member function and helper): @@ -365,7 +365,7 @@ tl::expected Ros2TopicDataProvider::sample(const s new_entry->last_sample_time = std::chrono::steady_clock::now(); std::weak_ptr entry_weak = new_entry; - auto cb = [entry_weak](std::shared_ptr msg) { + auto cb = [entry_weak](const std::shared_ptr & msg) { auto e = entry_weak.lock(); if (!e || e->shutdown.load(std::memory_order_acquire)) { return; diff --git a/src/ros2_medkit_gateway/src/data_access_manager.cpp b/src/ros2_medkit_gateway/src/data_access_manager.cpp index 9fcef57e1..90519f93f 100644 --- a/src/ros2_medkit_gateway/src/data_access_manager.cpp +++ b/src/ros2_medkit_gateway/src/data_access_manager.cpp @@ -20,8 +20,8 @@ #include #include -#include "ros2_medkit_gateway/data/topic_data_provider.hpp" -#include "ros2_medkit_gateway/exceptions.hpp" +#include "ros2_medkit_gateway/core/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/exceptions.hpp" #include "ros2_medkit_serialization/serialization_error.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/default_script_provider.cpp b/src/ros2_medkit_gateway/src/default_script_provider.cpp index d3485b0d1..2b1cc3e31 100644 --- a/src/ros2_medkit_gateway/src/default_script_provider.cpp +++ b/src/ros2_medkit_gateway/src/default_script_provider.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/default_script_provider.hpp" +#include "ros2_medkit_gateway/core/default_script_provider.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/discovery/discovery_manager.cpp b/src/ros2_medkit_gateway/src/discovery/discovery_manager.cpp index 89415f1bf..c6cf21e84 100644 --- a/src/ros2_medkit_gateway/src/discovery/discovery_manager.cpp +++ b/src/ros2_medkit_gateway/src/discovery/discovery_manager.cpp @@ -14,10 +14,10 @@ #include "ros2_medkit_gateway/discovery/discovery_manager.hpp" +#include "ros2_medkit_gateway/core/discovery/layers/manifest_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/layers/runtime_layer.hpp" #include "ros2_medkit_gateway/discovery/hybrid_discovery.hpp" -#include "ros2_medkit_gateway/discovery/layers/manifest_layer.hpp" #include "ros2_medkit_gateway/discovery/layers/plugin_layer.hpp" -#include "ros2_medkit_gateway/discovery/layers/runtime_layer.hpp" #include "ros2_medkit_gateway/discovery/manifest/runtime_linker.hpp" #include "ros2_medkit_gateway/discovery/merge_pipeline.hpp" diff --git a/src/ros2_medkit_gateway/src/discovery/layers/manifest_layer.cpp b/src/ros2_medkit_gateway/src/discovery/layers/manifest_layer.cpp index dbbd43c22..2951d6977 100644 --- a/src/ros2_medkit_gateway/src/discovery/layers/manifest_layer.cpp +++ b/src/ros2_medkit_gateway/src/discovery/layers/manifest_layer.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/layers/manifest_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/layers/manifest_layer.hpp" namespace ros2_medkit_gateway { namespace discovery { diff --git a/src/ros2_medkit_gateway/src/discovery/layers/runtime_layer.cpp b/src/ros2_medkit_gateway/src/discovery/layers/runtime_layer.cpp index b2666de3d..84020722b 100644 --- a/src/ros2_medkit_gateway/src/discovery/layers/runtime_layer.cpp +++ b/src/ros2_medkit_gateway/src/discovery/layers/runtime_layer.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/layers/runtime_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/layers/runtime_layer.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/discovery/manifest/manifest_parser.cpp b/src/ros2_medkit_gateway/src/discovery/manifest/manifest_parser.cpp index a02044115..0b40fa56e 100644 --- a/src/ros2_medkit_gateway/src/discovery/manifest/manifest_parser.cpp +++ b/src/ros2_medkit_gateway/src/discovery/manifest/manifest_parser.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/manifest/manifest_parser.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest_parser.hpp" #include diff --git a/src/ros2_medkit_gateway/src/discovery/manifest/runtime_linker.cpp b/src/ros2_medkit_gateway/src/discovery/manifest/runtime_linker.cpp index 3357c4fd5..84f42971f 100644 --- a/src/ros2_medkit_gateway/src/discovery/manifest/runtime_linker.cpp +++ b/src/ros2_medkit_gateway/src/discovery/manifest/runtime_linker.cpp @@ -14,7 +14,7 @@ #include "ros2_medkit_gateway/discovery/manifest/runtime_linker.hpp" -#include "ros2_medkit_gateway/discovery/merge_types.hpp" +#include "ros2_medkit_gateway/core/discovery/merge_types.hpp" #include diff --git a/src/ros2_medkit_gateway/src/discovery/merge_pipeline.cpp b/src/ros2_medkit_gateway/src/discovery/merge_pipeline.cpp index 681b8b35c..745da4dcc 100644 --- a/src/ros2_medkit_gateway/src/discovery/merge_pipeline.cpp +++ b/src/ros2_medkit_gateway/src/discovery/merge_pipeline.cpp @@ -14,7 +14,7 @@ #include "ros2_medkit_gateway/discovery/merge_pipeline.hpp" -#include "ros2_medkit_gateway/discovery/introspection_provider.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/gateway_node.cpp b/src/ros2_medkit_gateway/src/gateway_node.cpp index d21585069..75b509119 100644 --- a/src/ros2_medkit_gateway/src/gateway_node.cpp +++ b/src/ros2_medkit_gateway/src/gateway_node.cpp @@ -25,13 +25,13 @@ #include #include -#include "ros2_medkit_gateway/aggregation/network_utils.hpp" -#include "ros2_medkit_gateway/data/topic_data_provider.hpp" -#include "ros2_medkit_gateway/entity_validation.hpp" +#include "ros2_medkit_gateway/core/aggregation/network_utils.hpp" +#include "ros2_medkit_gateway/core/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/entity_validation.hpp" #include "ros2_medkit_gateway/param_utils.hpp" -#include "ros2_medkit_gateway/http/handlers/sse_transport_provider.hpp" -#include "ros2_medkit_gateway/sqlite_trigger_store.hpp" +#include "ros2_medkit_gateway/core/http/handlers/sse_transport_provider.hpp" +#include "ros2_medkit_gateway/core/sqlite_trigger_store.hpp" using namespace std::chrono_literals; diff --git a/src/ros2_medkit_gateway/src/http/handlers/auth_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/auth_handlers.cpp index 79cc922e7..8d9edd4b1 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/auth_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/auth_handlers.cpp @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/auth_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/auth_handlers.hpp" -#include "ros2_medkit_gateway/auth/auth_models.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/auth/auth_models.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp index a85446aff..4f9a9ce1b 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/bulkdata_handlers.cpp @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/bulkdata_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/bulkdata_handlers.hpp" #include #include #include #include -#include "ros2_medkit_gateway/bulk_data_store.hpp" +#include "ros2_medkit_gateway/core/http/entity_path_utils.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/managers/bulk_data_store.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/entity_path_utils.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/src/http/handlers/config_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/config_handlers.cpp index 503372323..0e0659018 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/config_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/config_handlers.cpp @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/config_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/config_handlers.hpp" #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/fan_out_helpers.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/fan_out_helpers.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/http/x_medkit.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/cyclic_subscription_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/cyclic_subscription_handlers.cpp index 3e77750ae..7d41857ba 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/cyclic_subscription_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/cyclic_subscription_handlers.cpp @@ -18,10 +18,10 @@ #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/data_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/data_handlers.cpp index cee976c44..e7c739a0f 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/data_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/data_handlers.cpp @@ -12,19 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/data_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/data_handlers.hpp" #include -#include "ros2_medkit_gateway/data/topic_data_provider.hpp" -#include "ros2_medkit_gateway/exceptions.hpp" +#include "ros2_medkit_gateway/core/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/exceptions.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/fan_out_helpers.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/providers/data_provider.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/fan_out_helpers.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/http/x_medkit.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/providers/data_provider.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/discovery_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/discovery_handlers.cpp index 13becaf4b..1e391c011 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/discovery_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/discovery_handlers.cpp @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/discovery_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/discovery_handlers.hpp" #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/handlers/capability_builder.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/handlers/capability_builder.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/http/x_medkit.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/docs_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/docs_handlers.cpp index 81b65633b..e3115d2b1 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/docs_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/docs_handlers.cpp @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/docs_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/docs_handlers.hpp" #include #include "../../openapi/capability_generator.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" #ifdef ENABLE_SWAGGER_UI #include "swagger_ui_assets.hpp" diff --git a/src/ros2_medkit_gateway/src/http/handlers/fault_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/fault_handlers.cpp index 3fbee21ff..b88863358 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/fault_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/fault_handlers.cpp @@ -24,14 +24,14 @@ #include #include "ros2_medkit_gateway/aggregation/aggregation_manager.hpp" +#include "ros2_medkit_gateway/core/http/entity_path_utils.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/fan_out_helpers.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/providers/fault_provider.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/entity_path_utils.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/fan_out_helpers.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/http/x_medkit.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/providers/fault_provider.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/handler_context.cpp b/src/ros2_medkit_gateway/src/http/handlers/handler_context.cpp index 87cd77605..374e2ec80 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/handler_context.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/handler_context.cpp @@ -17,12 +17,12 @@ #include #include "ros2_medkit_gateway/aggregation/aggregation_manager.hpp" -#include "ros2_medkit_gateway/entity_validation.hpp" +#include "ros2_medkit_gateway/core/entity_validation.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/managers/lock_manager.hpp" +#include "ros2_medkit_gateway/core/models/entity_capabilities.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/lock_manager.hpp" -#include "ros2_medkit_gateway/models/entity_capabilities.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/health_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/health_handlers.cpp index c70cd86a9..b0ca438ad 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/health_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/health_handlers.cpp @@ -12,22 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/health_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/health_handlers.hpp" #include #include "ros2_medkit_gateway/aggregation/aggregation_manager.hpp" -#include "ros2_medkit_gateway/auth/auth_models.hpp" -#include "ros2_medkit_gateway/data/topic_data_provider.hpp" -#include "ros2_medkit_gateway/discovery/discovery_enums.hpp" +#include "ros2_medkit_gateway/core/auth/auth_models.hpp" +#include "ros2_medkit_gateway/core/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_enums.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/fan_out_helpers.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/warning_codes.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" +#include "ros2_medkit_gateway/core/version.hpp" #include "ros2_medkit_gateway/discovery/discovery_manager.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/fan_out_helpers.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/http/warning_codes.hpp" -#include "ros2_medkit_gateway/http/x_medkit.hpp" -#include "ros2_medkit_gateway/version.hpp" #include "../../openapi/route_registry.hpp" diff --git a/src/ros2_medkit_gateway/src/http/handlers/lock_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/lock_handlers.cpp index 988561d7b..f0cca8c77 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/lock_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/lock_handlers.cpp @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/lock_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/lock_handlers.hpp" #include #include #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/log_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/log_handlers.cpp index 3465f01b7..a03873be3 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/log_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/log_handlers.cpp @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/log_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/log_handlers.hpp" #include #include #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/fan_out_helpers.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/fan_out_helpers.hpp" -#include "ros2_medkit_gateway/http/x_medkit.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/src/http/handlers/operation_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/operation_handlers.cpp index 806662d28..34437889c 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/operation_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/operation_handlers.cpp @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/operation_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/operation_handlers.hpp" #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/fan_out_helpers.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/providers/operation_provider.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/fan_out_helpers.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/http/x_medkit.hpp" #include "ros2_medkit_gateway/operation_manager.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/providers/operation_provider.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/script_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/script_handlers.cpp index b3db98a36..e9888858a 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/script_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/script_handlers.cpp @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/script_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/script_handlers.hpp" #include #include -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/sse_fault_handler.cpp b/src/ros2_medkit_gateway/src/http/handlers/sse_fault_handler.cpp index 4db37dfea..8010dbb49 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/sse_fault_handler.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/sse_fault_handler.cpp @@ -20,10 +20,10 @@ #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" #include "ros2_medkit_gateway/fault_manager.hpp" #include "ros2_medkit_gateway/fault_manager_paths.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" namespace ros2_medkit_gateway { namespace handlers { diff --git a/src/ros2_medkit_gateway/src/http/handlers/sse_transport_provider.cpp b/src/ros2_medkit_gateway/src/http/handlers/sse_transport_provider.cpp index 7e9f78897..4d68374c4 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/sse_transport_provider.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/sse_transport_provider.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/sse_transport_provider.hpp" +#include "ros2_medkit_gateway/core/http/handlers/sse_transport_provider.hpp" #include #include @@ -21,9 +21,9 @@ #include -#include "ros2_medkit_gateway/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/trigger_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/trigger_handlers.cpp index ac416ff4a..8b3fc1698 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/trigger_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/trigger_handlers.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/trigger_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/trigger_handlers.hpp" #include #include @@ -20,10 +20,10 @@ #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/handlers/update_handlers.cpp b/src/ros2_medkit_gateway/src/http/handlers/update_handlers.cpp index 0c2b72ec4..cd0c957fc 100644 --- a/src/ros2_medkit_gateway/src/http/handlers/update_handlers.cpp +++ b/src/ros2_medkit_gateway/src/http/handlers/update_handlers.cpp @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/handlers/update_handlers.hpp" +#include "ros2_medkit_gateway/core/http/handlers/update_handlers.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/src/http/http_server.cpp b/src/ros2_medkit_gateway/src/http/http_server.cpp index dd8b98b7d..716c2f8db 100644 --- a/src/ros2_medkit_gateway/src/http/http_server.cpp +++ b/src/ros2_medkit_gateway/src/http/http_server.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/http_server.hpp" +#include "ros2_medkit_gateway/core/http/http_server.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/http/rest_server.cpp b/src/ros2_medkit_gateway/src/http/rest_server.cpp index a0ae098dd..dd959e770 100644 --- a/src/ros2_medkit_gateway/src/http/rest_server.cpp +++ b/src/ros2_medkit_gateway/src/http/rest_server.cpp @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/http/rest_server.hpp" +#include "ros2_medkit_gateway/core/http/rest_server.hpp" #include #include #include #include -#include "ros2_medkit_gateway/auth/auth_middleware.hpp" +#include "ros2_medkit_gateway/core/auth/auth_middleware.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" #include "../openapi/route_registry.hpp" #include "../openapi/schema_builder.hpp" diff --git a/src/ros2_medkit_gateway/src/log_manager.cpp b/src/ros2_medkit_gateway/src/log_manager.cpp index 779c77c22..1df9dfcd3 100644 --- a/src/ros2_medkit_gateway/src/log_manager.cpp +++ b/src/ros2_medkit_gateway/src/log_manager.cpp @@ -19,8 +19,8 @@ #include #include -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/main.cpp b/src/ros2_medkit_gateway/src/main.cpp index d1349878a..06e64e94c 100644 --- a/src/ros2_medkit_gateway/src/main.cpp +++ b/src/ros2_medkit_gateway/src/main.cpp @@ -62,61 +62,77 @@ ros2_medkit_gateway::Ros2TopicDataProvider::Config declare_data_provider_config( } // namespace int main(int argc, char ** argv) { - rclcpp::init(argc, argv); + bool ros_inited = false; + try { + rclcpp::init(argc, argv); + ros_inited = true; - auto node = std::make_shared(); + auto node = std::make_shared(); - // MultiThreadedExecutor for the gateway node - HTTP handlers run on several - // threads, so the main executor must dispatch callbacks in parallel to avoid - // starving slow handlers. The Ros2SubscriptionExecutor built below owns its - // own internal single-threaded executor (spun from its worker thread); the - // subscription node is intentionally not added here. - rclcpp::executors::MultiThreadedExecutor executor; - executor.add_node(node); + // MultiThreadedExecutor for the gateway node - HTTP handlers run on several + // threads, so the main executor must dispatch callbacks in parallel to avoid + // starving slow handlers. The Ros2SubscriptionExecutor built below owns its + // own internal single-threaded executor (spun from its worker thread); the + // subscription node is intentionally not added here. + rclcpp::executors::MultiThreadedExecutor executor; + executor.add_node(node); - // Stand up the ROS 2 subscription executor + topic data provider. - // Issue #375: all subscription create/destroy calls are funneled through the - // serial worker owned by sub_exec, eliminating the rcl hash-map race that - // previously killed /data on Rolling when concurrent HTTP handler threads - // created subscriptions on the same node. - const auto exec_cfg = declare_executor_config(*node); - const auto dp_cfg = declare_data_provider_config(*node); - auto sub_exec = std::make_shared(node, exec_cfg); - auto serializer = std::make_shared(); - auto data_provider = std::make_shared(sub_exec, serializer, dp_cfg); - node->set_topic_data_provider(data_provider); + // Stand up the ROS 2 subscription executor + topic data provider. + // Issue #375: all subscription create/destroy calls are funneled through the + // serial worker owned by sub_exec, eliminating the rcl hash-map race that + // previously killed /data on Rolling when concurrent HTTP handler threads + // created subscriptions on the same node. + const auto exec_cfg = declare_executor_config(*node); + const auto dp_cfg = declare_data_provider_config(*node); + auto sub_exec = std::make_shared(node, exec_cfg); + auto serializer = std::make_shared(); + auto data_provider = std::make_shared(sub_exec, serializer, dp_cfg); + node->set_topic_data_provider(data_provider); - // Spin in a try/catch so an uncaught handler exception falls through to the - // explicit teardown block below. Without this, an escaping throw bypasses - // the teardown ordering and triggers exactly the rclcpp abort described - // there (~GatewayNode running against a dead executor, exit -6). - try { - executor.spin(); + // Spin in a try/catch so an uncaught handler exception falls through to the + // explicit teardown block below. Without this, an escaping throw bypasses + // the teardown ordering and triggers exactly the rclcpp abort described + // there (~GatewayNode running against a dead executor, exit -6). + try { + executor.spin(); + } catch (const std::exception & ex) { + RCLCPP_ERROR(node->get_logger(), "Executor.spin() threw an unhandled exception: %s. Falling through to teardown.", + ex.what()); + } catch (...) { + RCLCPP_ERROR(node->get_logger(), "Executor.spin() threw an unknown exception. Falling through to teardown."); + } + + // Teardown order (issue #375): stack-unwind destructs executor before node + // which leaves ~GatewayNode running against a dead executor. Newer rclcpp + // (rolling; recent jazzy patch releases) asserts 'node needs to be + // associated with an executor' and aborts with exit -6 when the managers' + // shutdown paths touch service clients. Explicit teardown avoids that: + // 1. detach the provider from GatewayNode so the managers stop using it + // before we drop it (GatewayNode otherwise holds a shared_ptr that + // would keep the provider alive past data_provider.reset()). + // 2. drop the provider (clears pool entries via the subscription worker) + // 3. reset sub_exec (joins worker, tears down internal subscription executor) + // 4. remove the gateway node from the executor and drop our ref so + // ~GatewayNode runs with the executor still alive. + node->set_topic_data_provider(nullptr); + data_provider.reset(); + sub_exec.reset(); + executor.remove_node(node); + node.reset(); + + rclcpp::shutdown(); } catch (const std::exception & ex) { - RCLCPP_ERROR(node->get_logger(), "Executor.spin() threw an unhandled exception: %s. Falling through to teardown.", - ex.what()); + fprintf(stderr, "[ros2_medkit_gateway] Fatal exception in main: %s\n", ex.what()); + if (ros_inited && rclcpp::ok()) { + rclcpp::shutdown(); + } + return 1; } catch (...) { - RCLCPP_ERROR(node->get_logger(), "Executor.spin() threw an unknown exception. Falling through to teardown."); + fprintf(stderr, "[ros2_medkit_gateway] Fatal unknown exception in main\n"); + if (ros_inited && rclcpp::ok()) { + rclcpp::shutdown(); + } + return 1; } - - // Teardown order (issue #375): stack-unwind destructs executor before node - // which leaves ~GatewayNode running against a dead executor. Newer rclcpp - // (rolling; recent jazzy patch releases) asserts 'node needs to be - // associated with an executor' and aborts with exit -6 when the managers' - // shutdown paths touch service clients. Explicit teardown avoids that: - // 1. detach the provider from GatewayNode so the managers stop using it - // before we drop it (GatewayNode otherwise holds a shared_ptr that - // would keep the provider alive past data_provider.reset()). - // 2. drop the provider (clears pool entries via the subscription worker) - // 3. reset sub_exec (joins worker, tears down internal subscription executor) - // 4. remove the gateway node from the executor and drop our ref so - // ~GatewayNode runs with the executor still alive. - node->set_topic_data_provider(nullptr); - data_provider.reset(); - sub_exec.reset(); - executor.remove_node(node); - node.reset(); - - rclcpp::shutdown(); return 0; } diff --git a/src/ros2_medkit_gateway/src/openapi/capability_generator.cpp b/src/ros2_medkit_gateway/src/openapi/capability_generator.cpp index ecb9ea500..e3bba1fef 100644 --- a/src/ros2_medkit_gateway/src/openapi/capability_generator.cpp +++ b/src/ros2_medkit_gateway/src/openapi/capability_generator.cpp @@ -21,13 +21,13 @@ #include "openapi_spec_builder.hpp" #include "path_builder.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/models/entity_capabilities.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/version.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/models/entity_capabilities.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/version.hpp" namespace ros2_medkit_gateway { namespace openapi { diff --git a/src/ros2_medkit_gateway/src/openapi/capability_generator.hpp b/src/ros2_medkit_gateway/src/openapi/capability_generator.hpp index 9695dd354..2995c2b1c 100644 --- a/src/ros2_medkit_gateway/src/openapi/capability_generator.hpp +++ b/src/ros2_medkit_gateway/src/openapi/capability_generator.hpp @@ -24,7 +24,7 @@ #include "route_registry.hpp" #include "schema_builder.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/openapi/path_builder.hpp b/src/ros2_medkit_gateway/src/openapi/path_builder.hpp index 4ee93cb79..7d5f827ff 100644 --- a/src/ros2_medkit_gateway/src/openapi/path_builder.hpp +++ b/src/ros2_medkit_gateway/src/openapi/path_builder.hpp @@ -18,8 +18,8 @@ #include #include -#include "ros2_medkit_gateway/discovery/models/common.hpp" -#include "ros2_medkit_gateway/models/thread_safe_entity_cache.hpp" +#include "ros2_medkit_gateway/core/discovery/models/common.hpp" +#include "ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp" namespace ros2_medkit_gateway { namespace openapi { diff --git a/src/ros2_medkit_gateway/src/operation_manager.cpp b/src/ros2_medkit_gateway/src/operation_manager.cpp index 289e76bde..40e83a963 100644 --- a/src/ros2_medkit_gateway/src/operation_manager.cpp +++ b/src/ros2_medkit_gateway/src/operation_manager.cpp @@ -20,7 +20,7 @@ #include #include -#include "ros2_medkit_gateway/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" #include "ros2_medkit_serialization/json_serializer.hpp" #include "ros2_medkit_serialization/message_cleanup.hpp" #include "ros2_medkit_serialization/serialization_error.hpp" diff --git a/src/ros2_medkit_gateway/src/plugins/plugin_context.cpp b/src/ros2_medkit_gateway/src/plugins/plugin_context.cpp index 8c4de1bc5..28461a742 100644 --- a/src/ros2_medkit_gateway/src/plugins/plugin_context.cpp +++ b/src/ros2_medkit_gateway/src/plugins/plugin_context.cpp @@ -12,22 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/plugins/plugin_context.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_context.hpp" #include #include #include -#include "ros2_medkit_gateway/entity_validation.hpp" +#include "ros2_medkit_gateway/core/entity_validation.hpp" -#include "ros2_medkit_gateway/condition_evaluator.hpp" +#include "ros2_medkit_gateway/core/condition_evaluator.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/managers/lock_manager.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/resource_sampler.hpp" #include "ros2_medkit_gateway/fault_manager.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/lock_manager.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" -#include "ros2_medkit_gateway/resource_sampler.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/plugins/plugin_http_types.cpp b/src/ros2_medkit_gateway/src/plugins/plugin_http_types.cpp index bb87e1549..fbf4daca5 100644 --- a/src/ros2_medkit_gateway/src/plugins/plugin_http_types.cpp +++ b/src/ros2_medkit_gateway/src/plugins/plugin_http_types.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/plugins/plugin_http_types.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_http_types.hpp" #include diff --git a/src/ros2_medkit_gateway/src/plugins/plugin_loader.cpp b/src/ros2_medkit_gateway/src/plugins/plugin_loader.cpp index a154075b8..6eba4c44e 100644 --- a/src/ros2_medkit_gateway/src/plugins/plugin_loader.cpp +++ b/src/ros2_medkit_gateway/src/plugins/plugin_loader.cpp @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/plugins/plugin_loader.hpp" - -#include "ros2_medkit_gateway/discovery/introspection_provider.hpp" -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" -#include "ros2_medkit_gateway/providers/data_provider.hpp" -#include "ros2_medkit_gateway/providers/fault_provider.hpp" -#include "ros2_medkit_gateway/providers/operation_provider.hpp" -#include "ros2_medkit_gateway/scripts/script_provider.hpp" -#include "ros2_medkit_gateway/updates/update_provider.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_loader.hpp" + +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" +#include "ros2_medkit_gateway/core/providers/data_provider.hpp" +#include "ros2_medkit_gateway/core/providers/fault_provider.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" +#include "ros2_medkit_gateway/core/providers/operation_provider.hpp" +#include "ros2_medkit_gateway/core/providers/script_provider.hpp" +#include "ros2_medkit_gateway/core/providers/update_provider.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/plugins/plugin_manager.cpp b/src/ros2_medkit_gateway/src/plugins/plugin_manager.cpp index 63fc8addb..c9f24e605 100644 --- a/src/ros2_medkit_gateway/src/plugins/plugin_manager.cpp +++ b/src/ros2_medkit_gateway/src/plugins/plugin_manager.cpp @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" #include #include #include -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/plugins/plugin_http_types.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_http_types.hpp" namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_gateway/src/script_manager.cpp b/src/ros2_medkit_gateway/src/script_manager.cpp index c77d9055c..f9f6357fb 100644 --- a/src/ros2_medkit_gateway/src/script_manager.cpp +++ b/src/ros2_medkit_gateway/src/script_manager.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/script_manager.hpp" +#include "ros2_medkit_gateway/core/managers/script_manager.hpp" #include diff --git a/src/ros2_medkit_gateway/src/trigger_manager.cpp b/src/ros2_medkit_gateway/src/trigger_manager.cpp index b56f0acec..a5ba6a781 100644 --- a/src/ros2_medkit_gateway/src/trigger_manager.cpp +++ b/src/ros2_medkit_gateway/src/trigger_manager.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/trigger_manager.hpp" +#include "ros2_medkit_gateway/core/managers/trigger_manager.hpp" #include #include diff --git a/src/ros2_medkit_gateway/src/type_introspection.cpp b/src/ros2_medkit_gateway/src/type_introspection.cpp index 8483e007a..ec279599f 100644 --- a/src/ros2_medkit_gateway/src/type_introspection.cpp +++ b/src/ros2_medkit_gateway/src/type_introspection.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/type_introspection.hpp" +#include "ros2_medkit_gateway/core/type_introspection.hpp" #include #include diff --git a/src/ros2_medkit_gateway/test/demo_nodes/test_bad_version_plugin.cpp b/src/ros2_medkit_gateway/test/demo_nodes/test_bad_version_plugin.cpp index 87ea9d7b1..5e00a4b20 100644 --- a/src/ros2_medkit_gateway/test/demo_nodes/test_bad_version_plugin.cpp +++ b/src/ros2_medkit_gateway/test/demo_nodes/test_bad_version_plugin.cpp @@ -15,8 +15,8 @@ /// Test plugin that exports a wrong API version (PLUGIN_API_VERSION + 1). /// Used by test_plugin_loader to verify version mismatch rejection. -#include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" extern "C" GATEWAY_PLUGIN_EXPORT int plugin_api_version() { return ros2_medkit_gateway::PLUGIN_API_VERSION + 1; diff --git a/src/ros2_medkit_gateway/test/demo_nodes/test_gateway_plugin.cpp b/src/ros2_medkit_gateway/test/demo_nodes/test_gateway_plugin.cpp index bac78f037..0f755f25f 100644 --- a/src/ros2_medkit_gateway/test/demo_nodes/test_gateway_plugin.cpp +++ b/src/ros2_medkit_gateway/test/demo_nodes/test_gateway_plugin.cpp @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/introspection_provider.hpp" -#include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" -#include "ros2_medkit_gateway/plugins/plugin_context.hpp" -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" -#include "ros2_medkit_gateway/updates/update_provider.hpp" +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_context.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" +#include "ros2_medkit_gateway/core/providers/update_provider.hpp" #include #include diff --git a/src/ros2_medkit_gateway/test/demo_nodes/test_minimal_plugin.cpp b/src/ros2_medkit_gateway/test/demo_nodes/test_minimal_plugin.cpp index 52a5a60be..916773e11 100644 --- a/src/ros2_medkit_gateway/test/demo_nodes/test_minimal_plugin.cpp +++ b/src/ros2_medkit_gateway/test/demo_nodes/test_minimal_plugin.cpp @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/demo_nodes/test_null_factory_plugin.cpp b/src/ros2_medkit_gateway/test/demo_nodes/test_null_factory_plugin.cpp index fb62aca9d..f6fc6d788 100644 --- a/src/ros2_medkit_gateway/test/demo_nodes/test_null_factory_plugin.cpp +++ b/src/ros2_medkit_gateway/test/demo_nodes/test_null_factory_plugin.cpp @@ -15,8 +15,8 @@ /// Test plugin with correct version but create_plugin() returns nullptr. /// Used by test_plugin_loader to verify null factory rejection. -#include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" extern "C" GATEWAY_PLUGIN_EXPORT int plugin_api_version() { return ros2_medkit_gateway::PLUGIN_API_VERSION; diff --git a/src/ros2_medkit_gateway/test/demo_nodes/test_update_backend.cpp b/src/ros2_medkit_gateway/test/demo_nodes/test_update_backend.cpp index b95068b16..20f84c20e 100644 --- a/src/ros2_medkit_gateway/test/demo_nodes/test_update_backend.cpp +++ b/src/ros2_medkit_gateway/test/demo_nodes/test_update_backend.cpp @@ -21,9 +21,9 @@ #include -#include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" -#include "ros2_medkit_gateway/updates/update_provider.hpp" +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" +#include "ros2_medkit_gateway/core/providers/update_provider.hpp" using json = nlohmann::json; using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/demo_nodes/test_version_only_plugin.cpp b/src/ros2_medkit_gateway/test/demo_nodes/test_version_only_plugin.cpp index 9d57f9d1b..b817e1e82 100644 --- a/src/ros2_medkit_gateway/test/demo_nodes/test_version_only_plugin.cpp +++ b/src/ros2_medkit_gateway/test/demo_nodes/test_version_only_plugin.cpp @@ -16,7 +16,7 @@ /// Used by test_plugin_loader to verify missing factory symbol detection /// (separate from missing version symbol). -#include "ros2_medkit_gateway/plugins/plugin_types.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_types.hpp" extern "C" GATEWAY_PLUGIN_EXPORT int plugin_api_version() { return ros2_medkit_gateway::PLUGIN_API_VERSION; diff --git a/src/ros2_medkit_gateway/test/test_aggregation_classification.cpp b/src/ros2_medkit_gateway/test/test_aggregation_classification.cpp index c6c26f44b..ed487988a 100644 --- a/src/ros2_medkit_gateway/test/test_aggregation_classification.cpp +++ b/src/ros2_medkit_gateway/test/test_aggregation_classification.cpp @@ -19,8 +19,8 @@ #include #include -#include "ros2_medkit_gateway/aggregation/classification.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/aggregation/classification.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_auth_config.cpp b/src/ros2_medkit_gateway/test/test_auth_config.cpp index e25e8321c..13c517266 100644 --- a/src/ros2_medkit_gateway/test/test_auth_config.cpp +++ b/src/ros2_medkit_gateway/test/test_auth_config.cpp @@ -14,8 +14,8 @@ #include -#include "ros2_medkit_gateway/auth/auth.hpp" -#include "ros2_medkit_gateway/config.hpp" +#include "ros2_medkit_gateway/core/auth/auth.hpp" +#include "ros2_medkit_gateway/core/config.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_auth_handlers.cpp b/src/ros2_medkit_gateway/test/test_auth_handlers.cpp index 8fe840188..bbfa017fd 100644 --- a/src/ros2_medkit_gateway/test/test_auth_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_auth_handlers.cpp @@ -18,8 +18,8 @@ #include #include -#include "ros2_medkit_gateway/auth/auth.hpp" -#include "ros2_medkit_gateway/http/handlers/auth_handlers.hpp" +#include "ros2_medkit_gateway/core/auth/auth.hpp" +#include "ros2_medkit_gateway/core/http/handlers/auth_handlers.hpp" using json = nlohmann::json; using ros2_medkit_gateway::AuthConfig; diff --git a/src/ros2_medkit_gateway/test/test_auth_manager.cpp b/src/ros2_medkit_gateway/test/test_auth_manager.cpp index 23ee6eba5..8cb883ff5 100644 --- a/src/ros2_medkit_gateway/test/test_auth_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_auth_manager.cpp @@ -17,7 +17,7 @@ #include #include -#include "ros2_medkit_gateway/auth/auth.hpp" +#include "ros2_medkit_gateway/core/auth/auth.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_bulk_data_store.cpp b/src/ros2_medkit_gateway/test/test_bulk_data_store.cpp index 6de1f6d79..a69558e2e 100644 --- a/src/ros2_medkit_gateway/test/test_bulk_data_store.cpp +++ b/src/ros2_medkit_gateway/test/test_bulk_data_store.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/bulk_data_store.hpp" +#include "ros2_medkit_gateway/core/managers/bulk_data_store.hpp" #include diff --git a/src/ros2_medkit_gateway/test/test_bulkdata_handlers.cpp b/src/ros2_medkit_gateway/test/test_bulkdata_handlers.cpp index f0a304cd0..af365de91 100644 --- a/src/ros2_medkit_gateway/test/test_bulkdata_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_bulkdata_handlers.cpp @@ -16,10 +16,10 @@ #include -#include "ros2_medkit_gateway/bulk_data_store.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/handlers/bulkdata_handlers.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/handlers/bulkdata_handlers.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/managers/bulk_data_store.hpp" using ros2_medkit_gateway::handlers::BulkDataHandlers; diff --git a/src/ros2_medkit_gateway/test/test_capability_builder.cpp b/src/ros2_medkit_gateway/test/test_capability_builder.cpp index def6a15d8..0d9da7808 100644 --- a/src/ros2_medkit_gateway/test/test_capability_builder.cpp +++ b/src/ros2_medkit_gateway/test/test_capability_builder.cpp @@ -14,7 +14,7 @@ #include -#include "ros2_medkit_gateway/http/handlers/capability_builder.hpp" +#include "ros2_medkit_gateway/core/http/handlers/capability_builder.hpp" using namespace ros2_medkit_gateway::handlers; using Cap = CapabilityBuilder::Capability; diff --git a/src/ros2_medkit_gateway/test/test_capability_generator.cpp b/src/ros2_medkit_gateway/test/test_capability_generator.cpp index f068e43c5..52cbb8348 100644 --- a/src/ros2_medkit_gateway/test/test_capability_generator.cpp +++ b/src/ros2_medkit_gateway/test/test_capability_generator.cpp @@ -22,10 +22,10 @@ #include "../src/openapi/capability_generator.hpp" #include "../src/openapi/route_registry.hpp" -#include "ros2_medkit_gateway/config.hpp" +#include "ros2_medkit_gateway/core/config.hpp" +#include "ros2_medkit_gateway/core/version.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/version.hpp" using namespace ros2_medkit_gateway; using namespace ros2_medkit_gateway::openapi; diff --git a/src/ros2_medkit_gateway/test/test_condition_evaluator.cpp b/src/ros2_medkit_gateway/test/test_condition_evaluator.cpp index c5d8eb555..b083ec17b 100644 --- a/src/ros2_medkit_gateway/test/test_condition_evaluator.cpp +++ b/src/ros2_medkit_gateway/test/test_condition_evaluator.cpp @@ -18,7 +18,7 @@ #include #include -#include "ros2_medkit_gateway/condition_evaluator.hpp" +#include "ros2_medkit_gateway/core/condition_evaluator.hpp" using namespace ros2_medkit_gateway; using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/test/test_cyclic_subscription_handlers.cpp b/src/ros2_medkit_gateway/test/test_cyclic_subscription_handlers.cpp index 1afed7f46..f814e34e2 100644 --- a/src/ros2_medkit_gateway/test/test_cyclic_subscription_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_cyclic_subscription_handlers.cpp @@ -18,12 +18,14 @@ #include #include -#include "ros2_medkit_gateway/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" #include "ros2_medkit_gateway/http/handlers/cyclic_subscription_handlers.hpp" using namespace ros2_medkit_gateway; using namespace ros2_medkit_gateway::handlers; -using json = nlohmann::json; +// json alias already imported via the `using namespace` above (defined in +// core/auth/auth_models.hpp). A local `using json = nlohmann::json;` would +// shadow it and trip clang-diagnostic-shadow under clang-tidy. // --- parse_resource_uri tests --- @@ -195,7 +197,7 @@ TEST(CyclicSubscriptionJsonTest, AllIntervalValuesSerialize) { info.entity_type = "apps"; info.entity_id = "e"; - for (auto [interval, expected] : std::vector>{ + for (const auto & [interval, expected] : std::vector>{ {CyclicInterval::FAST, "fast"}, {CyclicInterval::NORMAL, "normal"}, {CyclicInterval::SLOW, "slow"}}) { info.interval = interval; auto j = CyclicSubscriptionHandlers::subscription_to_json(info, "/events"); diff --git a/src/ros2_medkit_gateway/test/test_data_access_manager.cpp b/src/ros2_medkit_gateway/test/test_data_access_manager.cpp index 1173e077d..c8fa508b4 100644 --- a/src/ros2_medkit_gateway/test/test_data_access_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_data_access_manager.cpp @@ -21,11 +21,11 @@ #include #include +#include "ros2_medkit_gateway/core/exceptions.hpp" +#include "ros2_medkit_gateway/core/type_introspection.hpp" #include "ros2_medkit_gateway/data/ros2_topic_data_provider.hpp" #include "ros2_medkit_gateway/data_access_manager.hpp" -#include "ros2_medkit_gateway/exceptions.hpp" #include "ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp" -#include "ros2_medkit_gateway/type_introspection.hpp" #include "ros2_medkit_serialization/json_serializer.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_data_handlers.cpp b/src/ros2_medkit_gateway/test/test_data_handlers.cpp index 62d708d06..43fdfd676 100644 --- a/src/ros2_medkit_gateway/test/test_data_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_data_handlers.cpp @@ -17,8 +17,8 @@ #include #include -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/handlers/data_handlers.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/handlers/data_handlers.hpp" using json = nlohmann::json; using ros2_medkit_gateway::AuthConfig; diff --git a/src/ros2_medkit_gateway/test/test_default_script_provider.cpp b/src/ros2_medkit_gateway/test/test_default_script_provider.cpp index 9f73f1086..d6d93e926 100644 --- a/src/ros2_medkit_gateway/test/test_default_script_provider.cpp +++ b/src/ros2_medkit_gateway/test/test_default_script_provider.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/default_script_provider.hpp" +#include "ros2_medkit_gateway/core/default_script_provider.hpp" #include diff --git a/src/ros2_medkit_gateway/test/test_discovery_handlers.cpp b/src/ros2_medkit_gateway/test/test_discovery_handlers.cpp index a8a0bc077..bbc5a4386 100644 --- a/src/ros2_medkit_gateway/test/test_discovery_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_discovery_handlers.cpp @@ -31,8 +31,8 @@ #include #include +#include "ros2_medkit_gateway/core/http/handlers/discovery_handlers.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/handlers/discovery_handlers.hpp" using json = nlohmann::json; using ros2_medkit_gateway::AuthConfig; diff --git a/src/ros2_medkit_gateway/test/test_discovery_models.cpp b/src/ros2_medkit_gateway/test/test_discovery_models.cpp index 4d2c4a369..06fe0bb29 100644 --- a/src/ros2_medkit_gateway/test/test_discovery_models.cpp +++ b/src/ros2_medkit_gateway/test/test_discovery_models.cpp @@ -24,11 +24,11 @@ #include #include -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/common.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/common.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" using ros2_medkit_gateway::App; using ros2_medkit_gateway::Area; diff --git a/src/ros2_medkit_gateway/test/test_docs_handlers.cpp b/src/ros2_medkit_gateway/test/test_docs_handlers.cpp index 850d3e8a0..bb8bed121 100644 --- a/src/ros2_medkit_gateway/test/test_docs_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_docs_handlers.cpp @@ -21,9 +21,9 @@ #include #include -#include "ros2_medkit_gateway/config.hpp" +#include "ros2_medkit_gateway/core/config.hpp" +#include "ros2_medkit_gateway/core/http/handlers/docs_handlers.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/handlers/docs_handlers.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" #include "../src/openapi/route_registry.hpp" diff --git a/src/ros2_medkit_gateway/test/test_entity_change_scope.cpp b/src/ros2_medkit_gateway/test/test_entity_change_scope.cpp index e369e34cf..ae7a5b7c9 100644 --- a/src/ros2_medkit_gateway/test/test_entity_change_scope.cpp +++ b/src/ros2_medkit_gateway/test/test_entity_change_scope.cpp @@ -16,8 +16,8 @@ #include -#include "ros2_medkit_gateway/plugins/entity_change_scope.hpp" -#include "ros2_medkit_gateway/plugins/plugin_context.hpp" +#include "ros2_medkit_gateway/core/plugins/entity_change_scope.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_context.hpp" using ros2_medkit_gateway::EntityChangeScope; diff --git a/src/ros2_medkit_gateway/test/test_entity_merger.cpp b/src/ros2_medkit_gateway/test/test_entity_merger.cpp index 53d4813c9..b2265a0d9 100644 --- a/src/ros2_medkit_gateway/test/test_entity_merger.cpp +++ b/src/ros2_medkit_gateway/test/test_entity_merger.cpp @@ -20,7 +20,7 @@ #include #include -#include "ros2_medkit_gateway/aggregation/entity_merger.hpp" +#include "ros2_medkit_gateway/core/aggregation/entity_merger.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_entity_path_utils.cpp b/src/ros2_medkit_gateway/test/test_entity_path_utils.cpp index 027dc5668..e163b9ebc 100644 --- a/src/ros2_medkit_gateway/test/test_entity_path_utils.cpp +++ b/src/ros2_medkit_gateway/test/test_entity_path_utils.cpp @@ -14,7 +14,7 @@ #include -#include "ros2_medkit_gateway/http/entity_path_utils.hpp" +#include "ros2_medkit_gateway/core/http/entity_path_utils.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_entity_resource_model.cpp b/src/ros2_medkit_gateway/test/test_entity_resource_model.cpp index 30e522403..1f31b13a6 100644 --- a/src/ros2_medkit_gateway/test/test_entity_resource_model.cpp +++ b/src/ros2_medkit_gateway/test/test_entity_resource_model.cpp @@ -19,10 +19,10 @@ #include #include -#include "ros2_medkit_gateway/models/aggregation_service.hpp" -#include "ros2_medkit_gateway/models/entity_capabilities.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" -#include "ros2_medkit_gateway/models/thread_safe_entity_cache.hpp" +#include "ros2_medkit_gateway/core/models/aggregation_service.hpp" +#include "ros2_medkit_gateway/core/models/entity_capabilities.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp" using namespace ros2_medkit_gateway; using namespace std::chrono_literals; diff --git a/src/ros2_medkit_gateway/test/test_error_info.cpp b/src/ros2_medkit_gateway/test/test_error_info.cpp index cc8e4b30e..fe8d3ed66 100644 --- a/src/ros2_medkit_gateway/test/test_error_info.cpp +++ b/src/ros2_medkit_gateway/test/test_error_info.cpp @@ -16,8 +16,8 @@ #include -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/models/error_info.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/models/error_info.hpp" using ros2_medkit_gateway::ErrorInfo; diff --git a/src/ros2_medkit_gateway/test/test_fan_out_helpers.cpp b/src/ros2_medkit_gateway/test/test_fan_out_helpers.cpp index 14c8c8407..452cf1f34 100644 --- a/src/ros2_medkit_gateway/test/test_fan_out_helpers.cpp +++ b/src/ros2_medkit_gateway/test/test_fan_out_helpers.cpp @@ -23,7 +23,7 @@ #include #include -#include "ros2_medkit_gateway/http/fan_out_helpers.hpp" +#include "ros2_medkit_gateway/core/http/fan_out_helpers.hpp" using namespace ros2_medkit_gateway; // NOLINT(google-build-using-namespace) using nlohmann::json; diff --git a/src/ros2_medkit_gateway/test/test_fault_manager.cpp b/src/ros2_medkit_gateway/test/test_fault_manager.cpp index bc3aeb9f4..1126110bc 100644 --- a/src/ros2_medkit_gateway/test/test_fault_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_fault_manager.cpp @@ -24,9 +24,9 @@ #include #include +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" #include "ros2_medkit_gateway/fault_manager.hpp" #include "ros2_medkit_gateway/fault_manager_paths.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" #include "ros2_medkit_gateway/trigger_fault_subscriber.hpp" #include "ros2_medkit_msgs/msg/fault_event.hpp" #include "ros2_medkit_msgs/srv/get_rosbag.hpp" diff --git a/src/ros2_medkit_gateway/test/test_function_resource_collections.cpp b/src/ros2_medkit_gateway/test/test_function_resource_collections.cpp index 5bfc3eaa9..c64f3ca03 100644 --- a/src/ros2_medkit_gateway/test/test_function_resource_collections.cpp +++ b/src/ros2_medkit_gateway/test/test_function_resource_collections.cpp @@ -18,10 +18,10 @@ #include #include -#include "ros2_medkit_gateway/models/aggregation_service.hpp" -#include "ros2_medkit_gateway/models/entity_capabilities.hpp" -#include "ros2_medkit_gateway/models/entity_types.hpp" -#include "ros2_medkit_gateway/models/thread_safe_entity_cache.hpp" +#include "ros2_medkit_gateway/core/models/aggregation_service.hpp" +#include "ros2_medkit_gateway/core/models/entity_capabilities.hpp" +#include "ros2_medkit_gateway/core/models/entity_types.hpp" +#include "ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp" using namespace ros2_medkit_gateway; // nlohmann::json is already aliased as 'json' in the ros2_medkit_gateway namespace diff --git a/src/ros2_medkit_gateway/test/test_gateway_core_smoke.cpp b/src/ros2_medkit_gateway/test/test_gateway_core_smoke.cpp new file mode 100644 index 000000000..106ba80b3 --- /dev/null +++ b/src/ros2_medkit_gateway/test/test_gateway_core_smoke.cpp @@ -0,0 +1,79 @@ +// Copyright 2026 bburda +// +// 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. + +// Smoke test: this translation unit must compile and link against +// gateway_core alone, without any ament/rclcpp link dependency. Any ROS +// transitive include reaching the core layer would surface here as a +// missing-symbol link error, catching leaks the grep-based purity check +// might miss when an include is reached via a third-party header. + +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/providers/data_provider.hpp" +#include "ros2_medkit_gateway/core/providers/fault_provider.hpp" +#include "ros2_medkit_gateway/core/providers/host_info_provider.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" +#include "ros2_medkit_gateway/core/providers/log_provider.hpp" +#include "ros2_medkit_gateway/core/providers/operation_provider.hpp" +#include "ros2_medkit_gateway/core/providers/script_provider.hpp" +#include "ros2_medkit_gateway/core/providers/update_provider.hpp" + +#include + +#include + +namespace { + +// Reference each entity model and provider interface so the includes +// above are not flagged as unused. The translation unit must still link +// against gateway_core alone, which proves the neutral-layer contract. + +using ros2_medkit_gateway::App; +using ros2_medkit_gateway::Area; +using ros2_medkit_gateway::Component; +using ros2_medkit_gateway::DataProvider; +using ros2_medkit_gateway::FaultProvider; +using ros2_medkit_gateway::Function; +using ros2_medkit_gateway::HostInfoProvider; +using ros2_medkit_gateway::IntrospectionProvider; +using ros2_medkit_gateway::LogProvider; +using ros2_medkit_gateway::OperationProvider; +using ros2_medkit_gateway::ScriptProvider; +using ros2_medkit_gateway::UpdateProvider; + +static_assert(sizeof(Area) > 0); +static_assert(sizeof(Component) > 0); +static_assert(sizeof(App) > 0); +static_assert(sizeof(Function) > 0); +static_assert(std::is_abstract_v); +static_assert(std::is_abstract_v); +static_assert(std::is_abstract_v); +static_assert(std::is_abstract_v); +static_assert(std::is_abstract_v); +static_assert(std::is_abstract_v); +static_assert(std::is_abstract_v); +static_assert(sizeof(HostInfoProvider) > 0); + +} // namespace + +TEST(GatewayCoreSmoke, HeadersCompileAndLinkWithoutRos) { + // The mere fact that this translation unit compiles and links against + // gateway_core alone - with no ament_target_dependencies and no rclcpp + // on the link line - proves the neutral layer carries no ROS coupling. + // The static_asserts above pin the entity model and provider interface + // contracts so the includes are exercised at compile time. + SUCCEED(); +} diff --git a/src/ros2_medkit_gateway/test/test_gateway_node.cpp b/src/ros2_medkit_gateway/test/test_gateway_node.cpp index ea089ed21..f37078822 100644 --- a/src/ros2_medkit_gateway/test/test_gateway_node.cpp +++ b/src/ros2_medkit_gateway/test/test_gateway_node.cpp @@ -28,10 +28,10 @@ #include #include -#include "ros2_medkit_gateway/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" #include "ros2_medkit_gateway/fault_manager_paths.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" using namespace std::chrono_literals; diff --git a/src/ros2_medkit_gateway/test/test_handler_context.cpp b/src/ros2_medkit_gateway/test/test_handler_context.cpp index 7dd4e3de0..146676f85 100644 --- a/src/ros2_medkit_gateway/test/test_handler_context.cpp +++ b/src/ros2_medkit_gateway/test/test_handler_context.cpp @@ -27,19 +27,21 @@ #include #include "ros2_medkit_gateway/aggregation/aggregation_manager.hpp" -#include "ros2_medkit_gateway/config.hpp" -#include "ros2_medkit_gateway/discovery/models/app.hpp" -#include "ros2_medkit_gateway/discovery/models/area.hpp" -#include "ros2_medkit_gateway/discovery/models/component.hpp" -#include "ros2_medkit_gateway/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/config.hpp" +#include "ros2_medkit_gateway/core/discovery/models/app.hpp" +#include "ros2_medkit_gateway/core/discovery/models/area.hpp" +#include "ros2_medkit_gateway/core/discovery/models/component.hpp" +#include "ros2_medkit_gateway/core/discovery/models/function.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/models/thread_safe_entity_cache.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/models/thread_safe_entity_cache.hpp" using namespace ros2_medkit_gateway; using namespace ros2_medkit_gateway::handlers; -using json = nlohmann::json; +// json alias already imported via the `using namespace` above (defined in +// core/auth/auth_models.hpp). A local `using json = nlohmann::json;` would +// shadow it and trip clang-diagnostic-shadow under clang-tidy. // ============================================================================= // HandlerContext static method tests (don't require GatewayNode) diff --git a/src/ros2_medkit_gateway/test/test_health_handlers.cpp b/src/ros2_medkit_gateway/test/test_health_handlers.cpp index e226b76b7..c29688ab2 100644 --- a/src/ros2_medkit_gateway/test/test_health_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_health_handlers.cpp @@ -25,8 +25,8 @@ #include #include "../src/openapi/route_registry.hpp" +#include "ros2_medkit_gateway/core/http/handlers/health_handlers.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/handlers/health_handlers.hpp" using namespace std::chrono_literals; diff --git a/src/ros2_medkit_gateway/test/test_host_info_provider.cpp b/src/ros2_medkit_gateway/test/test_host_info_provider.cpp index 2f52c5ae0..4b74e48f1 100644 --- a/src/ros2_medkit_gateway/test/test_host_info_provider.cpp +++ b/src/ros2_medkit_gateway/test/test_host_info_provider.cpp @@ -22,7 +22,7 @@ #include #include -#include "ros2_medkit_gateway/discovery/host_info_provider.hpp" +#include "ros2_medkit_gateway/core/providers/host_info_provider.hpp" using ros2_medkit_gateway::HostInfoProvider; using ros2_medkit_gateway::json; diff --git a/src/ros2_medkit_gateway/test/test_lock_handlers.cpp b/src/ros2_medkit_gateway/test/test_lock_handlers.cpp index b1cff5245..8c564037d 100644 --- a/src/ros2_medkit_gateway/test/test_lock_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_lock_handlers.cpp @@ -28,11 +28,11 @@ #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/handlers/lock_handlers.hpp" +#include "ros2_medkit_gateway/core/http/http_utils.hpp" +#include "ros2_medkit_gateway/core/managers/lock_manager.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/handlers/lock_handlers.hpp" -#include "ros2_medkit_gateway/http/http_utils.hpp" -#include "ros2_medkit_gateway/lock_manager.hpp" using json = nlohmann::json; using ros2_medkit_gateway::AuthConfig; diff --git a/src/ros2_medkit_gateway/test/test_lock_manager.cpp b/src/ros2_medkit_gateway/test/test_lock_manager.cpp index c8a61b56a..fbb370faa 100644 --- a/src/ros2_medkit_gateway/test/test_lock_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_lock_manager.cpp @@ -18,7 +18,7 @@ #include #include -#include "ros2_medkit_gateway/lock_manager.hpp" +#include "ros2_medkit_gateway/core/managers/lock_manager.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_log_handlers.cpp b/src/ros2_medkit_gateway/test/test_log_handlers.cpp index e157633fc..b2fcf1595 100644 --- a/src/ros2_medkit_gateway/test/test_log_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_log_handlers.cpp @@ -16,8 +16,8 @@ #include -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/handlers/log_handlers.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/handlers/log_handlers.hpp" using json = nlohmann::json; using ros2_medkit_gateway::AuthConfig; diff --git a/src/ros2_medkit_gateway/test/test_log_manager.cpp b/src/ros2_medkit_gateway/test/test_log_manager.cpp index faa34d1c1..839a57093 100644 --- a/src/ros2_medkit_gateway/test/test_log_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_log_manager.cpp @@ -21,11 +21,11 @@ #include #include +#include "ros2_medkit_gateway/core/plugins/gateway_plugin.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/providers/log_provider.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" #include "ros2_medkit_gateway/log_manager.hpp" -#include "ros2_medkit_gateway/logs/log_provider.hpp" -#include "ros2_medkit_gateway/plugins/gateway_plugin.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" using json = nlohmann::json; using ros2_medkit_gateway::LogConfig; diff --git a/src/ros2_medkit_gateway/test/test_manifest_parser.cpp b/src/ros2_medkit_gateway/test/test_manifest_parser.cpp index 977ffb680..4bd075ed7 100644 --- a/src/ros2_medkit_gateway/test/test_manifest_parser.cpp +++ b/src/ros2_medkit_gateway/test/test_manifest_parser.cpp @@ -24,7 +24,7 @@ #include #include -#include "ros2_medkit_gateway/discovery/manifest/manifest_parser.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest_parser.hpp" using ros2_medkit_gateway::discovery::ManifestConfig; using ros2_medkit_gateway::discovery::ManifestParser; diff --git a/src/ros2_medkit_gateway/test/test_manifest_validator.cpp b/src/ros2_medkit_gateway/test/test_manifest_validator.cpp index 5a1e69ccb..bb8d61def 100644 --- a/src/ros2_medkit_gateway/test/test_manifest_validator.cpp +++ b/src/ros2_medkit_gateway/test/test_manifest_validator.cpp @@ -23,8 +23,8 @@ #include -#include "ros2_medkit_gateway/discovery/manifest/manifest_parser.hpp" -#include "ros2_medkit_gateway/discovery/manifest/manifest_validator.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest_parser.hpp" +#include "ros2_medkit_gateway/core/discovery/manifest/manifest_validator.hpp" using ros2_medkit_gateway::discovery::ManifestParser; using ros2_medkit_gateway::discovery::ManifestValidator; diff --git a/src/ros2_medkit_gateway/test/test_mdns_discovery.cpp b/src/ros2_medkit_gateway/test/test_mdns_discovery.cpp index 770f0f73d..13c07f15e 100644 --- a/src/ros2_medkit_gateway/test/test_mdns_discovery.cpp +++ b/src/ros2_medkit_gateway/test/test_mdns_discovery.cpp @@ -18,7 +18,7 @@ #include #include -#include "ros2_medkit_gateway/aggregation/mdns_discovery.hpp" +#include "ros2_medkit_gateway/core/aggregation/mdns_discovery.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_merge_pipeline.cpp b/src/ros2_medkit_gateway/test/test_merge_pipeline.cpp index 882a93cb5..b6c7c5212 100644 --- a/src/ros2_medkit_gateway/test/test_merge_pipeline.cpp +++ b/src/ros2_medkit_gateway/test/test_merge_pipeline.cpp @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/discovery_layer.hpp" -#include "ros2_medkit_gateway/discovery/layers/manifest_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/discovery_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/layers/manifest_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/layers/runtime_layer.hpp" +#include "ros2_medkit_gateway/core/discovery/merge_types.hpp" #include "ros2_medkit_gateway/discovery/layers/plugin_layer.hpp" -#include "ros2_medkit_gateway/discovery/layers/runtime_layer.hpp" #include "ros2_medkit_gateway/discovery/manifest/runtime_linker.hpp" #include "ros2_medkit_gateway/discovery/merge_pipeline.hpp" -#include "ros2_medkit_gateway/discovery/merge_types.hpp" #include diff --git a/src/ros2_medkit_gateway/test/test_network_utils.cpp b/src/ros2_medkit_gateway/test/test_network_utils.cpp index 13f01cf5e..fc317e28d 100644 --- a/src/ros2_medkit_gateway/test/test_network_utils.cpp +++ b/src/ros2_medkit_gateway/test/test_network_utils.cpp @@ -16,7 +16,7 @@ #include -#include "ros2_medkit_gateway/aggregation/network_utils.hpp" +#include "ros2_medkit_gateway/core/aggregation/network_utils.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_operation_handlers.cpp b/src/ros2_medkit_gateway/test/test_operation_handlers.cpp index 040b73a18..95eb0cf8d 100644 --- a/src/ros2_medkit_gateway/test/test_operation_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_operation_handlers.cpp @@ -36,9 +36,9 @@ #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/handlers/operation_handlers.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/handlers/operation_handlers.hpp" using json = nlohmann::json; using ros2_medkit_gateway::ActionGoalInfo; diff --git a/src/ros2_medkit_gateway/test/test_peer_client.cpp b/src/ros2_medkit_gateway/test/test_peer_client.cpp index dd03112a7..e5bd2e887 100644 --- a/src/ros2_medkit_gateway/test/test_peer_client.cpp +++ b/src/ros2_medkit_gateway/test/test_peer_client.cpp @@ -18,7 +18,7 @@ #include #include -#include "ros2_medkit_gateway/aggregation/peer_client.hpp" +#include "ros2_medkit_gateway/core/aggregation/peer_client.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_plugin_entity_routing.cpp b/src/ros2_medkit_gateway/test/test_plugin_entity_routing.cpp index e58c02653..b3254abfc 100644 --- a/src/ros2_medkit_gateway/test/test_plugin_entity_routing.cpp +++ b/src/ros2_medkit_gateway/test/test_plugin_entity_routing.cpp @@ -14,10 +14,10 @@ #include -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/providers/data_provider.hpp" -#include "ros2_medkit_gateway/providers/fault_provider.hpp" -#include "ros2_medkit_gateway/providers/operation_provider.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/providers/data_provider.hpp" +#include "ros2_medkit_gateway/core/providers/fault_provider.hpp" +#include "ros2_medkit_gateway/core/providers/operation_provider.hpp" using namespace ros2_medkit_gateway; // json alias already available via ros2_medkit_gateway namespace headers diff --git a/src/ros2_medkit_gateway/test/test_plugin_http_types.cpp b/src/ros2_medkit_gateway/test/test_plugin_http_types.cpp index 0c97e76b3..a9eb6c02c 100644 --- a/src/ros2_medkit_gateway/test/test_plugin_http_types.cpp +++ b/src/ros2_medkit_gateway/test/test_plugin_http_types.cpp @@ -18,8 +18,8 @@ #include #include +#include "ros2_medkit_gateway/core/plugins/plugin_http_types.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" -#include "ros2_medkit_gateway/plugins/plugin_http_types.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_plugin_loader.cpp b/src/ros2_medkit_gateway/test/test_plugin_loader.cpp index 4ebae86cb..8dc4e3935 100644 --- a/src/ros2_medkit_gateway/test/test_plugin_loader.cpp +++ b/src/ros2_medkit_gateway/test/test_plugin_loader.cpp @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ros2_medkit_gateway/discovery/introspection_provider.hpp" -#include "ros2_medkit_gateway/plugins/plugin_loader.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" -#include "ros2_medkit_gateway/updates/update_provider.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_loader.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" +#include "ros2_medkit_gateway/core/providers/update_provider.hpp" #include diff --git a/src/ros2_medkit_gateway/test/test_plugin_manager.cpp b/src/ros2_medkit_gateway/test/test_plugin_manager.cpp index a42313dc1..1943a914c 100644 --- a/src/ros2_medkit_gateway/test/test_plugin_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_plugin_manager.cpp @@ -19,9 +19,9 @@ #include #include -#include "ros2_medkit_gateway/discovery/introspection_provider.hpp" -#include "ros2_medkit_gateway/plugins/plugin_context.hpp" -#include "ros2_medkit_gateway/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_context.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_manager.hpp" +#include "ros2_medkit_gateway/core/providers/introspection_provider.hpp" using namespace ros2_medkit_gateway; // json alias is already imported by the `using namespace` above (defined in @@ -43,30 +43,33 @@ class MockPlugin : public GatewayPlugin, public UpdateProvider, public Introspec } // UpdateProvider - tl::expected, UpdateBackendErrorInfo> list_updates(const UpdateFilter &) override { + tl::expected, UpdateBackendErrorInfo> + list_updates(const UpdateFilter & /*filter*/) override { return std::vector{}; } - tl::expected get_update(const std::string &) override { + tl::expected get_update(const std::string & /*id*/) override { return tl::make_unexpected(UpdateBackendErrorInfo{UpdateBackendError::NotFound, "mock"}); } - tl::expected register_update(const json &) override { + tl::expected register_update(const json & /*metadata*/) override { return {}; } - tl::expected delete_update(const std::string &) override { + tl::expected delete_update(const std::string & /*id*/) override { return {}; } - tl::expected prepare(const std::string &, UpdateProgressReporter &) override { + tl::expected prepare(const std::string & /*id*/, + UpdateProgressReporter & /*reporter*/) override { return {}; } - tl::expected execute(const std::string &, UpdateProgressReporter &) override { + tl::expected execute(const std::string & /*id*/, + UpdateProgressReporter & /*reporter*/) override { return {}; } - tl::expected supports_automated(const std::string &) override { + tl::expected supports_automated(const std::string & /*id*/) override { return false; } // IntrospectionProvider - IntrospectionResult introspect(const IntrospectionInput &) override { + IntrospectionResult introspect(const IntrospectionInput & /*input*/) override { return {}; } @@ -81,9 +84,9 @@ class MockIntrospectionOnly : public GatewayPlugin, public IntrospectionProvider std::string name() const override { return "introspection_only"; } - void configure(const json &) override { + void configure(const json & /*cfg*/) override { } - IntrospectionResult introspect(const IntrospectionInput &) override { + IntrospectionResult introspect(const IntrospectionInput & /*input*/) override { return {}; } }; @@ -94,7 +97,7 @@ class MockThrowingPlugin : public GatewayPlugin { std::string name() const override { return "throwing"; } - void configure(const json &) override { + void configure(const json & /*cfg*/) override { throw std::runtime_error("configure failed"); } }; @@ -105,31 +108,34 @@ class MockThrowOnSetContext : public GatewayPlugin, public UpdateProvider { std::string name() const override { return "throw_set_context"; } - void configure(const json &) override { + void configure(const json & /*cfg*/) override { } - void set_context(PluginContext &) override { + void set_context(PluginContext & /*ctx*/) override { throw std::runtime_error("set_context failed"); } - tl::expected, UpdateBackendErrorInfo> list_updates(const UpdateFilter &) override { + tl::expected, UpdateBackendErrorInfo> + list_updates(const UpdateFilter & /*filter*/) override { return std::vector{}; } - tl::expected get_update(const std::string &) override { + tl::expected get_update(const std::string & /*id*/) override { return json::object(); } - tl::expected register_update(const json &) override { + tl::expected register_update(const json & /*metadata*/) override { return {}; } - tl::expected delete_update(const std::string &) override { + tl::expected delete_update(const std::string & /*id*/) override { return {}; } - tl::expected prepare(const std::string &, UpdateProgressReporter &) override { + tl::expected prepare(const std::string & /*id*/, + UpdateProgressReporter & /*reporter*/) override { return {}; } - tl::expected execute(const std::string &, UpdateProgressReporter &) override { + tl::expected execute(const std::string & /*id*/, + UpdateProgressReporter & /*reporter*/) override { return {}; } - tl::expected supports_automated(const std::string &) override { + tl::expected supports_automated(const std::string & /*id*/) override { return false; } }; @@ -140,7 +146,7 @@ class MockRoutePlugin : public GatewayPlugin { std::string name() const override { return "mock_route"; } - void configure(const json &) override { + void configure(const json & /*cfg*/) override { } std::vector get_routes() override { return { @@ -160,13 +166,13 @@ class MockThrowOnGetRoutes : public GatewayPlugin, public IntrospectionProvider std::string name() const override { return "throw_get_routes"; } - void configure(const json &) override { + void configure(const json & /*cfg*/) override { } std::vector get_routes() override { throw std::runtime_error("get_routes failed"); } - IntrospectionResult introspect(const IntrospectionInput &) override { + IntrospectionResult introspect(const IntrospectionInput & /*input*/) override { return {}; } }; @@ -177,7 +183,7 @@ class MockThrowOnShutdown : public GatewayPlugin { std::string name() const override { return "throw_shutdown"; } - void configure(const json &) override { + void configure(const json & /*cfg*/) override { } void shutdown() override { throw std::runtime_error("shutdown failed"); @@ -402,6 +408,7 @@ TEST(PluginManagerConcurrencyTest, ConcurrentReadsDoNotBlock) { std::atomic completed{0}; std::vector readers; + readers.reserve(8); for (int i = 0; i < 8; ++i) { readers.emplace_back([&mgr, &completed] { @@ -445,6 +452,7 @@ TEST(PluginManagerConcurrencyTest, ConcurrentReadsAndLifecycleDoNotDeadlock) { // Multiple reader threads (simulating ROS 2 executor calling get_log_observers) std::vector readers; + readers.reserve(4); for (int i = 0; i < 4; ++i) { readers.emplace_back([&mgr, &keep_running, &read_count] { while (keep_running) { @@ -488,6 +496,7 @@ TEST(PluginManagerConcurrencyTest, ShutdownWhileReadersActiveDoesNotDeadlock) { std::atomic read_count{0}; std::vector readers; + readers.reserve(4); for (int i = 0; i < 4; ++i) { readers.emplace_back([&mgr, &keep_running, &read_count] { while (keep_running) { diff --git a/src/ros2_medkit_gateway/test/test_plugin_notify_integration.cpp b/src/ros2_medkit_gateway/test/test_plugin_notify_integration.cpp index ad935932e..5fb00cd15 100644 --- a/src/ros2_medkit_gateway/test/test_plugin_notify_integration.cpp +++ b/src/ros2_medkit_gateway/test/test_plugin_notify_integration.cpp @@ -41,11 +41,11 @@ #include #include +#include "ros2_medkit_gateway/core/plugins/entity_change_scope.hpp" +#include "ros2_medkit_gateway/core/plugins/plugin_context.hpp" #include "ros2_medkit_gateway/discovery/discovery_manager.hpp" #include "ros2_medkit_gateway/discovery/manifest/manifest_manager.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/plugins/entity_change_scope.hpp" -#include "ros2_medkit_gateway/plugins/plugin_context.hpp" using namespace std::chrono_literals; diff --git a/src/ros2_medkit_gateway/test/test_rate_limiter.cpp b/src/ros2_medkit_gateway/test/test_rate_limiter.cpp index e94f51b5f..f2d2b505d 100644 --- a/src/ros2_medkit_gateway/test/test_rate_limiter.cpp +++ b/src/ros2_medkit_gateway/test/test_rate_limiter.cpp @@ -17,7 +17,7 @@ #include #include -#include "ros2_medkit_gateway/http/rate_limiter.hpp" +#include "ros2_medkit_gateway/core/http/rate_limiter.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_resource_change_notifier.cpp b/src/ros2_medkit_gateway/test/test_resource_change_notifier.cpp index 90d7ed7a4..ab7f40231 100644 --- a/src/ros2_medkit_gateway/test/test_resource_change_notifier.cpp +++ b/src/ros2_medkit_gateway/test/test_resource_change_notifier.cpp @@ -26,7 +26,7 @@ #include -#include "ros2_medkit_gateway/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_resource_sampler_registry.cpp b/src/ros2_medkit_gateway/test/test_resource_sampler_registry.cpp index ff9c2d1b5..3cb4232e4 100644 --- a/src/ros2_medkit_gateway/test/test_resource_sampler_registry.cpp +++ b/src/ros2_medkit_gateway/test/test_resource_sampler_registry.cpp @@ -17,7 +17,7 @@ #include #include -#include "ros2_medkit_gateway/resource_sampler.hpp" +#include "ros2_medkit_gateway/core/resource_sampler.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_ros2_topic_data_provider.cpp b/src/ros2_medkit_gateway/test/test_ros2_topic_data_provider.cpp index 62fc84927..f6ae84149 100644 --- a/src/ros2_medkit_gateway/test/test_ros2_topic_data_provider.cpp +++ b/src/ros2_medkit_gateway/test/test_ros2_topic_data_provider.cpp @@ -22,8 +22,8 @@ #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" #include "ros2_medkit_gateway/data/ros2_topic_data_provider.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" #include "ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp" #include "ros2_medkit_serialization/json_serializer.hpp" diff --git a/src/ros2_medkit_gateway/test/test_route_descriptions.cpp b/src/ros2_medkit_gateway/test/test_route_descriptions.cpp index 85f49ee3b..766ec5ff2 100644 --- a/src/ros2_medkit_gateway/test/test_route_descriptions.cpp +++ b/src/ros2_medkit_gateway/test/test_route_descriptions.cpp @@ -14,7 +14,7 @@ #include -#include "ros2_medkit_gateway/openapi/route_descriptions.hpp" +#include "ros2_medkit_gateway/core/openapi/route_descriptions.hpp" using namespace ros2_medkit_gateway::openapi; diff --git a/src/ros2_medkit_gateway/test/test_script_handlers.cpp b/src/ros2_medkit_gateway/test/test_script_handlers.cpp index 8472ae0f9..b22f66587 100644 --- a/src/ros2_medkit_gateway/test/test_script_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_script_handlers.cpp @@ -22,9 +22,9 @@ #include #include +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/handlers/script_handlers.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/handlers/script_handlers.hpp" using json = nlohmann::json; using ros2_medkit_gateway::AuthConfig; diff --git a/src/ros2_medkit_gateway/test/test_script_manager.cpp b/src/ros2_medkit_gateway/test/test_script_manager.cpp index 73931aac8..6c8f70946 100644 --- a/src/ros2_medkit_gateway/test/test_script_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_script_manager.cpp @@ -14,8 +14,8 @@ #include -#include "ros2_medkit_gateway/script_manager.hpp" -#include "ros2_medkit_gateway/scripts/script_provider.hpp" +#include "ros2_medkit_gateway/core/managers/script_manager.hpp" +#include "ros2_medkit_gateway/core/providers/script_provider.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_sse_fault_handler.cpp b/src/ros2_medkit_gateway/test/test_sse_fault_handler.cpp index 894badced..c840651b6 100644 --- a/src/ros2_medkit_gateway/test/test_sse_fault_handler.cpp +++ b/src/ros2_medkit_gateway/test/test_sse_fault_handler.cpp @@ -27,12 +27,12 @@ #include #include -#include "ros2_medkit_gateway/config.hpp" +#include "ros2_medkit_gateway/core/config.hpp" +#include "ros2_medkit_gateway/core/http/sse_client_tracker.hpp" #include "ros2_medkit_gateway/fault_manager_paths.hpp" #include "ros2_medkit_gateway/gateway_node.hpp" #include "ros2_medkit_gateway/http/handlers/handler_context.hpp" #include "ros2_medkit_gateway/http/handlers/sse_fault_handler.hpp" -#include "ros2_medkit_gateway/http/sse_client_tracker.hpp" #include "ros2_medkit_msgs/msg/fault_event.hpp" using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/test/test_sse_transport_provider.cpp b/src/ros2_medkit_gateway/test/test_sse_transport_provider.cpp index 38b14ea22..af4b05cb0 100644 --- a/src/ros2_medkit_gateway/test/test_sse_transport_provider.cpp +++ b/src/ros2_medkit_gateway/test/test_sse_transport_provider.cpp @@ -16,8 +16,8 @@ #include -#include "ros2_medkit_gateway/http/handlers/sse_transport_provider.hpp" -#include "ros2_medkit_gateway/subscription_manager.hpp" +#include "ros2_medkit_gateway/core/http/handlers/sse_transport_provider.hpp" +#include "ros2_medkit_gateway/core/managers/subscription_manager.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_stream_proxy.cpp b/src/ros2_medkit_gateway/test/test_stream_proxy.cpp index 70bf6175a..d5c9f9fbc 100644 --- a/src/ros2_medkit_gateway/test/test_stream_proxy.cpp +++ b/src/ros2_medkit_gateway/test/test_stream_proxy.cpp @@ -17,7 +17,7 @@ #include #include -#include "ros2_medkit_gateway/aggregation/stream_proxy.hpp" +#include "ros2_medkit_gateway/core/aggregation/stream_proxy.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_subscription_manager.cpp b/src/ros2_medkit_gateway/test/test_subscription_manager.cpp index dc4f1220c..4ed1da5cc 100644 --- a/src/ros2_medkit_gateway/test/test_subscription_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_subscription_manager.cpp @@ -18,7 +18,7 @@ #include #include -#include "ros2_medkit_gateway/subscription_manager.hpp" +#include "ros2_medkit_gateway/core/managers/subscription_manager.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_tls_config.cpp b/src/ros2_medkit_gateway/test/test_tls_config.cpp index 793c574a9..4eba1c9eb 100644 --- a/src/ros2_medkit_gateway/test/test_tls_config.cpp +++ b/src/ros2_medkit_gateway/test/test_tls_config.cpp @@ -20,7 +20,7 @@ #include #include -#include "ros2_medkit_gateway/config.hpp" +#include "ros2_medkit_gateway/core/config.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_topic_data_provider_interface.cpp b/src/ros2_medkit_gateway/test/test_topic_data_provider_interface.cpp index 40b25dfd4..d16bd5bbf 100644 --- a/src/ros2_medkit_gateway/test/test_topic_data_provider_interface.cpp +++ b/src/ros2_medkit_gateway/test/test_topic_data_provider_interface.cpp @@ -21,7 +21,7 @@ #include #include -#include "ros2_medkit_gateway/data/topic_data_provider.hpp" +#include "ros2_medkit_gateway/core/data/topic_data_provider.hpp" using ros2_medkit_gateway::ComponentTopics; using ros2_medkit_gateway::ErrorInfo; diff --git a/src/ros2_medkit_gateway/test/test_transport_registry.cpp b/src/ros2_medkit_gateway/test/test_transport_registry.cpp index 4701ae1a6..3f8994fc7 100644 --- a/src/ros2_medkit_gateway/test/test_transport_registry.cpp +++ b/src/ros2_medkit_gateway/test/test_transport_registry.cpp @@ -18,7 +18,7 @@ #include #include -#include "ros2_medkit_gateway/subscription_transport.hpp" +#include "ros2_medkit_gateway/core/subscription_transport.hpp" using namespace ros2_medkit_gateway; diff --git a/src/ros2_medkit_gateway/test/test_trigger_handlers.cpp b/src/ros2_medkit_gateway/test/test_trigger_handlers.cpp index fa77eb63a..7e89e427b 100644 --- a/src/ros2_medkit_gateway/test/test_trigger_handlers.cpp +++ b/src/ros2_medkit_gateway/test/test_trigger_handlers.cpp @@ -18,8 +18,8 @@ #include #include -#include "ros2_medkit_gateway/http/error_codes.hpp" -#include "ros2_medkit_gateway/http/handlers/trigger_handlers.hpp" +#include "ros2_medkit_gateway/core/http/error_codes.hpp" +#include "ros2_medkit_gateway/core/http/handlers/trigger_handlers.hpp" using namespace ros2_medkit_gateway; using namespace ros2_medkit_gateway::handlers; diff --git a/src/ros2_medkit_gateway/test/test_trigger_manager.cpp b/src/ros2_medkit_gateway/test/test_trigger_manager.cpp index 3c36e28ad..04203954d 100644 --- a/src/ros2_medkit_gateway/test/test_trigger_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_trigger_manager.cpp @@ -20,10 +20,10 @@ #include #include -#include "ros2_medkit_gateway/condition_evaluator.hpp" -#include "ros2_medkit_gateway/resource_change_notifier.hpp" -#include "ros2_medkit_gateway/sqlite_trigger_store.hpp" -#include "ros2_medkit_gateway/trigger_manager.hpp" +#include "ros2_medkit_gateway/core/condition_evaluator.hpp" +#include "ros2_medkit_gateway/core/managers/trigger_manager.hpp" +#include "ros2_medkit_gateway/core/resource_change_notifier.hpp" +#include "ros2_medkit_gateway/core/sqlite_trigger_store.hpp" using namespace ros2_medkit_gateway; using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/test/test_trigger_store.cpp b/src/ros2_medkit_gateway/test/test_trigger_store.cpp index 3b1930888..40e8322cf 100644 --- a/src/ros2_medkit_gateway/test/test_trigger_store.cpp +++ b/src/ros2_medkit_gateway/test/test_trigger_store.cpp @@ -19,7 +19,7 @@ #include #include -#include "ros2_medkit_gateway/sqlite_trigger_store.hpp" +#include "ros2_medkit_gateway/core/sqlite_trigger_store.hpp" using namespace ros2_medkit_gateway; using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/test/test_update_manager.cpp b/src/ros2_medkit_gateway/test/test_update_manager.cpp index f2e619c68..cd656298b 100644 --- a/src/ros2_medkit_gateway/test/test_update_manager.cpp +++ b/src/ros2_medkit_gateway/test/test_update_manager.cpp @@ -17,7 +17,7 @@ #include #include -#include "ros2_medkit_gateway/updates/update_manager.hpp" +#include "ros2_medkit_gateway/core/managers/update_manager.hpp" using namespace ros2_medkit_gateway; using json = nlohmann::json; diff --git a/src/ros2_medkit_gateway/test/test_x_medkit.cpp b/src/ros2_medkit_gateway/test/test_x_medkit.cpp index 1ef38f462..128ee41c2 100644 --- a/src/ros2_medkit_gateway/test/test_x_medkit.cpp +++ b/src/ros2_medkit_gateway/test/test_x_medkit.cpp @@ -14,7 +14,7 @@ #include -#include "ros2_medkit_gateway/http/x_medkit.hpp" +#include "ros2_medkit_gateway/core/http/x_medkit.hpp" using ros2_medkit_gateway::XMedkit; using json = nlohmann::json; diff --git a/src/ros2_medkit_integration_tests/test/features/test_combined_introspection.test.py b/src/ros2_medkit_integration_tests/test/features/test_combined_introspection.test.py index 11c6c7b97..025b0a98d 100644 --- a/src/ros2_medkit_integration_tests/test/features/test_combined_introspection.test.py +++ b/src/ros2_medkit_integration_tests/test/features/test_combined_introspection.test.py @@ -74,24 +74,34 @@ def _get_any_app_id(self): return items[0]['id'] def _poll_procfs_app(self, app_id, timeout=20.0): - """Poll procfs endpoint until it returns valid data.""" + """Poll procfs endpoint until rss_bytes is populated. + + A freshly forked process can show RssAnon=0 in /proc//status + before any memory is touched, so a 200 response alone is not + sufficient - wait until rss_bytes > 0 to avoid a timing race + between process spawn and the first procfs sample. + """ start = time.monotonic() last_status = None + last_rss = None while time.monotonic() - start < timeout: try: r = requests.get( f'{self.BASE_URL}/apps/{app_id}/x-medkit-procfs', - timeout=5, + timeout=2, ) last_status = r.status_code if r.status_code == 200: - return r.json() + data = r.json() + last_rss = data.get('rss_bytes') + if last_rss and last_rss > 0: + return data except requests.exceptions.RequestException: pass time.sleep(1.0) self.fail( f'Procfs data not available for app {app_id} after {timeout}s ' - f'(last status: {last_status})' + f'(last status: {last_status}, last rss_bytes: {last_rss})' ) def _poll_container_app(self, app_id, timeout=20.0): diff --git a/src/ros2_medkit_plugins/ros2_medkit_graph_provider/CMakeLists.txt b/src/ros2_medkit_plugins/ros2_medkit_graph_provider/CMakeLists.txt index 7129048e5..4b585fc6a 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_graph_provider/CMakeLists.txt +++ b/src/ros2_medkit_plugins/ros2_medkit_graph_provider/CMakeLists.txt @@ -32,7 +32,8 @@ find_package(rclcpp REQUIRED) find_package(diagnostic_msgs REQUIRED) find_package(nlohmann_json REQUIRED) # MODULE target: loaded via dlopen at runtime by PluginManager. -# Symbols from gateway_lib are resolved from the host process at runtime. +# Symbols from gateway_ros2 (and gateway_core transitively) are resolved +# from the host process at runtime. # We only need headers at compile time (via medkit_target_dependencies). add_library(ros2_medkit_graph_provider_plugin MODULE src/graph_provider_plugin.cpp diff --git a/src/ros2_medkit_plugins/ros2_medkit_graph_provider/test/test_graph_provider_plugin.cpp b/src/ros2_medkit_plugins/ros2_medkit_graph_provider/test/test_graph_provider_plugin.cpp index 9d09edd9f..319dd9822 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_graph_provider/test/test_graph_provider_plugin.cpp +++ b/src/ros2_medkit_plugins/ros2_medkit_graph_provider/test/test_graph_provider_plugin.cpp @@ -39,7 +39,7 @@ using namespace std::chrono_literals; using namespace ros2_medkit_gateway; -// Stubs for PluginRequest/PluginResponse (implemented in gateway_lib, not linked into tests). +// Stubs for PluginRequest/PluginResponse (implemented in gateway_core, not linked into tests). // These wrap httplib::Request/Response directly so the route tests can use a real HTTP server. namespace ros2_medkit_gateway { diff --git a/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/CMakeLists.txt b/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/CMakeLists.txt index df09dc63d..913363aa0 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/CMakeLists.txt +++ b/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/CMakeLists.txt @@ -33,7 +33,8 @@ find_package(rclcpp REQUIRED) find_package(nlohmann_json REQUIRED) # MODULE target: loaded via dlopen at runtime by PluginManager. -# Symbols from gateway_lib are resolved from the host process at runtime. +# Symbols from gateway_ros2 (and gateway_core transitively) are resolved +# from the host process at runtime. add_library(sovd_service_interface MODULE src/sovd_service_interface.cpp src/service_exports.cpp diff --git a/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/test/test_sovd_service_interface.cpp b/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/test/test_sovd_service_interface.cpp index ab2f4d8cc..15d76ec25 100644 --- a/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/test/test_sovd_service_interface.cpp +++ b/src/ros2_medkit_plugins/ros2_medkit_sovd_service_interface/test/test_sovd_service_interface.cpp @@ -33,7 +33,7 @@ using namespace ros2_medkit_gateway; -// Stubs for PluginRequest/PluginResponse (defined in gateway_lib, not linked into plugin tests) +// Stubs for PluginRequest/PluginResponse (defined in gateway_core, not linked into plugin tests) namespace ros2_medkit_gateway { PluginRequest::PluginRequest(const void * impl) : impl_(impl) { } diff --git a/src/ros2_medkit_serialization/CMakeLists.txt b/src/ros2_medkit_serialization/CMakeLists.txt index 133267077..3c2bd8b5d 100644 --- a/src/ros2_medkit_serialization/CMakeLists.txt +++ b/src/ros2_medkit_serialization/CMakeLists.txt @@ -61,7 +61,7 @@ set_source_files_properties( ) # Enable PIC so this static library can be linked into shared objects -# (e.g. test_gateway_plugin.so via gateway_lib.a) +# (e.g. test_gateway_plugin.so via gateway_core.a / gateway_ros2.a) set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) target_include_directories(${PROJECT_NAME} PUBLIC