summaryrefslogtreecommitdiffstats
path: root/crates/core/tedge_api/README.md
blob: 340faa235d1553b74ef8080e060bf1c1497d9281 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Thin Edge API

thin-edge is made up out of "Plugins"[^1] which pass messages to eachother.
These plugins run on a "Core", which handles the message passing and the plugin
lifecycle.
This crate defines the interfaces a plugin author needs to implement so that a
plugin can be built into thin-edge.


## What a Plugin is

A Plugin is a piece of code that covers some usecase. That usecase has to be
exposed to the thin-edge.io ecosystem with the following functionalities (from a
high level):

* There's a function to "instantiate" a `Plugin`
* There's a function to "start" a `Plugin`
* A plugin can expose a number of API endpoints that it can receive messages on
* There's a function for cleanly shutting a `Plugin` down

The implementation of what we call the "core" of thin-edge.io is then
responsible of instantiating a plugin upon user request, start it, and send it
messages or forward messages the plugin emits to other plugins.

Messages are just objects that are defined via Rust structures. See below for
more information.

If shutdown of thin-edge.io is requested, the core is also responsible of
shutting a plugin down.

The core is responsible to protect each plugin from crashes of other plugins and
guarantee safe operation of all plugins in the ecosystem.


## API to implement

To implement a Plugin and bring functionality to the thin-edge.io ecosystem,
the following API endpoints need to be implemented:

* The `PluginBuilder` trait defines the interface that will be used to
  instantiate a `Plugin`
* The `Plugin` trait defines the interface that is used to start the
  instantiated `Plugin` and to shut it down
* The `Handle` trait defines the interfaces a `Plugin` instance can receive
  messages on. This trait can be implemented multiple times for each `Plugin`,
  one time for each message type this plugin is able to receive.

The following (simplified) diagram should describe this in a visual way:

<!--
the "aquamarine" crate does not yet support rendering this in rustdoc.
See: https://github.com/mersinvald/aquamarine/issues/19
-->
```mermaid
classDiagram
    class PluginBuilder
    <<interface>> PluginBuilder
    PluginBuilder : +instantiate() ~Plugin~

    class Plugin
    <<interface>> Plugin
    Plugin : +start()
    Plugin : +shutdown()

    class Handle
    <<interface>> Handle~Message~
    Handle : +handle_message(~Message~ message)

    class MyPluginBuilder
    MyPluginBuilder <|-- PluginBuilder : implements

    class MyPlugin
    MyPlugin <|-- Plugin : implements
    MyPlugin <|-- Handle~MyMessage~ : implements
```

## What a Message is

A message can be anything that is able to implement the `Message` trait.

This trait does not require the message to implement functionality, it just
requires an implementing structure to implement `Debug` and `Send` and some
others.

For example:

```rust
#[derive(Debug)]
struct Value(f64);

impl Message for Value {}
```

## How messages are send

Messages can be send between plugins, but can also be send to the core of
thin-edge.io and to the plugin itself (a Plugin can send messages to itself).

To be able to send a Message, an `Address` of that Plugin needs to be known.
That `Address` can be fetched during the instantiation of the Plugin. The
`PluginBuilder::instantiate()` function gets a reference to a `PluginDirectory`.
That `PluginDirectory` is basically an "address book", that can be asked for
addresses to other plugins, by specifying their name.
That name usually has to be configured.


## Plugin lifecycle

The above illustrated how a plugin lifecycle looks like. The following diagram
is here to visualize the words from above (minus some details that are not
required for understanding the grand scheme of things):

```mermaid
sequenceDiagram
    thinedge->>+PluginBuilder: instantiate()
    PluginBuilder->>Configuration: get_target_address()
    Configuration->>PluginBuilder: target_address
    PluginBuilder->>PluginDirectory: get_address_for<MeasurementReceiver>(target_address)
    PluginDirectory->>PluginBuilder: Address<MeasurementReceiver>
    PluginBuilder->>+Plugin: new(Address<MeasurementReceiver>)
    Plugin-->PluginBuilder: Plugin
    PluginBuilder->thinedge : Plugin
    thinedge->>+Plugin : start()
    Plugin-->-thinedge : start
    loop Lifecycle
      thinedge-->Plugin : handle_message()
    end
    thinedge->>+Plugin : shutdown()
    Plugin-->-thinedge : shutdown
```


[^1]: Name is subject to change.