Skip to content

Adding Pluginsystem v2 to ImSwitch - #314

Open
beniroquai wants to merge 5 commits into
masterfrom
feature/pluginsystemV2
Open

Adding Pluginsystem v2 to ImSwitch#314
beniroquai wants to merge 5 commits into
masterfrom
feature/pluginsystemV2

Conversation

@beniroquai

Copy link
Copy Markdown
Collaborator

This pull request introduces a comprehensive, secure, and flexible plugin integration system for ImSwitch, making it easier for external developers to extend or customize the platform without forking or rebuilding the core. It establishes a standardized drop-in plugin directory, updates Docker and entrypoint configurations to support plugin delivery, and provides clear documentation for integration paths.

Plugin System and Integration Support

  • Added a drop-in plugin directory (/opt/imswitch/plugins) to the Docker image, ensuring a consistent mount point for plugins and improving operational clarity and security. The directory is created at build time and exposed as IMSWITCH_PLUGIN_DIR.
  • Updated the Docker entrypoint script to configure, log, and safely handle the plugin directory, including informative logs if the directory is missing or empty. [1] [2] [3]

Docker Compose Enhancements

  • Updated docker-compose.yml to mount the plugin directory read-only, document security considerations, and provide an alternative plugin delivery pattern using a container image as a volume source for fleet deployments. [1] [2] [3]

Documentation Improvements

  • Added docs/INTEGRATION.md, a detailed guide for external developers describing supported integration paths (REST/Socket.IO client, plugin, upstream contribution), when to use each, and why forking the core is discouraged.
  • Updated the README.md to direct integrators to the new documentation and clarify extension points.

These changes make plugin development safer, more robust, and better documented, while supporting both simple and advanced deployment scenarios.

Add a v2 plugin system: new imswitch.plugin_manager that discovers plugins (entry-points + drop-in dir), validates manifests, instantiates controllers, mounts per-plugin API routers and static UI at /plugin/<name>/*, and appends v1-shaped manifest records for back-compat. Add imswitch.plugin_sdk exposing PluginManifest, PluginContext, PluginController, APIExport, Event, and helpers for plugin authors. Wire the server to create and use PluginManager (discover, attach_to_app) and ensure it is shut down on server stop; ImConMainController now passes the master controller into ImSwitchServer. Update frontend loader to prefer the new v2 manifest field remote_entry (falling back to legacy remote) so the existing UI can load plugins served under the new manager.
Implements the first two work packages of the v2 plugin system:

- WP0: Adds docs/plugins/DECISIONS.md as an architecture decision record covering the two plugin mechanisms, deprecating v1 (imswitch.implugins) in favour of v2 PluginManager, and defining the stable API surface. Removes dead v1 code: SetupInfo.add_attribute and ImConMainController.loadPlugin plus its unreachable caller. Adds deprecation comments to the three remaining reachable v1 consumers.

- WP1: Exposes GET /imswitch/api/plugins and GET /imswitch/api/plugins/{name} via register_plugin_routes(), registered in createAPI() before app.include_router(). Uses a module-level _PLUGIN_MANAGER holder so route handlers can read state that only exists after discovery. Never returns 500. Adds 9 tests in test_plugin_api.py including a B3 registration-order regression guard.

Also adds docs/wp_pluginsystem.md as the full work plan for WPs 0–8.
Switch plugin support to a drop-in directory model, add federated frontend loading with dynamic app registry/error handling, and remove the old `imswitch.implugins` entry-point paths. Also wire the plugin directory through Docker and startup, expand partner-facing docs, and add end-to-end plugin tests.
Copilot AI review requested due to automatic review settings August 3, 2026 20:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a v2 drop-in plugin system for ImSwitch, spanning backend discovery/loading (manifest + role-based hardware binding), a stable Python plugin SDK, frontend runtime loading via Module Federation (including dynamic Redux reducer injection), and Docker + documentation updates. It also removes the legacy v1 imswitch.implugins entry-point based mechanism across the codebase.

Changes:

  • Add a new backend plugin architecture (imswitch.plugin_manager + imswitch.plugin_sdk) and expose plugin manifests via GET /imswitch/api/plugins.
  • Update the frontend to discover plugins at runtime, load federated widgets robustly (timeout + error boundary), and integrate plugins into navigation/App Manager state.
  • Add Docker mount points + entrypoint logging for /opt/imswitch/plugins, plus extensive documentation for integration and deployment.

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
setup.py Removes legacy imswitch.implugins.* entry-point groups from packaging metadata.
pyproject.toml Removes legacy imswitch.implugins.* entry-point groups from project metadata.
README.md Adds “Extending ImSwitch” section pointing integrators to the new docs.
imswitch/plugin_sdk/init.py Introduces the stable v2 plugin SDK (manifest schema, APIExport, Event, context).
imswitch/plugin_manager.py Adds directory-based plugin discovery/loading, gating, mounting, and manifest serialization.
imswitch/imcontrol/view/ImConMainView.py Removes v1 entry-point widget loading path; clarifies v2 plugin UI is mounted elsewhere.
imswitch/imcontrol/model/SetupInfo.py Removes v1 plugin-derived setup augmentation logic.
imswitch/imcontrol/model/managers/MultiManager.py Removes v1 entry-point fallback manager loading; documents ADR-002 rationale.
imswitch/imcontrol/controller/server/ImSwitchServer.py Registers /api/plugins routes and wires PluginManager into server lifecycle.
imswitch/imcontrol/controller/MasterController.py Removes v1 manager plugin injection; documents device-type constraints.
imswitch/imcontrol/controller/ImConMainController.py Removes v1 controller plugin loading/UI API generation; passes master into server for plugins.
imswitch/imcontrol/_test/test_plugin_manager.py Adds comprehensive PluginManager unit tests for discovery, gating, URLs, and failure modes.
imswitch/imcontrol/_test/test_plugin_e2e.py Adds end-to-end tests for the full backend plugin chain and served UI bundle.
imswitch/imcontrol/_test/test_plugin_api.py Adds tests for the new /imswitch/api/plugins HTTP surface and registration order.
imswitch/imcommon/model/api.py Removes deprecated UIExport/generateUI mechanisms.
imswitch/imcommon/model/init.py Stops exporting UIExport/generateUI from the common model barrel.
imswitch/main.py Adds --plugin-dir / plugin_dir wiring and startup logging for resolved plugin folder.
frontend/src/state/store.js Adds dynamic reducer injection while preserving redux-persist + sync wrapper identity.
frontend/src/state/slices/appManagerSlice.js Adds runtime plugin app registry integration and stable selectors for plugin arrays.
frontend/src/context/index.js Adds an explicit “public contexts” barrel for federation (host_app/contexts).
frontend/src/constants/appRegistry.js Adds runtime plugin manifest mapping + MUI icon name resolution support.
frontend/src/components/PluginErrorBoundary.jsx Adds a dedicated error boundary for third-party plugin widgets.
frontend/src/components/navigation/NavigationDrawer.jsx Renders runtime plugin entries and adds a dedicated Plugins group.
frontend/src/components/AppManager/AppManager.jsx Integrates runtime plugins into App Manager and shows “plugins not available” panel.
frontend/src/App.jsx Reworks plugin loader to be manifest-driven, time-bounded, and error-visible; dispatches runtime apps.
frontend/shared-deps.js Adds canonical shared dependency list + helper for host/plugin Module Federation config.
frontend/craco.config.js Exposes host modules to plugins and uses the canonical shared-deps builder.
docs/wp_pluginsystem.md Adds/updates the full work plan and rationale document for the plugin system.
docs/plugins/README.md Adds partner/developer-facing plugin documentation and troubleshooting.
docs/plugins/DEPLOYMENT.md Adds deployment instructions (Docker + native dev) and troubleshooting.
docs/plugins/DECISIONS.md Adds ADRs and stable-surface definitions for the v2 plugin system.
docs/INTEGRATION.md Adds a guide for partners choosing REST vs plugin vs upstream contribution.
Dockerfile Creates /opt/imswitch/plugins and sets default IMSWITCH_PLUGIN_DIR.
docker/entrypoint.sh Adds PLUGIN_PATH/IMSWITCH_PLUGIN_DIR wiring and startup logging of plugin directory contents.
docker/docker-compose.yml Adds read-only plugin bind mount and documents an image-as-volume alternative pattern.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +114 to +123
def load_manifest(toml_path) -> PluginManifest:
"""Parse a ``plugin.toml`` file into a validated :class:`PluginManifest`.

``toml_path`` can be anything ``open()`` accepts in binary mode — a
:class:`pathlib.Path`, a string, or an ``importlib.resources`` traversable.
"""
with open(str(toml_path), "rb") as f:
raw = tomllib.load(f)
block = raw.get("plugin", {})
return PluginManifest(**block)
Comment on lines +35 to +37
// Namespace import so a plugin manifest can name any MUI icon at runtime.
// @mui/icons-material is a federation singleton, so this costs nothing extra.
import * as MuiIcons from "@mui/icons-material";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants