diff --git a/README.md b/README.md index 936847fbc5..f5fc6cd485 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ There is an [architectural deep dive webinar](https://www.youtube.com/watch?v=FX ![drawing](./aca-py_architecture.png) +You can extend Aca-Py using plug-ins, which can be loaded at runtime. Plug-ins are mentioned in the [webinar](https://docs.google.com/presentation/d/1K7qiQkVi4n-lpJ3nUZY27OniUEM0c8HAIk4imCWCx5Q/edit#slide=id.g5d43fe05cc_0_145) and are [described in more detail here](/docs/GettingStartedAriesDev/PlugIns.md). + ### Installation and Usage An ["install and go" page for developers](https://github.com/hyperledger/aries-cloudagent-python/blob/main/DevReadMe.md) is available if you are comfortable with Trust over IP and Aries concepts. ACA-Py can be run with Docker without installation (highly recommended), or can be installed [from PyPi](https://pypi.org/project/aries-cloudagent/). In the [/demo directory](/demo) there is a full set of demos for developers to use in getting started, and the [demo read me](/demo/README.md) is a great starting point for developers to use an "in-browser" approach to run a zero-install example. The [Read the Docs](https://aries-cloud-agent-python.readthedocs.io/en/latest/) overview is also a way to reference the modules and APIs that make up an ACA-Py instance. diff --git a/docs/GettingStartedAriesDev/PlugIns.md b/docs/GettingStartedAriesDev/PlugIns.md new file mode 100644 index 0000000000..8f742bd57d --- /dev/null +++ b/docs/GettingStartedAriesDev/PlugIns.md @@ -0,0 +1,181 @@ +# Deeper Dive: Aca-Py Plug-Ins + +## What's in a Plug-In and How does it Work? + +Plug-ins are loaded on Aca-Py startup based on the following parameters: + +* `--plugin` - identifies the plug-in library to load +* `--block-plugin` - identifies plug-ins (including built-ins) that are *not* to be loaded +* `--plugin-config` - identify a configuration parameter for a plug-in +* `--plugin-config-value` - identify a *value* for a plug-in configuration + + +The `--plug-in` parameter specifies a package that is loaded by Aca-Py at runtime, and extends Aca-Py by adding support for additional protocols and message types, and/or extending the Admin API with additional endpoints. + +The original plug-in design (which we will call the "old" model) explicitly indluded `message_types.py` `routes.py` (to add Admin API's). But functionality was added later (we'll call this the "new" model) to allow the plug-in to include a generic `setup` package that could perform arbitrary initialization. The "new" model also includes support for a `definition.py` file that can specify plug-in version information (major/minor plug-in version, as well as the minimum supported version (if another agent is running an older version of the plug-in)). + +You can discover which plug-ins are installed in an aca-py instance by calling (in the "server" section) the `GET /plugins` endpoint. (Note that this will return all loaded protocols, including the built-ins. You can call the `GET /status/config` to inspect the Aca-Py configuration, which will include the configuration for the *external* plug-ins.) + +### setup method + +If a setup method is provided, it will be called. If not, the `message_types.py` and `routes.py` will be explicitly loaded. + +This would be in the `package/module __init__.py`: + +``` +async def setup(context: InjectionContext): + pass +``` + +TODO I couldn't find an implementation of a custom `setup` in any of the existing plug-ins, so I'm not completely sure what are the best practices for this option. + +### message_types.py + +When loading a plug-in, if there is a `message_types.py` available, Aca-Py will check the following attributes to initialize the protocol(s): + +- `MESSAGE_TYPES` - identifies message types supported by the protocol +- `CONTROLLERS` - identifies protocol controllers + +### routes.py + +If `routes.py` is available, then Aca-Py will call the following functions to initialize the Admin endpoints: + +- `register()` - registers routes for the new Admin endpoints +- `register_events()` - registers an events this package will listen for/respond to + +### definition.py + +If `definition.py` is available, Aca-Py will read this package to determine protocol version information. An example follows (this is an example that specifies two protocol versions): + +``` +versions = [ + { + "major_version": 1, + "minimum_minor_version": 0, + "current_minor_version": 0, + "path": "v1_0", + }, + { + "major_version": 2, + "minimum_minor_version": 0, + "current_minor_version": 0, + "path": "v2_0", + }, +] +``` + +The attributes are: + +- `major_version` - specifies the protocol major version +- `current_minor_version` - specifies the protocol minor version +- `minimum_minor_version` - specifies the minimum supported version (if a lower version is installed in another agent) +- `path` - specifies the sub-path within the package for this version + + +## Loading Aca-Py Plug-Ins at Runtime + +The load sequence for a plug-in (the "Startup" class depends on how Aca-Py is running - `upgrade`, `provision` or `start`): + +```mermaid +sequenceDiagram + participant Startup + Note right of Startup: Configuration is loaded on startup<br/>from aca-py config params + Startup->>+ArgParse: configure + ArgParse->>settings: ["external_plugins"] + ArgParse->>settings: ["blocked_plugins"] + + Note right of Startup: Each configured plug-in is validated and loaded + Startup->>+DefaultContext: build_context() + DefaultContext->>DefaultContext: load_plugins() + DefaultContext->>+PluginRegistry: register_package() (for built-in protocols) + PluginRegistry->>PluginRegistry: register_plugin() (for each sub-package) + DefaultContext->>PluginRegistry: register_plugin() (for non-protocol built-ins) + loop for each external plug-in + DefaultContext->>PluginRegistry: register_plugin() + alt if a setup method is provided + PluginRegistry->>ExternalPlugIn: has setup + else if routes and/or message_types are provided + PluginRegistry->>ExternalPlugIn: has routes + PluginRegistry->>ExternalPlugIn: has message_types + end + opt if definition is provided + PluginRegistry->>ExternalPlugIn: definition() + end + end + DefaultContext->>PluginRegistry: init_context() + loop for each external plug-in + alt if a setup method is provided + PluginRegistry->>ExternalPlugIn: setup() + else if a setup method is NOT provided + PluginRegistry->>PluginRegistry: load_protocols() + PluginRegistry->>PluginRegistry: load_protocol_version() + PluginRegistry->>ProtocolRegistry: register_message_types() + PluginRegistry->>ProtocolRegistry: register_controllers() + end + PluginRegistry->>PluginRegistry: register_protocol_events() + end + + Note right of Startup: If the admin server is enabled, plug-in routes are added + Startup->>AdminServer: create admin server if enabled + Startup->>AdminServer: setup_context() (called on each request) + AdminServer->>PluginRegistry: register_admin_routes() + loop for each external plug-in + PluginRegistry->>ExternalPlugIn: routes.register() (to register endpoints) + end +``` + +## Developing a New Plug-In + +When developing a new plug-in: + +- If you are providing a new protocol or defining message types, you *should* include a `definition.py` file. +- If you are providing a new protocol or defining message types, you *should* include a `message_types.py` file. +- If you are providing additional Admin endpoints, you *should* include a `routes.py` file. +- If you are providing any other functionality, you should provide a `setup.py` file to initialize the custom functionality. No guidance is *currently* available for this option. + +### PIP vs Poetry Support + +Most Aca-Py plug-ins provide support for installing the plug-in using [poetry](https://python-poetry.org/). It is *recommended* to include support in your package for installing using *either* pip or poetry, to provide maximum support for users of your plug-in. + +### Plug-In Demo + +TBD + +# Aca-Py Plug-ins + +This list was originally published in [this hackmd document](https://hackmd.io/m2AZebwJRkm6sWgO64-5xQ). + +| Maintainer | Name | Features | Last Update | Link | +| ----------- | -------------------------- | -------------------------------- | ----------- | ----------------------------------------------------------------------- | +| BCGov | Redis Events | Inbound/Outbound message queue | Sep 2022 | https://github.com/bcgov/aries-acapy-plugin-redis-events | +| Hyperledger | Aries Toolbox | UI for ACA-py | Aug 2022 | https://github.com/hyperledger/aries-toolbox | +| Hyperledger | Aries ACApy Plugin Toolbox | Protocol Handlers | Aug 2022 | https://github.com/hyperledger/aries-acapy-plugin-toolbox | +| Indicio | Data Transfer | Specific Data import | Aug 2022 | https://github.com/Indicio-tech/aries-acapy-plugin-data-transfer | +| Indicio | Question & Answer | Non-Aries Protocol | Aug 2022 | https://github.com/Indicio-tech/acapy-plugin-qa | +| Indicio | Acapy-plugin-pickup | Fetching Messages from Mediator | Aug 2022 | https://github.com/Indicio-tech/acapy-plugin-pickup | +| Indicio | Machine Readable GF | Governance Framework | Mar 2022 | https://github.com/Indicio-tech/mrgf | +| Indicio | Cache Redis | Cache for Scaleability | Jul 2022 | https://github.com/Indicio-tech/aries-acapy-cache-redis | +| SICPA Dlab | Kafka Events | Event Bus Integration | Aug 2022 | https://github.com/sicpa-dlab/aries-acapy-plugin-kafka-events | +| SICPA Dlab | DidComm Resolver | Unversal Resolver for DIDComm | Aug 2022 | https://github.com/sicpa-dlab/acapy-resolver-didcomm | +| SICPA Dlab | Universal Resolver | Multi-ledger Reading | Jul 2021 | https://github.com/sicpa-dlab/acapy-resolver-universal | +| DDX | mydata-did-protocol | | Oct 2022 | https://github.com/decentralised-dataexchange/acapy-mydata-did-protocol | +| BCGov | Basic Message Storage | Basic message storage (traction) | Dec 2022 | https://github.com/bcgov/traction/tree/develop/plugins/basicmessage_storage | +| BCGov | Multi-tenant Provider | Multi-tenant Provider (traction) | Dec 2022 | https://github.com/bcgov/traction/tree/develop/plugins/multitenant_provider | +| BCGov | Traction Innkeeper | Innkeeper (traction) | Feb 2023 | https://github.com/bcgov/traction/tree/develop/plugins/traction_innkeeper | + + +# Reference + +The following links may be helpful or provide additional context for the current plug-in support. (These are links to issues or pull requests that were raised during plug-in development.) + +Configuration params: + https://github.com/hyperledger/aries-cloudagent-python/issues/1121 + https://hackmd.io/ROUzENdpQ12cz3UB9qk1nA + https://github.com/hyperledger/aries-cloudagent-python/pull/1226 + +Loading plug-ins: + https://github.com/hyperledger/aries-cloudagent-python/pull/1086 + +Versioning for plug-ins: + https://github.com/hyperledger/aries-cloudagent-python/pull/443 + diff --git a/docs/GettingStartedAriesDev/README.md b/docs/GettingStartedAriesDev/README.md index e6b98aa655..dad297c007 100644 --- a/docs/GettingStartedAriesDev/README.md +++ b/docs/GettingStartedAriesDev/README.md @@ -21,5 +21,6 @@ Note that in the guidance we have here, we include not only the links to look at * [Deeper Dive: Routing Example](AriesRoutingExample.md) * To Do: [Deeper Dive: Running and Connecting to an Indy Network](ConnectIndyNetwork.md) * [Steps and APIs to support credential revocation with Aries agent](CredentialRevocation.md) +* [Deeper Dive: Aca-Py Plug-Ins](PlugIns.md) Want to help with this guide? Please add issues or submit a pull request to improve the document. Point out things that are missing, things to improve and especially things that are wrong.