Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ qtcreator-*
COLCON_IGNORE
AMENT_IGNORE

# Git worktrees
.worktrees/

# End of https://www.toptal.com/developers/gitignore/api/ros2,c++,pythonPLAN.md

PLAN.mdsrc/dynamic_message_introspection/
5 changes: 3 additions & 2 deletions docs/api/rest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -676,8 +676,9 @@ Software Updates
----------------

Manage software update packages with an async prepare/execute lifecycle.
The updates feature requires a backend plugin to be loaded (see :doc:`/config/server`).
Without a plugin, all endpoints return ``501 Not Implemented``.
The updates feature requires a plugin implementing ``UpdateProvider`` to be loaded
via the plugin framework (see :doc:`/config/server`).
Without such a plugin, all endpoints return ``501 Not Implemented``.

``GET /api/v1/updates``
List all registered update packages.
Expand Down
17 changes: 15 additions & 2 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0
Added
~~~~~

* Software update management with pluggable backend architecture:
* Gateway plugin framework for extending the gateway with custom functionality:

- Load plugins from shared libraries (``.so``) via ``plugins`` parameter
- Provider interfaces: ``UpdateProvider``, ``IntrospectionProvider`` (preview)
- ``PluginContext`` gives plugins access to entity cache, fault data, and HTTP utilities
- Custom capability registration (per-type and per-entity) with discovery integration
- Error isolation: failing plugins are disabled without crashing the gateway
- RAII lifecycle with API version checking and path validation

* Software update management via plugin framework:

- 8 SOVD-compliant ``/updates`` endpoints (CRUD + prepare/execute/automated/status)
- Plugin system via dlopen for runtime backend loading
- Async lifecycle with progress tracking and status polling
- Feature gating via ``updates.enabled`` parameter

Expand All @@ -41,6 +49,9 @@ Changed
* Fault response structure now SOVD-compliant with ``item`` wrapper
* Rosbag downloads use SOVD bulk-data pattern instead of legacy endpoints
* Rosbag IDs changed from timestamps to UUIDs
* Software update backends now load via the plugin framework instead of
dedicated ``updates.backend`` / ``updates.plugin_path`` parameters.
Migrate to ``plugins`` array with ``plugins.<name>.path`` entries.

Removed
~~~~~~~
Expand All @@ -56,6 +67,8 @@ Removed
and ``environment_data`` structure
* Legacy snapshot endpoints removed - migrate to inline snapshots and bulk-data
* Rosbag identifiers changed from timestamps to UUIDs
* ``updates.backend`` and ``updates.plugin_path`` parameters removed - use the
``plugins`` array to load update backend plugins

[0.1.0] - 2026-02-01
--------------------
Expand Down
62 changes: 51 additions & 11 deletions docs/config/server.rst
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,58 @@ Example:
max_clients: 10
max_subscriptions: 100

Plugin Framework
----------------

Extend the gateway with custom plugins loaded from shared libraries (``.so``).
Plugins can implement provider interfaces (e.g., ``UpdateProvider``, ``IntrospectionProvider``)
that are automatically detected and wired into the gateway's subsystem managers.

.. list-table::
:header-rows: 1
:widths: 25 15 15 45

* - Parameter
- Type
- Default
- Description
* - ``plugins``
- string[]
- ``[]``
- List of plugin names to load. Each plugin requires a corresponding ``plugins.<name>.path`` parameter.
* - ``plugins.<name>.path``
- string
- (required)
- Absolute path to the plugin ``.so`` file. Must exist and have ``.so`` extension.

Plugin loading lifecycle:

1. Shared library is loaded via ``dlopen`` with ``RTLD_NOW | RTLD_LOCAL``
2. API version is checked (must match gateway headers)
3. ``create_plugin()`` factory is called to instantiate the plugin
4. Provider interfaces are queried via ``extern "C"`` functions
5. ``configure()`` is called with per-plugin config
6. ``set_context()`` passes the gateway context to the plugin
7. ``register_routes()`` allows the plugin to add custom REST endpoints

Error isolation: if a plugin throws during any lifecycle call, it is disabled
without crashing the gateway. Other plugins continue to operate normally.

Example:

.. code-block:: yaml

ros2_medkit_gateway:
ros__parameters:
plugins: ["my_ota_plugin"]
plugins.my_ota_plugin.path: "/opt/ros2_medkit/lib/libmy_ota_plugin.so"

Software Updates
----------------

Configure the software updates plugin system. Updates are disabled by default.
Configure the software updates system. Updates are disabled by default.
When enabled, a plugin implementing ``UpdateProvider`` is required to provide
the backend functionality (see `Plugin Framework`_ above).

.. list-table::
:header-rows: 1
Expand All @@ -272,25 +320,17 @@ Configure the software updates plugin system. Updates are disabled by default.
- bool
- ``false``
- Enable/disable software updates endpoints. When disabled, ``/updates`` routes are not registered.
* - ``updates.backend``
- string
- ``"none"``
- Backend type. ``"none"`` enables endpoints but returns 501. ``"plugin"`` loads a shared library.
* - ``updates.plugin_path``
- string
- ``""``
- Path to the ``.so`` plugin file. Required when ``backend`` is ``"plugin"``.

Example:

.. code-block:: yaml

ros2_medkit_gateway:
ros__parameters:
plugins: ["my_update_plugin"]
plugins.my_update_plugin.path: "/opt/ros2_medkit/lib/libmy_update_plugin.so"
updates:
enabled: true
backend: "plugin"
plugin_path: "/opt/ros2_medkit/plugins/libmy_update_backend.so"

Complete Example
----------------
Expand Down
6 changes: 4 additions & 2 deletions docs/troubleshooting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,10 @@ ros2_medkit is currently suitable for development and testing. For production:

**Q: Can I extend ros2_medkit with custom endpoints?**

Not directly at this time. Future versions may support plugins.
For now, you can fork the gateway and add custom routes in ``rest_server.cpp``.
Yes. The gateway plugin framework allows you to add custom REST endpoints via
``GatewayPlugin::register_routes()``. Create a shared library (``.so``) that
implements the ``GatewayPlugin`` base class and configure it in ``gateway_params.yaml``.
See :doc:`/config/server` for plugin configuration details.

**Q: How do I report a bug or request a feature?**

Expand Down
4 changes: 4 additions & 0 deletions docs/tutorials/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Step-by-step guides for common use cases with ros2_medkit.
custom_areas
web-ui
mcp-server
plugin-system

Demos
-----
Expand Down Expand Up @@ -84,3 +85,6 @@ Advanced Tutorials

:doc:`custom_areas`
Customize the entity hierarchy for your robot architecture.

:doc:`plugin-system`
Extend the gateway with custom plugins for update backends, introspection, and REST endpoints.
Loading