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:
Juan Cruz Viotti 2017-02-10 11:59:23 -04:00 committed by GitHub
parent db8f7d0862
commit 43c08d1547
2 changed files with 128 additions and 0 deletions

128
lib/shared/robot/README.md Normal file
View 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