mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-24 15:27:17 +00:00
docs: explain the "robot" module in a high level way (#1081)
This commit adds a README file at `lib/shared/robot` explaining in detail how the "robot" mechanism works, and why it is needed. Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
parent
db8f7d0862
commit
43c08d1547
128
lib/shared/robot/README.md
Normal file
128
lib/shared/robot/README.md
Normal file
@ -0,0 +1,128 @@
|
||||
The "robot" mechanism
|
||||
=====================
|
||||
|
||||
As discussed in [`lib/child-writer`][child-writer], communication between the
|
||||
main Etcher application and its elevated writer process happens through an IPC
|
||||
(Inter Process Communication) channel. In a nutshell, we emit every single line
|
||||
that the writer process prints to the parent as a "message". Since these
|
||||
"lines" need to convey non-trivial information such as progress information,
|
||||
speed, final computer checksums, etc we are in need of a basic form of a
|
||||
"protocol".
|
||||
|
||||
The "robot" module is the entity that implements this protocol, and provides
|
||||
utility functions to read/send messages using the protocol targeted at both
|
||||
parties (the client and the writer processes).
|
||||
|
||||
The contents and structure of these messages is what the "robot" module is
|
||||
mainly concerned with. Each "message" consists of a type (a "command" in robot
|
||||
parlance) and an arbitrary data object:
|
||||
|
||||
- `String command`: the message command name
|
||||
- `Object data`: the message data
|
||||
|
||||
For example:
|
||||
|
||||
*Child process:*
|
||||
|
||||
```js
|
||||
robot.printMessage('my-message-type', {
|
||||
my: {
|
||||
message: 'data'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
*Parent process:*
|
||||
|
||||
```js
|
||||
const message = robot.parseMessage(line);
|
||||
|
||||
console.log(robot.getCommand(message));
|
||||
> 'my-message-type'
|
||||
|
||||
console.log(robot.getData(message));
|
||||
> {
|
||||
> my: {
|
||||
> message: 'data'
|
||||
> }
|
||||
> }
|
||||
```
|
||||
|
||||
The codename "robot" is inspired by [xz][xz-man], which provides a `--robot`
|
||||
option that makes the tool print machine-parseable output:
|
||||
|
||||
```
|
||||
--robot
|
||||
Print messages in a machine-parsable format. This is intended
|
||||
to ease writing frontends that want to use xz instead of
|
||||
liblzma, which may be the case with various scripts. The output
|
||||
with this option enabled is meant to be stable across xz
|
||||
releases. See the section ROBOT MODE for details.
|
||||
```
|
||||
|
||||
To enable the "robot" option, we standardised the presence of an
|
||||
`ETCHER_CLI_ROBOT` environment variable. You can check if the mode is enabled
|
||||
by using the `.isEnabled()` static function that the robot module provides:
|
||||
|
||||
```js
|
||||
if (robot.isEnabled()) {
|
||||
console.log('The robot option is enabled');
|
||||
}
|
||||
```
|
||||
|
||||
The current protocol that we use is based on JSON. The writer process
|
||||
stringifies a JSON object, and prints it. The client then gets the line, parses
|
||||
it as JSON, and accesses the object.
|
||||
|
||||
For example, the writer process may have a fictitious internal object that
|
||||
looks like this:
|
||||
|
||||
```js
|
||||
{
|
||||
percentage: 50,
|
||||
stage: 'validation'
|
||||
}
|
||||
```
|
||||
|
||||
That object can be stringified as `{"percentage":50,"stage":"validation"}` and
|
||||
printed to `stdout`.
|
||||
|
||||
This is what a valid robot message looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "progress",
|
||||
"data": {
|
||||
"percentage": 50
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The command content and the data associated with it are application specific,
|
||||
however the robot module defines a single command called "error", which is used
|
||||
to transmit a JavaScript Error object, along with its metadata (stacktrace,
|
||||
code, description, etc) as a string.
|
||||
|
||||
You don't have to worry about the internal details of how an Error object is
|
||||
encoded/decoded, given that the robot module exposes two high level utility
|
||||
functions: `.printError()` and `.recomposeErrorMessage()`.
|
||||
|
||||
Here's an example of these functions in action:
|
||||
|
||||
```javascript
|
||||
const error = new Error('This is an error');
|
||||
robot.printError(error);
|
||||
```
|
||||
|
||||
The client can then fetch the line, and recompose it back:
|
||||
|
||||
```javascript
|
||||
const error = robot.recomposeErrorMessage(line);
|
||||
```
|
||||
|
||||
The resulting `error` inherits the stacktrace and other metadata from the
|
||||
original error, even if this was created in another process. This is how the
|
||||
writer process propagates informational errors to the GUI.
|
||||
|
||||
[xz-man]: https://www.freebsd.org/cgi/man.cgi?query=xz&sektion=1&manpath=FreeBSD+8.3-RELEASE
|
||||
[child-writer]: https://github.com/resin-io/etcher/tree/master/lib/child-writer
|
Loading…
x
Reference in New Issue
Block a user