summaryrefslogtreecommitdiffstats
path: root/crates/core
diff options
context:
space:
mode:
authorMatthias Beyer <matthias.beyer@ifm.com>2022-06-21 16:55:39 +0200
committerMatthias Beyer <matthias.beyer@ifm.com>2022-08-30 13:54:48 +0200
commit5874d04838623e9c0ef1dac313705c1fa1cb39d3 (patch)
treeedcee132cfa9088c53dca968f57652fe1f427a24 /crates/core
parent49a80a7f228700c33a7d4de720a69572cae4fee9 (diff)
Update PluginBuilder description
Signed-off-by: Matthias Beyer <matthias.beyer@ifm.com>
Diffstat (limited to 'crates/core')
-rw-r--r--crates/core/tedge_api/goals.md237
1 files changed, 225 insertions, 12 deletions
diff --git a/crates/core/tedge_api/goals.md b/crates/core/tedge_api/goals.md
index 6ab505f2..cb36f686 100644
--- a/crates/core/tedge_api/goals.md
+++ b/crates/core/tedge_api/goals.md
@@ -135,24 +135,230 @@ So, to get started:
It looks like this:
```rust
-/// A plugin builder for a given plugin
#[async_trait]
-pub trait PluginBuilder: Sync + Send + 'static {
- /// The a name for the kind of plugins this creates, this should be unique and will prevent startup otherwise
- fn kind_name(&self) -> &'static str;
-
- /// This may be called anytime to verify whether a plugin could be instantiated with the
- /// passed configuration.
+pub trait PluginBuilder<PD: PluginDirectory>: Sync + Send + 'static {
+ /// The name for the kind of plugins this creates, this should be unique and will prevent startup otherwise
+ ///
+ /// The "kind name" of a plugin is used by the configuration to name what plugin is to be
+ /// instantiated. For example, if the configuration asks thin-edge to instantiate a plugin
+ /// of kind "foo", but only a plugin implementation of kind "bar" is compiled into thin-edge,
+ /// the software is able to report misconfiguration on startup.
+ fn kind_name() -> &'static str
+ where
+ Self: Sized;
+
+ /// A list of message types the plugin this builder creates supports
+ ///
+ /// This function must return a `HandleTypes` object which represents the types of messages
+ /// that a plugin is able to handle.
+ ///
+ /// To create an instance of this type, you must call the [`PluginExt::get_handled_types`]
+ /// method on the plugin this PluginBuilder will build
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # use tedge_api::{Plugin, plugin::BuiltPlugin, PluginError, PluginExt, PluginDirectory, PluginBuilder, PluginConfiguration};
+ /// # use type_uuid::TypeUuid;
+ ///
+ /// #[derive(Debug, TypeUuid)]
+ /// #[uuid = "46f5d318-4158-4726-83dd-9b310cae3328"]
+ /// struct MyMessage;
+ /// impl tedge_api::Message for MyMessage { }
+ ///
+ /// struct MyPluginBuilder;
+ /// struct MyPlugin; // + some impl Plugin for MyPlugin
+ /// # #[async_trait::async_trait]
+ /// # impl Plugin for MyPlugin {
+ /// # async fn start(&mut self) -> Result<(), PluginError> {
+ /// # unimplemented!()
+ /// # }
+ /// # async fn shutdown(&mut self) -> Result<(), PluginError> {
+ /// # unimplemented!()
+ /// # }
+ /// # }
+ ///
+ /// # impl tedge_api::plugin::PluginDeclaration for MyPlugin {
+ /// # type HandledMessages = (MyMessage,);
+ /// # }
+ ///
+ /// #[async_trait::async_trait]
+ /// impl tedge_api::plugin::Handle<MyMessage> for MyPlugin {
+ /// async fn handle_message(
+ /// &self,
+ /// message: MyMessage,
+ /// sender: tedge_api::address::ReplySenderFor<MyMessage>
+ /// ) -> Result<(), tedge_api::error::PluginError> {
+ /// // ... Do something with it
+ ///# Ok(())
+ /// }
+ /// }
+ ///
+ /// #[async_trait::async_trait]
+ /// impl<PD: PluginDirectory> PluginBuilder<PD> for MyPluginBuilder {
+ /// fn kind_message_types() -> tedge_api::plugin::HandleTypes
+ /// where
+ /// Self: Sized,
+ /// {
+ /// MyPlugin::get_handled_types()
+ /// }
+ /// // other trait functions...
+ /// # fn kind_name() -> &'static str {
+ /// # unimplemented!()
+ /// # }
+ /// # async fn verify_configuration(
+ /// # &self,
+ /// # _config: &PluginConfiguration,
+ /// # ) -> Result<(), tedge_api::error::PluginError> {
+ /// # unimplemented!()
+ /// # }
+ /// # async fn instantiate(
+ /// # &self,
+ /// # config: PluginConfiguration,
+ /// # cancellation_token: tedge_api::CancellationToken,
+ /// # core_comms: &PD,
+ /// # ) -> Result<BuiltPlugin, tedge_api::error::PluginError>
+ /// # where
+ /// # PD: 'async_trait,
+ /// # {
+ /// # unimplemented!()
+ /// # }
+ /// }
+ /// ```
+ fn kind_message_types() -> HandleTypes
+ where
+ Self: Sized;
+
+ /// Get a generic configuration description of what kind of input the
+ /// plugin expects.
+ ///
+ /// See [`ConfigDescription`] as well as [`AsConfig`](crate::config::AsConfig) for how to
+ /// implement and use these types and interfaces.
+ fn kind_configuration() -> Option<ConfigDescription>
+ where
+ Self: Sized,
+ {
+ None
+ }
+
+ /// Verify the configuration of the plugin for this plugin kind
+ ///
+ /// This function will be used by the core implementation to verify that a given plugin
+ /// configuration can be used by a plugin.
+ ///
+ /// After the plugin configuration got loaded and deserialized, it might still contain settings
+ /// which are erroneous, for example
+ ///
+ /// ```toml
+ /// timeout = -1
+ /// ```
+ ///
+ /// This function can be used by plugin authors to verify that a given configuration is sound,
+ /// before the plugins are instantiated (to be able to fail early).
+ ///
+ /// # Note
+ ///
+ /// This may be called anytime (also while plugins are already running) to verify whether a
+ /// plugin could be instantiated with the passed configuration.
async fn verify_configuration(&self, config: &PluginConfiguration) -> Result<(), PluginError>;
/// Instantiate a new instance of this plugin using the given configuration
///
- /// This _must not_ block
+ /// This function is called by the core of thin-edge to create a new plugin instance.
+ ///
+ /// The [`PluginExt::finish()`] function can be used to make any type implementing [`Plugin`]
+ /// into a `BuiltPlugin`, which the function requires to be returned (see example below).
+ ///
+ /// # Note
+ ///
+ /// This function _must not_ block.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # use tedge_api::plugin::BuiltPlugin;
+ /// # use tedge_api::PluginConfiguration;
+ /// # use tedge_api::Plugin;
+ /// # use tedge_api::PluginBuilder;
+ /// # use tedge_api::PluginDirectory;
+ /// # use tedge_api::PluginExt;
+ /// # use type_uuid::TypeUuid;
+ ///
+ /// #[derive(Debug, TypeUuid)]
+ /// #[uuid = "39046e3e-05ad-4b16-bbf1-8c2d2da5b668"]
+ /// struct MyMessage;
+ /// impl tedge_api::Message for MyMessage { }
+ ///
+ ///
+ /// struct MyPluginBuilder;
+ /// struct MyPlugin; // + some impl Plugin for MyPlugin
+ /// # #[async_trait::async_trait]
+ /// # impl Plugin for MyPlugin {
+ /// # async fn start(&mut self) -> Result<(), tedge_api::error::PluginError> {
+ /// # unimplemented!()
+ /// # }
+ /// # async fn shutdown(&mut self) -> Result<(), tedge_api::error::PluginError> {
+ /// # unimplemented!()
+ /// # }
+ /// # }
+ ///
+ /// # impl tedge_api::plugin::PluginDeclaration for MyPlugin {
+ /// # type HandledMessages = (MyMessage,);
+ /// # }
+ ///
+ /// #[async_trait::async_trait]
+ /// impl tedge_api::plugin::Handle<MyMessage> for MyPlugin {
+ /// async fn handle_message(
+ /// &self,
+ /// _message: MyMessage,
+ /// _sender: tedge_api::address::ReplySenderFor<MyMessage>,
+ /// ) -> Result<(), tedge_api::error::PluginError> {
+ /// // implementation...
+ /// # unimplemented!()
+ /// }
+ /// }
+ ///
+ /// #[async_trait::async_trait]
+ /// impl<PD: PluginDirectory> PluginBuilder<PD> for MyPluginBuilder {
+ /// async fn instantiate(
+ /// &self,
+ /// config: PluginConfiguration,
+ /// cancellation_token: tedge_api::CancellationToken,
+ /// core_comms: &PD,
+ /// ) -> Result<BuiltPlugin, tedge_api::error::PluginError>
+ /// where
+ /// PD: 'async_trait,
+ /// {
+ /// use tedge_api::plugin::PluginExt;
+ /// let p = MyPlugin {};
+ /// Ok(p.finish())
+ /// }
+ /// // other trait functions...
+ /// # fn kind_name() -> &'static str {
+ /// # unimplemented!()
+ /// # }
+ /// # fn kind_message_types() -> tedge_api::plugin::HandleTypes
+ /// # where
+ /// # Self: Sized,
+ /// # {
+ /// # MyPlugin::get_handled_types()
+ /// # }
+ /// # async fn verify_configuration(
+ /// # &self,
+ /// # _config: &PluginConfiguration,
+ /// # ) -> Result<(), tedge_api::error::PluginError> {
+ /// # unimplemented!()
+ /// # }
+ /// }
+ /// ```
async fn instantiate(
&self,
config: PluginConfiguration,
- tedge_comms: Comms,
- ) -> Result<Box<dyn Plugin + 'static>, PluginError>;
+ cancellation_token: crate::CancellationToken,
+ core_comms: &PD,
+ ) -> Result<BuiltPlugin, PluginError>
+ where
+ PD: 'async_trait;
}
```
@@ -162,8 +368,15 @@ Things of note here:
- `verify_configuration` allows one to check if a given configuration _could even work_
- It however is not required to prove it
- `instantiate` which actually constructs your plugin and returns a new instance of it
- - One argument is the `Comms` object which holds the sender part of a
- channel to the tedge core, and through which messages can be sent
+ - One argument is a reference to a `PluginDirectory` object which can be
+ used to retrieve addresses of other plugins.
+ These address can be used to send messages to other plugins. The address
+ objects are typed, so it is guaranteed that you cannot accidentially send
+ messages to a plugin that this plugin cannot handle.
+ - Another argument is the `CancellationToken`, which you can (but don't have
+ to) use to receive cancellation requests, once thin-edge.io tries to
+ shut down, to do cleanup work of allocated resources (such as closing file
+ handles, sending notifications about shutdown to external services, etc).
2. Implement `Plugin` for your plugin struct.