Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial plugin docs #2138

Merged
merged 4 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
172 changes: 172 additions & 0 deletions docs/GettingStartedAriesDev/PlugIns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# 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:

* `--plug-in` - identifies the plug-in library to load
ianco marked this conversation as resolved.
Show resolved Hide resolved
* `--block-plugin` - identifies plug-ins (includign built-ins) that are *not* to be loaded
Copy link
Contributor

Choose a reason for hiding this comment

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

spelling: including

* `--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) explicitely 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)).

### setup.py

If a setup method is provided, it will be called. If not, the `message_types.py` and `routes.py` will be explicitely loaded.
Copy link
Contributor

Choose a reason for hiding this comment

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

sp: explicitly

Copy link
Contributor

Choose a reason for hiding this comment

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

should we mention that it would be in the package/module __init__.py?

async def setup(context: InjectionContext):
    pass

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point I'll do that


TODO I couldn't find an implementation of a custom `setup` in any of the existing plug-ins, so I'm not completly sure what are the best practices for this option.
Copy link
Contributor

Choose a reason for hiding this comment

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

sp. completely


### 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
- `CONTRROLLERS` - identifies protocol controllers
Copy link
Contributor

Choose a reason for hiding this comment

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

sp 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
Copy link
Contributor

Choose a reason for hiding this comment

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

I did not know that - excellent!


### 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
Copy link
Contributor

Choose a reason for hiding this comment

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

wow - this section is fantastic. this would have saved me days of jumping in and out of code and poking around.

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
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this idea... maybe illustrate all the ways mentioned above in the "When developing a new plug-in" section. Or we can begin pointing at specific implementations that exist in the wild.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes that's what I was thinking. I'm going to create a new issue for this


# 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

1 change: 1 addition & 0 deletions docs/GettingStartedAriesDev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.