# Runtime Architecture
## Generated Libraries

When using `jsii-pacmak` to generate libraries in different programming
languages, the **Javascript** code is bundled within the generated library, so
that it can be used at runtime. This is the reason why a `node` runtime
needs to be available in order to execute code that depends on *jsii* libraries.

The generated libraries have a dependency on a *Runtime client* library for the
language, which contains the necessary logic to start a child `node` process
with the `jsii-runtime`. The `jsii-runtime` manages JSON-based inter-process
communication over its `STDIN`, `STDOUT` and `STDERR`, and manages a
`@jsii/kernel` instance that acts as a container for the **Javascript** code
that backs the *jsii* libraries.

## Architecture Overview

A representation of the execution environment of an application using *jsii*
libraries from a different language follows:

```
┌─────────────────────────┐               ┌────────────┬────┬────┬────┐
│                         │               │            │    │    │    │
│    Host Application     │               │@jsii/kernel│LibA│LibB│... │
│                         │               │            │    │    │    │
│      ┌──────────────────┤               ├────────────┴────┴────┴────┤
│      │                  │               │                           │
│      │Generated Bindings│               │       @jsii/runtime       │
│      │                  │               │                           │
│      ├──────────────────┤   Requests    ├──────┬────────────────────┤
│      │                  ├───────────────▶STDIN │                    │
│      │Host jsii Runtime │   Responses   ├──────┤                    │
│      │     Library      ◀───────────────┤STDOUT│                    │
│      │                  │    Console    ├──────┤    node            │
│      │                  ◀───────────────┤STDERR│                    │
├──────┴──────────────────┤               ├──────┘                    │
│      Host Runtime       │               │      (Child Process)      │
│  (JVM, .NET Core, ...)  │               │                           │
│                         │               │                           │
├─────────────────────────┴───────────────┴───────────────────────────┤
│                                                                     │
│                          Operating System                           │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
```

## Communication Protocol

As shown in the [architecture overview](#architecture-overview) diagram, the
`@jsii/runtime` process receives requests via its `STDIN` stream, sends
responses via its `STDOUT` stream, and sends console output through the `STDERR`
stream.

All those messages are sent in JSON-encoded objects. On `STDIN` and `STDOUT`,
the request-response protocol is defined by the [kernel api specification]. On
`STDERR` messages are encoded in the following way:

- `#!json { "stderr": "<base64-encoded data>" }` when the console data is to be
  written on the *Host Application*'s `STDERR` stream.
- `#!json { "stdout": "<base64-encoded data>" }` when the console data is to be
  written on the *Host Application*'s `STDOUT` stream.
- Any data that is not valid JSON, or that does not match either of the formats
  described above must be written as-is on the *Host Application*'s `STDERR`
  stream.

[kernel api specification]: ../specification/3-kernel-api.md

In order to allow the hosted original **JavaScript** libraries to naturally
interact with `process.stdout`, `process.stderr` and all other APIs that make
use of those streams (such as `console.log` and `console.error`), the
`@jsii/runtime` process does in fact spawn a second `node` process to allow
intercepting the console data to properly encode it. Below is a diagram
describing the process arrangement that achieves this:

```
                                          ┌────────────┬────┬────┬────┐
                                          │            │    │    │    │
                                          │@jsii/kernel│LibA│LibB│... │
                                          │            │    │    │    │
┌─────────────────────────┐               ├────────────┴────┴────┴────┤
│                         │               │                           │
│  @jsii/runtime Wrapper  │               │    @jsii/runtime Core     │
│                         │               │                           │
├──────┬──────────────────┤               ├──────┬────────────────────┤
│STDIN │                  │        X──────▶STDIN │                    │
├──────┤                  │    Console    ├──────┤                    │
│STDOUT│                  ◀───────────────┤STDOUT│                    │
├──────┤                  │    Console    ├──────┤        node        │
│STDERR│   node           ◀───────────────┤STDERR│                    │
├──────┘                  │     JSON      ├──────┤  (Child Process)   │
│                         ◀───────────────▶ FD#3 │                    │
│                         │               ├──────┘                    │
│                         │               │                           │
├─────────────────────────┴───────────────┴───────────────────────────┤
│                                                                     │
│                          Operating System                           │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
```

!!! bug "Missing Feature"
    As shown on the diagram above, there is nothing connected to the *Core*
    process' `FD#0` (`STDIN`). This feature will be added in the future, but
    currently this means *jsii* libraries have no way of accepting input through
    `STDIN`.

The *Wrapper* process manages the *Core* process such that:

!!! info
    It would be possible to use a single `node` process (the *`@jsii/runtime`
    Core* process) for any platform that supposed spawning child processes with
    additional open file descriptors. This is for example not possible in
    **Java** and **C#**, which is why this dual-process contraption was devised.

    In such cases, the *Host Application* would spawn the *Core* process and
    directly operate on the file descriptors as described below.

- Any requests received from the *Host Application* through the *Wrapper*'s
  `STDIN` stream is forwarded to the *Core* process' `FD#3`.
- Any response written to the *Core*'s `FD#3` stream is forwarded to the *Host
  Application* though the *Wrapper*'s `STDOUT`.
- Any data sent to the *Core*'s `STDERR` is base64-encoded and wrapped in a JSON
  object with the `"stderr"` key, then forwarded to the *Host
  Application* through the *Wrapper*'s `STDERR`
- Any data sent to the *Core*'s `STDOUT` is base64-encoded and wrapped in a JSON
  object with the `"stdout"` key, then forwarded to the *Host
  Application* through the *Wrapper*'s `STDERR`

!!! danger
    As with any file descriptor besides `FD#0` (`STDIN`), `FD#1` (`STDOUT`) and
    `FD#2` (`STDERR`) that was not opened by the application, **JavaScript**
    libraries loaded in the `@jsii/kernel` instance are not allowed to interact
    directly with file descriptor `FD#3`.

## Initialization Process

The initialization workflow can be described as:

1. The *host* (**Java**, **.NET**, ...) application starts on its own runtime
    (JVM, .NET Runtime, ...)
2. When the *host* code encounters a *jsii* entity for the first time (creating
    an instance of a *jsii* type, loading a static constant, ...), the *runtime
    client library* creates a child `node` process, and loads the `jsii-runtime`
    library (specified by the `JSII_RUNTIME` environment variable, or the
    version that is bundled in the *runtime client library*)
3. The *runtime client library*  interacts with the child `node` process by
    exchanging JSON-encoded messages through the `node` process' *STDIN* and
    `STDOUT`. It maintains a thread (or equivalent) that decodes messages from
    the child's `STDERR` stream, and forwards the decoded data to it's host
    process' `STDERR` and `STDOUT` as needed.
4. The *runtime client library* automatically loads the **Javascript** modules
    bundled within the *generated bindings* (and their depedencies, bundled in
    other *generated bindings*) into the `node` process when needed.
5. Calls into the *Generated bindings* are encoded into JSON requests and sent
    to the child `node` process, which will execute the corresponding
    **Javascript** code, then responds back.
6. Upon exiting, the *host* process closes the communication channels with the
    child `node` process, causing it to exit.