The LanguageLink protocol
LanguageLink uses a custom protocol for communication between Glamorous Toolkit and the language server. In this page we give an overview of the protocol format.
The LanguageLink protocol uses either JSON or MsgPack, a binary serialization format similar to JSON. The relevant classes implementing the encodings are subclasses of PharoLinkAbstractMessageBroker
.
The encoded messages contain dictionaries describing commands and responses between Glamorous Toolkit and the language server. They are encoded as follows:
{ 'type' -> msgType. "explained later" '__sync' -> isSync. "depends on the type of the message" "... various other keys dependent on the message type" } asDictionary
To understand the protocol better, we will have to discuss message types. The following types exist:
- ENQUEUE
: Enqueues a command, usually an evaluation, on the language server. Asynchronous.
- IS_ALIVE
: sends a heartbeat. Synchronous, sent periodically. The answer is expected to be the string IS_ALIVE
.
Server implementations can implement custom message types, but none are implemented by any of the standard language implementations.
The ENQUEUE
command (implemented in LanguageLinkEnqueueCommandMessage
) is the central command for communication. It is sent for every code evaluation inside GT, whether triggered programatically or through a snippet.
ENQUEUE
commands contain other keys in the message describing the evaluation request. The shape is as follows:
{ 'type' -> 'ENQUEUE'. '__sync' -> false. 'commandId' -> 1234. "a unique identifier for the command" 'statements' -> '1 + x'. "the code to run, language-specific" 'bindings' -> { 'x' -> 15 } asDictionary "custom bindings to inject into the language" } asDictionary
Bindings should usually be kept by the server, but can be injected from the GT side. This is useful for, e.g., keeping cross-language bindings, as is possible in the Python snippet.
Contrary to what one would probably expect from an endpoint like this, but true to its command name, this is not expected to return the answer directly, but rather enqueue that command for asynchronous evaluation. This setup is used to avoid any long blocking calls between the server and Glamorous Toolkit.
A server is expected to execute an enqueued command asynchronously, at some point returning the evaluation result by sending a message to an endpoint called EVAL
owned by the GT instance.
Taking the example ENQUEUE
statement above, we could respond to it like so if we were using the JSON encoder:
client := ZnClient new forJsonREST. client url: 'http://localhost:', port , '/EVAL'. client entity: { 'type' -> 'EVAL'. 'id' -> 1234. "the ID must match the command ID sent above" 'value' -> '16'. "this is sent directly to the encoder used by the language; more details below" '__sync' -> false } asDictionary
The port here may be injected in various ways, depending on how the server is set up, but it should match wahtever is set in the LanguageLinkSettings
class used by the application (for some references refer to LanguageLinkSettings>>#jsDefaultSettings
, LanguageLinkSettings>>#pharoDefaultSettings
, or PBPlatform>>#defaultSettings
).