Skip to content
Alexei Sholik edited this page Jun 2, 2014 · 7 revisions

In order for Porcelain and goon to work together, a simple protocol is defined that is used for all communications between the two components.

In Elixir, we always do Port.open {:spawn_executable, <path to goon>}, ... and then exchange messages with the spawned instance of goon. We use simple framing to be able to pass data to the external program managed by goon with as little overhead as possible.

Handshake

Before exhanging data between Elixir and goon, we need to make sure that both components have compatible versions. This is verified during the handshake.

The handshake is performed as follows:

  1. The Goon driver spawn the goon executable with at least the following command-line flags:

     goon -proto 1 -ack abcd1234 <program>
    

    The flags are defined as follows:

    • -proto specifies the protocol version to use. Elixir and goon will be able to communicate only when the goon client supports the requested protocol version (it can support more than one).

    • -ack takes an arbitrary string as its argument.

    • <program> is the name of the program to run.

First thing the goon program will output is the signature containing the ack string and its crc32 checksum, like this:

abcd1234:1027584326:ok\0

where the first field is the ack value, the second field is its crc32 checksum, and the third field is the handshake status. If it is not ok, it means an error has occurred and goon terminates immediately.

If it is ok, the Elixir side will check that the ack string and its checksum are correct. After that, everything returned from goon is expected to be the actual program output.

Communication

Output forwarding

Because Elixir is able to communicate with goon through a single channel, output from the external program needs to be framed in order to distinguish stderr and stdout channels. The framing is very simple: goon prepends one character to each packet it sends to Elixir. The char o stands for stdout and e stands for stderr.

It should be mentioned that there are actually two levels of framing going on from the goon's point of view. The low-level framing is implemented by passing {:packet, 2} option to the Erlang's open_port function. This means that data going in either direction between Elixir and goon is composed of packets prepended by 2-byte length of the packet content.

On the Elixir side packets are decoded automatically whereas on the Go side we need to do this by hand.

The application level framing is only concerned with distinguishing stdout and stderr and it has been described above.

Input forwarding

TODO

Signal forwarding

TODO

Future extensions

Any future extension to the protocol will increment its version. Trying to spawn a goon with unsupported protocol version will fail with an error.

Clone this wiki locally