ros2_medkit_beacon_common ========================== This section contains design documentation for the ros2_medkit_beacon_common library. Overview -------- The ``ros2_medkit_beacon_common`` package is a shared C++ library used by the beacon discovery plugins (``ros2_medkit_topic_beacon`` and ``ros2_medkit_param_beacon``). It provides the data model, hint storage, entity mapping, validation, and response building that both beacon transports rely on. It is not a plugin itself - it is linked as a static library by the two beacon plugin packages. Architecture ------------ The following diagram shows the beacon common components and their relationships. .. plantuml:: :caption: Beacon Common Library Architecture @startuml ros2_medkit_beacon_common_architecture skinparam linetype ortho skinparam classAttributeIconSize 0 title Beacon Common - Library Architecture package "ros2_medkit_gateway" { interface IntrospectionProvider { +introspect(input): IntrospectionResult } class IntrospectionInput { +areas: vector +components: vector +apps: vector +functions: vector } class IntrospectionResult { +metadata: map +new_entities: NewEntities } } package "ros2_medkit_beacon_common" { class BeaconHint { + entity_id: string + stable_id: string + display_name: string + function_ids: vector + depends_on: vector + component_id: string + transport_type: string + negotiated_format: string + process_id: uint32 + process_name: string + hostname: string + metadata: map + received_at: time_point } class BeaconHintStore { - hints_: map - config_: Config - mutex_: shared_mutex -- + update(hint): bool + evict_and_snapshot(): vector + get(entity_id): optional + size(): size_t } class BeaconEntityMapper { - config_: Config -- + map(hints, current): IntrospectionResult -- - build_metadata(hint): json - apply_function_membership() } class BeaconValidator <> { + {static} validate_beacon_hint(hint, limits): ValidationResult } class BeaconResponseBuilder <> { + {static} build_beacon_response(id, stored): json } class "BeaconHintStore::Config" as StoreConfig { + beacon_ttl_sec: double = 10.0 + beacon_expiry_sec: double = 300.0 + max_hints: size_t = 10000 } class ValidationLimits { + max_id_length: 256 + max_string_length: 512 + max_function_ids: 100 + max_metadata_entries: 50 } enum HintStatus { ACTIVE STALE EXPIRED } } BeaconHintStore o--> BeaconHint : stores BeaconHintStore --> HintStatus : computes BeaconHintStore --> StoreConfig : configured by BeaconEntityMapper --> BeaconHintStore : reads snapshots BeaconEntityMapper ..> IntrospectionResult : produces BeaconEntityMapper ..> IntrospectionInput : reads BeaconValidator --> BeaconHint : validates BeaconResponseBuilder --> BeaconHintStore : reads @enduml Main Components --------------- 1. **BeaconHint** - Core data structure representing a discovery hint from a ROS 2 node - ``entity_id`` is the only required field (identifies the app) - Identity fields: ``stable_id``, ``display_name`` for human-readable labeling - Topology fields: ``function_ids``, ``depends_on``, ``component_id`` for entity relationships - Transport fields: ``transport_type``, ``negotiated_format`` for DDS introspection - Process fields: ``process_id``, ``process_name``, ``hostname`` for runtime context - ``metadata`` map for arbitrary key-value pairs - ``received_at`` timestamp in steady_clock domain for TTL computation 2. **BeaconHintStore** - Thread-safe TTL-based storage for beacon hints - ``update()`` inserts or refreshes a hint; returns false if capacity is full for new entity IDs - ``evict_and_snapshot()`` atomically removes expired hints and returns a consistent snapshot - Three-state lifecycle: ACTIVE (within TTL), STALE (past TTL but before expiry), EXPIRED (evicted) - Configurable: TTL (default 10s), expiry (default 300s), max capacity (default 10,000 hints) - Protected by ``std::shared_mutex`` for concurrent reads during ``get()`` 3. **BeaconEntityMapper** - Maps stored hints to gateway IntrospectionResult - Takes a snapshot from ``BeaconHintStore`` and the current ``IntrospectionInput`` - Builds per-entity metadata JSON from hint fields - Applies function membership: if a hint declares ``function_ids``, the mapper updates the corresponding Function entities' host lists - Optionally allows new entity creation (``allow_new_entities`` config flag) 4. **BeaconValidator** - Input sanitization for incoming beacon hints - Validates ``entity_id`` format (required, max length, allowed characters) - Truncates oversized string fields rather than rejecting the entire hint - Enforces limits on collection sizes (function_ids, depends_on, metadata entries) - Returns ``valid=false`` only when ``entity_id`` itself is invalid 5. **BeaconResponseBuilder** - Builds JSON responses for beacon metadata HTTP endpoints - Constructs the response payload served by ``x-medkit-beacon`` vendor extension endpoints - Includes hint data plus status (active/stale) and last-seen timestamp Design Decisions ---------------- Shared Library, Not Plugin ~~~~~~~~~~~~~~~~~~~~~~~~~~ The beacon common code is a static library linked into the topic and parameter beacon plugins, not a standalone plugin. This avoids an extra shared library load at runtime while keeping the transport-specific logic (topic subscription vs. parameter polling) in separate plugin ``.so`` files. Three-State Hint Lifecycle ~~~~~~~~~~~~~~~~~~~~~~~~~~ Hints transition through ACTIVE, STALE, and EXPIRED states rather than using a simple present/absent model. The STALE state allows the gateway to report that a node was recently seen but is no longer actively sending beacons - useful for distinguishing temporary network hiccups from actual node departures. Capacity Limits ~~~~~~~~~~~~~~~ The store enforces a hard cap on the number of tracked hints (default 10,000) to prevent memory exhaustion from misbehaving nodes or DDoS scenarios. When capacity is reached, new entity IDs are rejected while existing hints can still be refreshed. Validation Strategy ~~~~~~~~~~~~~~~~~~~ The validator is lenient by design: only an invalid ``entity_id`` causes rejection. Other fields are sanitized (truncated, pruned) so that partially malformed beacons still contribute useful discovery information rather than being silently dropped.