diff --git a/Hello_world.md b/Hello_world.md
index facfec8..b5e6188 100644
--- a/Hello_world.md
+++ b/Hello_world.md
@@ -19,6 +19,8 @@ I can also reference the section {ref}`section-two` without specifying my title.
:::{note}
And here's a note with a colon fence!
+
+Note, that you have to use a colon fence in a markdown file instead of the normal directives in rst files.
:::
And finally, here's a cool mermaid diagram!
@@ -36,3 +38,20 @@ sequenceDiagram
John->Bob: How about you?
Bob-->John: Jolly good!
:::
+
+
+
+## JSON Schema
+
+You can show json data in a data-viewer:
+
+:::{data-viewer}
+:expand:
+:file: schemas/component.json
+:::
+
+
+
+
+
+test
diff --git a/conf.py b/conf.py
index 5a1d0c4..1d263b8 100644
--- a/conf.py
+++ b/conf.py
@@ -7,13 +7,19 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'experiment_control_protocol'
-copyright = '2023, PyMeasure maintainers'
-author = 'PyMeasure maintainers'
+copyright = '2023, LECO maintainers'
+author = 'LECO maintainers'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
-extensions = ['myst_parser', 'sphinxcontrib.mermaid', 'sphinx_rtd_theme']
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'myst_parser',
+ 'sphinxcontrib.mermaid',
+ 'sphinx_rtd_theme',
+ "sphinx_data_viewer",
+]
myst_enable_extensions = [
"colon_fence",
diff --git a/control_protocol.md b/control_protocol.md
index 96e56de..618802e 100644
--- a/control_protocol.md
+++ b/control_protocol.md
@@ -48,7 +48,7 @@ For example `N1.CA` is the Full name of the Component `CA` in the Node `N1`.
The receiver of a message may be specified by Component name alone if the receiver belongs to the same Node as the sender.
In all other cases, the receiver of a message must be specified by the Full name.
-The sender of a message must be specified by Full name, except during SIGNIN, when the Component name alone is sufficient.
+The sender of a message must be specified by Full name, except for the `sign_in` message, when the Component name alone is sufficient.
#### Message composition
@@ -91,10 +91,10 @@ In the exchange of messages, only the messages over the wire are shown, the conn
##### Signing-in
-After connecting to a Coordinator (`Co1`), a Component (`CA`) shall send a SIGNIN message indicating its Component name.
-The Coordinator shall indicate success/acceptance with an ACKNOWLEDGE response, giving the Namespace and other relevant information, or reply with an ERROR, e.g. if the Component name is already taken.
+After connecting to a Coordinator (`Co1`), a Component (`CA`) shall send a `sign_in` message (see {ref}`control_protocol.md#coordinator`) indicating its Component name.
+The Coordinator shall indicate success/acceptance with a `result` response (according to [JSON-RPC](https://www.jsonrpc.org/specification)), giving the Namespace and other relevant information, or reply with an ERROR, e.g. if the Component name is already taken.
In that case, the Coordinator may indicate a suitable, still available variation on the indicated Component name.
-The Component may retry SIGNIN with a different chosen name.
+The Component may retry signing in with a different chosen name.
After a successful handshake, the Coordinator shall store the Component name in its {ref}`control_protocol.md#directory` and shall ensure message delivery to that Component (e.g. by storing the (zmq) connection identity with the local directory).
It shall also notify the other Coordinators in the network that this Component signed in, see {ref}`control_protocol.md#coordinator-coordination`.
@@ -106,21 +106,21 @@ If a Component does send a message to someone without having signed in, the Coor
sequenceDiagram
Note over CA,N1: Name "CA" is still free
participant N1 as N1.COORDINATOR
- CA ->> N1: V|COORDINATOR|CA|H|SIGNIN
+ CA ->> N1: V|COORDINATOR|CA|H|sign_in
Note right of N1: Connection identity "IA"
Note right of N1: Stores "CA" with identity "IA"
- N1 ->> CA: V|N1.CA|N1.COORDINATOR|H|ACKNOWLEDGE: Namespace is "N1"
+ N1 ->> CA: V|N1.CA|N1.COORDINATOR|H|result
Note left of CA: Stores "N1" as Namespace
Note over CA,N1: Name "CA" is already used
- CA ->> N1: V|COORDINATOR|CA|H|SIGNIN
- N1 ->> CA: V|CA|N1.COORDINATOR|H|ERROR: Name "CA" is already used.
+ CA ->> N1: V|COORDINATOR|CA|H|sign_in
+ N1 ->> CA: V|CA|N1.COORDINATOR|H|ERROR: The name is already taken.
Note left of CA: May retry with another Name
- Note over CA,N1: "CA" has not send SIGNIN
+ Note over CA,N1: "CA" has not send sign_in
Note left of CA: Wants to send a message to CB
CA ->> N1: V|N1.CB|CA|H|Content
Note right of N1: Does not know CA
- N1 ->> CA: V|CA|N1.COORDINATOR|H|ERROR:I do not know you
- Note left of CA: Must send a SIGNIN message
before further messaging.
+ N1 ->> CA: V|CA|N1.COORDINATOR|H|ERROR: Component not signed in yet!
+ Note left of CA: Must send a sign_in message
before further messaging.
:::
@@ -130,7 +130,7 @@ Heartbeats are used to know whether a communication peer is still online.
Every message received counts as a heartbeat.
-A Component should and a Coordinator shall send a PING and wait some time before considering a connection dead.
+A Component should and a Coordinator shall send a `pong` request message (see {ref}`control_protocol.md#actor`) and wait some time before considering a connection dead.
A Coordinator shall follow the {ref}`control_protocol.md#signing-out` for a signed in Component considered dead.
:::{note}
@@ -140,18 +140,18 @@ TBD: Heartbeat details are still to be determined.
##### Signing out
-A Component should send a SIGNOUT message to its Coordinator when it stops participating in the Network.
-The Coordinator shall ACKNOWLEDGE the sign-out and remove the Component name from its local {ref}`control_protocol.md#directory`.
+A Component should send a `sign_out` message (see {ref}`control_protocol.md#coordinator`) to its Coordinator when it stops participating in the Network.
+The Coordinator shall acknowledge the sign-out with a `result` message and remove the Component name from its local {ref}`control_protocol.md#directory`.
It shall also notify the other Coordinators in the network that this Component signed out, see {ref}`control_protocol.md#coordinator-coordination`.
:::{mermaid}
sequenceDiagram
- CA ->> N1: V|COORDINATOR|N1.CA|H|SIGNOUT
+ CA ->> N1: V|COORDINATOR|N1.CA|H|sign_out
participant N1 as N1.COORDINATOR
- N1 ->> CA: V|N1.CA|N1.COORDINATOR|H|ACKNOWLEDGE
+ N1 ->> CA: V|N1.CA|N1.COORDINATOR|H|result
Note right of N1: Removes "CA" with identity "IA"
from local Directory
Note right of N1: Notifies other Coordinators about sign-out of "CA"
- Note left of CA: Shall not send any message anymore except SIGNIN
+ Note left of CA: Shall not send any message anymore except sign_in
:::
@@ -215,9 +215,9 @@ flowchart TB
CnS-->|yes| Clocal{CA in
local Directory?}
Clocal -->|yes| CidKnown{iA is CA's identity?}
CidKnown -->|yes| RemIdent
- Clocal -.->|no| E1[ERROR: Sender unknown] ==>|"iA|V|nS.CA|N1.COORDINATOR|H|ERROR: Sender unknown"| S
+ Clocal -.->|no| E1[ERROR: Component not signed in yet!] ==>|"iA|V|nS.CA|N1.COORDINATOR|H|ERROR: Component not signed in yet!"| S
S[send] ==> WA([N1.CA DEALER])
- CidKnown -.->|no| E2[ERROR: Name and identity do not match]==>|"iA|V|nS.CA|N1.COORDINATOR|H|ERROR: Name and identity do not match"| S
+ CidKnown -.->|no| E2[ERROR: Component not signed in yet!]==>|"iA|V|nS.CA|N1.COORDINATOR|H|ERROR: Component not signed in yet!"| S
RemIdent[remove sender identity] == "V|nR.recipient|nS.CA|H|Content" ==> CnR
CnR -- "is None" --> Local
CnR{nR?} -- "== N1"--> Local
@@ -227,7 +227,7 @@ flowchart TB
Local2a -->|yes, with Identity iB| Local2
Local2[add recipient identity iB] == "iB|V|nR.recipient|nS.CA|H|Content" ==> R1[send]
R1 == "V|nR.recipient|nS.CA|H|Content" ==> W1([Wire to N1.recipient DEALER])
- Local2a -.->|no| E3[ERROR recipient unknown
send Error to original sender] ==>|"V|nS.CA|N1.COORDINATOR|H|ERROR N1.recipient is unknown"|CnR
+ Local2a -.->|no| E3[ERROR: Receiver is not in addresses list
send Error to original sender] ==>|"V|nS.CA|N1.COORDINATOR|H|
ERROR: N1.recipient is unknown"|CnR
CnR -- "== N2" --> Keep
Keep[send to N2.COORDINATOR] == "V|nR.recipient|nS.CA|H|Content" ==> R2[send]
R2 == "V|nR.recipient|nS.CA|H|Content" ==> W2([Wire to N2.COORDINATOR ROUTER])
@@ -238,7 +238,7 @@ flowchart TB
R1
S
end
- subgraph Co1 DEALER socket
to N2.COORDINATOR
+ subgraph "Co1 DEALER socket
to N2.COORDINATOR"
R2
end
:::
@@ -275,27 +275,27 @@ sequenceDiagram
activate d1
Note left of d1: created with
name "temp-NS"
d1-->>r2: connect to address2
- d1->>r2: V|COORDINATOR|N1.COORDINATOR|H|
CO_SIGNIN
+ d1->>r2: V|COORDINATOR|N1.COORDINATOR|H|
coordinator_sign_in
Note right of r2: stores N1 identity
- r2->>d1: V|N1.COORDINATOR|N2.COORDINATOR|H|ACK
+ r2->>d1: V|N1.COORDINATOR|N2.COORDINATOR|H|result
Note left of d1: DEALER name
set to "N2"
- d1->>r2: V|N1.COORDINATOR|N2.COORDINATOR|H|
Here is my local directory
and Coordinator addresses
+ d1->>r2: V|N1.COORDINATOR|N2.COORDINATOR|H|
add_nodes(Coordinator addresses)
record_components
Note right of r2: Updates global
Directory and signs
in to all unknown
Coordinators,
also N1
Note over d1,r2: Mirror of above sign-in procedure
activate d2
Note left of d2: created with
name "N1"
d2-->>r1: connect to address1
- d2->>r1: V|COORDINATOR|N2.COORDINATOR|H|
CO_SIGNIN
+ d2->>r1: V|COORDINATOR|N2.COORDINATOR|H|
coordinator_sign_in
Note right of r1: stores N2 identity
- r1->>d2: V|N2.COORDINATOR|N1.COORDINATOR|H|ACK
+ r1->>d2: V|N2.COORDINATOR|N1.COORDINATOR|H|result
Note left of d2: Name is already "N1"
- d2->>r1: V|N2.COORDINATOR|N1.COORDINATOR|H|
Here is my local directory
and Coordinator addresses
+ d2->>r1: V|N2.COORDINATOR|N1.COORDINATOR|H|
add_nodes(Coordinator addresses)
record_components
Note right of r1: Updates global
Directory and signs
in to all unknown
Coordinators
Note over r1,d2: Sign out between two Coordinators
Note right of r1: shall sign out from N2
- d1->>r2: CO_SIGNOUT
+ d1->>r2: coordinator_sign_out
Note right of r2: removes N1 identity
- d2->>-r1: CO_SIGNOUT
+ d2->>-r1: coordinator_sign_out
Note right of r1: removes N2 identity
deactivate d1
:::
@@ -311,6 +311,10 @@ Each Coordinator shall keep an up-to-date global {ref}`control_protocol.md#direc
For this, whenever a Component signs in to or out from its Coordinator, the Coordinator shall notify all the other Coordinators regarding this event.
The other Coordinators shall update their global Directory according to this message (add or remove an entry).
+:::{note}
+TBD: These updates have to be determined.
+:::
+
On request, Coordinators shall send the Names of their local or global Directory, depending on the request type.
For the format of the Messages, see {ref}`control_protocol.md#message-layer`.
@@ -330,17 +334,102 @@ A Component MUST also offer a list of all possibly callable methods in accordanc
For such a RPC message, the first content frame MUST consist in a JSON-RPC compatible content, for example a single request object or a batch of request objects.
+### List of methods
-### Messages for Transport Layer
+List of methods defined by LECO.
+You MAY implement the optional methods of this list and you MUST implement the methods obligatory for your type of Component.
+All methods implemented in a Component MUST adhere to this list or MUST have a name different to any method in this list.
-- SIGNIN
-- SIGNOUT
-- ACKNOWLEDGE
-- ERROR
-- PING
-- CO_SIGNIN
-- CO_SIGNOUT
-:::{note}
-TODO How to make these messages work? Define them directly in the transport layer?
+#### Component
+
+Any Component, i.e. any participant in the LECO protocol, MUST offer the [OpenRPC Service Discovery Method](https://spec.open-rpc.org/#service-discovery-method) and the following methods.
+
+:::{data-viewer}
+:expand:
+:file: schemas/component.json
+:::
+
+Any Component MAY offer ANY of the following methods.
+Components SHOULD offer ``shut_down``.
+
+:::{data-viewer}
+:expand:
+:file: schemas/component_optional.json
+:::
+
+
+#### Coordinator
+
+Control protocol Coordinators are also {ref}`Components `.
+Furthermore, Coordinators MUST offer the following methods.
+
+:::{data-viewer}
+:expand:
+:file: schemas/coordinator.json
:::
+
+
+#### Actor
+
+An Actor is a {ref}`control_protocol.md#Component`.
+Additionally, it MUST offer the following methods.
+
+:::{data-viewer}
+:expand:
+:file: schemas/actor.json
+:::
+
+
+#### Polling Actor
+
+An {ref}`control_protocol.md#Actor`, which supports regular polling of values, MUST implement these methods.
+
+:::{data-viewer}
+:expand:
+:file: schemas/polling_actor.json
+:::
+
+
+#### Locking Actor
+
+An {ref}`control_protocol.md#Actor` which support locking resources MUST offer the following methods.
+
+:::{data-viewer}
+:expand:
+:file: schemas/locking_actor.json
+:::
+
+Accessing a locked resource (the whole Component or parts of it) or trying to unlock one, locked by another Component, will raise appropriate {ref}`control_protocol.md#errors`.
+
+
+### Errors
+
+Every error has a code and a message.
+Additionally they may have a ``data`` field with more information.
+
+According to JSONRPC, applications can define error codes between -32000 and -32099.
+LECO defines the following errors.
+
+
+#### Routing errors
+
+Errors related to routing (mainly emitted by Coordinators).
+Their error codes are in the range of -32090 to -32099.
+
+
+| code | message | data | description |
+|--------|------------------------------------|----------------------|--------------------------------------------------------------------------------------|
+| -32090 | Component not signed in yet! | Name of the Component| If a Component did not sign in. |
+| -32091 | The name is already taken. | Name of the Component| A Component tries to sign in, but another Component is signed in with the same name |
+| -32092 | Node is unknown. | Name of the Node | The Node to which the message should be sent, is not known to this Coordinator. |
+| -32093 | Receiver is not in addresses list. | Name of the receiver | The Component to which the message should be sent, is not known to this Coordinator. |
+
+
+#### Locking errors
+
+Errors related to locked Resources
+
+| code | message | data | description |
+|--------|------------------|------|----------------------------------------------|
+| -32050 | Resource locked! | - | The resource is locked by another component. |
diff --git a/environment.yml b/environment.yml
index ef2ff56..5499b1c 100644
--- a/environment.yml
+++ b/environment.yml
@@ -4,6 +4,8 @@ channels:
dependencies:
- myst-parser=0.18.1
- python=3.11
+ - pip
- sphinx=5.3.0
- sphinxcontrib-mermaid=0.8.1
- sphinx_rtd_theme=1.1.1
+ - sphinx-data-viewer=0.1.2
diff --git a/schemas/actor.json b/schemas/actor.json
new file mode 100644
index 0000000..33c92d7
--- /dev/null
+++ b/schemas/actor.json
@@ -0,0 +1,169 @@
+{
+ "openrpc": "1.2.6",
+ "info": {
+ "title": "Actor",
+ "version": "0.1.0"
+ },
+ "methods": [
+ {
+ "name": "get_parameters",
+ "description": "Get values of Device parameters.",
+ "params": [
+ {
+ "name": "parameters",
+ "description": "List of parameter names to get the values of.",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "required": true
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "object",
+ "description": "Object with parameter-value pairs",
+ "additionalProperties": true
+ },
+ "required": true
+ },
+ "examples": [
+ {
+ "name": "Get parameters example",
+ "params": [
+ {
+ "name": "parameters",
+ "value": ["parameter1", "parameter2"]
+ }
+ ],
+ "result": {
+ "name": "result",
+ "value": {
+ "parameter1": "value_of_parameter1",
+ "parameter2": "some_other_value"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "set_parameters",
+ "description": "Set values of Device parameters.",
+ "params": [
+ {
+ "name": "parameters",
+ "description": "Object with parameter-value pairs",
+ "schema": {
+ "type": "object",
+ "additionalProperties": true
+
+ },
+ "required": true
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ },
+ "examples": [
+ {
+ "name": "Set parameters example",
+ "params": [
+ {
+ "name": "parameters",
+ "value": {
+ "parameter1": "value_of_parameter1",
+ "parameter2": "some_other_value"
+ }
+ }
+ ],
+ "result": {
+ "name": "result",
+ "value": null
+ }
+ }
+ ]
+
+ },
+ {
+ "name": "call_action",
+ "description": "Call an Action of the Device.",
+ "params": [
+ {
+ "name": "action",
+ "description": "Name of the action to call.",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "args",
+ "description": "List of positional arguments.",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/any"
+ }
+ },
+ "required": false
+ }
+ ],
+ "result": {
+ "name": "result",
+ "description": "Result of the action.",
+ "schema": {
+ "$ref": "#/components/any"
+ },
+ "required": true
+ },
+ "examples": [
+ {
+ "name": "Calling some action 'action'.",
+ "params": [
+ {
+ "name": "action",
+ "value": "action"
+ },
+ {
+ "name": "args",
+ "value": [5, 7]
+
+ }
+ ],
+ "result": {
+ "name": "result",
+ "value": "result of `action(5, 7)`"
+ }
+ }
+ ]
+ }
+ ],
+ "components": {
+ "any" : {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ },
+ {
+ "type": "object"
+ }
+ ]
+ }
+ }
+}
diff --git a/schemas/component.json b/schemas/component.json
new file mode 100644
index 0000000..9342b88
--- /dev/null
+++ b/schemas/component.json
@@ -0,0 +1,21 @@
+{
+ "openrpc": "1.2.6",
+ "info": {
+ "title": "Component",
+ "version": "0.1.0"
+ },
+ "methods": [
+ {
+ "name": "pong",
+ "description": "Respond to a ping.",
+ "params": [],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ }
+ ]
+}
diff --git a/schemas/component_optional.json b/schemas/component_optional.json
new file mode 100644
index 0000000..bfac673
--- /dev/null
+++ b/schemas/component_optional.json
@@ -0,0 +1,44 @@
+{
+ "openrpc": "1.2.6",
+ "info": {
+ "title": "Component-optional",
+ "version": "0.1.0"
+ },
+ "methods": [
+ {
+ "name": "set_log_level",
+ "params": [
+ {
+ "name": "level",
+ "schema": {
+ "type": "string",
+ "enum": ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
+ },
+ "description": "The logging level, for a description of the different levels see https://docs.python.org/3/library/logging.html#logging-levels.",
+ "required": true
+ }
+ ],
+ "description": "Set the logging level.",
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "shut_down",
+ "params": [],
+ "description": "Shut down the Component.",
+ "result": {
+ "name": "result",
+ "schema": {
+
+ "type": "null"
+ },
+ "required": true
+ }
+ }
+ ]
+}
diff --git a/schemas/coordinator.json b/schemas/coordinator.json
new file mode 100644
index 0000000..55f4015
--- /dev/null
+++ b/schemas/coordinator.json
@@ -0,0 +1,244 @@
+{
+ "openrpc": "1.2.6",
+ "info": {
+ "title": "Coordinator",
+ "description": "Coordinates messages between LECO Components.",
+ "version": "0.1.0"
+ },
+ "methods": [
+ {
+ "name": "sign_in",
+ "params": [],
+ "description": "Sign in to this Coordinator.",
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ },
+ "errors": [
+ {
+ "code": -32091,
+ "message": "The name is already taken.",
+ "data": "Already taken name."
+ }
+ ]
+ },
+ {
+ "name": "sign_out",
+ "params": [],
+ "description": "Sign out from this Coordinator.",
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "coordinator_sign_in",
+ "params": [],
+ "description": "Sign in as a Coordinator to this Coordinator.",
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ },
+ "errors": [
+ {
+ "code": -32091,
+ "message": "The name is already taken.",
+ "data": "Already taken name."
+ }
+ ]
+ },
+ {
+ "name": "coordinator_sign_out",
+ "params": [],
+ "description": "Sign out as a Coordinator from this Coordinator.",
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "add_nodes",
+ "description": "Establish a connection to these nodes, if not yet connected.",
+ "params": [
+ {
+ "name": "nodes",
+ "schema": {
+ "$ref": "#/components/nodes"
+ }
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ },
+ "examples": [
+ {
+ "name": "Add nodes example",
+ "params": [
+ {
+ "name": "nodes",
+ "value": {
+ "Namespace1": "host_of_namespace1:12345",
+ "Namespace2": "host_of_namespace2:54321"
+ }
+ }
+ ],
+ "result": {
+ "name": "result",
+ "value": null
+ }
+ }
+ ]
+ },
+ {
+ "name": "send_nodes",
+ "params": [],
+ "description": "Send the names and addresses of the nodes known to this Coordinator.",
+ "result": {
+ "name": "result",
+ "schema": {
+ "$ref": "#/components/nodes"
+ },
+ "required": true
+ },
+ "examples": [
+ {
+ "name": "Send nodes example",
+ "params": [],
+ "result": {
+ "name": "result",
+ "value": {
+ "Namespace1": "host_of_namespace1:12345",
+ "Namespace2": "host_of_namespace2:54321"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "record_components",
+ "description": "Record Components of another Coordinator.",
+ "params": [
+ {
+ "name": "components",
+ "description": "List of Components' names.",
+ "schema": {
+ "$ref": "#/components/components_array"
+ },
+ "required": true
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "send_local_components",
+ "params": [],
+ "description": "Send the names of locally connected Components.",
+ "result": {
+ "name": "result",
+ "schema": {
+ "$ref": "#/components/components_array"
+ },
+ "required": true
+ },
+ "examples": [
+ {
+ "name": "Send local directory example",
+ "params": [],
+ "result": {
+ "name": "result",
+ "value": [
+ "ComponentA",
+ "ComponentB"
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "send_global_components",
+ "params": [],
+ "description": "Send the names of all Components in this LECO network.",
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "object",
+ "description": "Object with 'namespace'-'array of component names' pairs.",
+ "additionalProperties": {
+ "$ref": "#/components/components_array"
+ }
+ }
+ },
+ "examples": [
+ {
+ "name": "Global directory example.",
+ "params": [],
+ "result": {
+ "name": "result",
+ "value": {
+ "Namespace1": ["Namespace1.ComponentA", "Namespace1.ComponentB"],
+ "Namespace2": ["Namespace2.ComponentC", "Namespace2.ComponentD", "Namespace2.ComponentE"],
+ "Namespace3": ["Namespace3.ComponentF"]
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "remove_expired_addresses",
+ "description": "Clean all expired addresses from the directory.",
+ "params": [
+ {
+ "name": "expiration_time",
+ "description": "Expiration time of Components and Coordinators in seconds.",
+ "schema": {
+ "type": "number"
+ },
+ "required": true
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ }
+ ],
+ "components": {
+ "nodes" : {
+ "type": "object",
+ "additionalProperties": {"type": "string"},
+ "description": "Object with 'node'-'address' pairs as properties."
+ },
+ "components_array": {
+ "type": "array",
+ "description": "List of Components' names.",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+}
diff --git a/schemas/locking_actor.json b/schemas/locking_actor.json
new file mode 100644
index 0000000..e1e7b11
--- /dev/null
+++ b/schemas/locking_actor.json
@@ -0,0 +1,72 @@
+{
+ "openrpc": "1.2.6",
+ "info": {
+ "title": "Locking Actor",
+ "version": "0.1.0"
+ },
+ "methods": [
+ {
+ "name": "lock",
+ "description": "Lock this Component or a resource of it, such that no other Component may use it.",
+ "params": [
+ {
+ "name": "resource",
+ "schema": {
+ "type": "string"
+ },
+ "required": false
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "boolean",
+ "description": "Whether locking succeeded or not."
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "unlock",
+ "description": "Unlock this Component or a resource of it, such that other Component may use it again. Only the locking Component may unlock.",
+ "params": [
+ {
+ "name": "resource",
+ "schema": {
+ "type": "string"
+ },
+ "required": false
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "boolean",
+ "description": "Whether unlocking succeeded or not."
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "force_unlock",
+ "description": "Unock this Component or a resource of it, such that other Component may use it. This may be used even if someone else locked the resource.",
+ "params": [
+ {
+ "name": "resource",
+ "schema": {
+ "type": "string"
+ },
+ "required": false
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "boolean",
+ "description": "Whether force unlocking succeeded or not."
+ },
+ "required": true
+ }
+ }
+ ]
+}
diff --git a/schemas/polling_actor.json b/schemas/polling_actor.json
new file mode 100644
index 0000000..2fc9700
--- /dev/null
+++ b/schemas/polling_actor.json
@@ -0,0 +1,76 @@
+{
+ "openrpc": "1.2.6",
+ "info": {
+ "title": "Polling Actor",
+ "version": "0.1.0"
+ },
+ "methods": [
+ {
+ "name": "start_polling",
+ "description": "Start to poll some values regularly.",
+ "params": [
+ {
+ "name": "polling_interval",
+ "description": "Polling interval in seconds.",
+ "schema": {
+ "type": "number"
+ },
+ "required": false
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "stop_polling",
+ "description": "Stop to poll regularly.",
+ "params": [],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "get_polling_interval",
+ "description": "Get the polling interval.",
+ "params": [],
+ "result": {
+ "name": "result",
+ "description": "The polling interval in seconds.",
+ "schema": {
+ "type": "number"
+ },
+ "required": true
+ }
+ },
+ {
+ "name": "set_polling_interval",
+ "description": "Set the polling interval",
+ "params": [
+ {
+ "name": "polling_interval",
+ "description": "Polling interval in seconds.",
+ "schema": {
+ "type": "number"
+ },
+ "required": true
+ }
+ ],
+ "result": {
+ "name": "result",
+ "schema": {
+ "type": "null"
+ },
+ "required": true
+ }
+ }
+ ]
+}