-
Notifications
You must be signed in to change notification settings - Fork 45
Goex Protocol
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.
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:
-
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 andgoon
will be able to communicate only when thegoon
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.
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.
TODO
TODO
Any future extension to the protocol will increment its version. Trying to
spawn a goon
with unsupported protocol version will fail with an error.