Juggler communication protocol

Juggler is communication protocol used for communication between back-end and GUI front-end parts of components. As underlying protocol, Juggler uses WebSocket communication.

Juggler is composed of two communication layers:

  • transport layer

  • user layer

By defining communication in two distinctive layers, juggler enables transport of large user data with benefits of segmented communication. Because of the restricted WebSocket API available in web browsers, usage of WebSocket messages with limited payload size is required for reliable detection of communication activity and correct “keep alive” implementation.

Transport layer

Juggler transport layer is used for transmission of arbitrary JSON data - user layer messages. Each user message is encoded as UTF-8 JSON string and segmented into multiple parts. Each segment is is prepended with transport header and sent as single WebSocket text message.

In addition to transporting user messages, transport layer provides transport packages for detection of broken connection.

Transport packages are formatted as:

    0        1      ...     n+1
+--------+----------------------+
| header |   payload (n bytes)  |
+--------+----------------------+

where:

  • header - utf-8 encoded single character identifying package type

  • payload - user message segment (0 or more bytes)

Supported package types are:

  • 0 - package transporting last segment of single user message

  • 1 - package transporting non last segment of single user message

  • 2 - ping request

  • 3 - ping response

Transport layer between peers is symmetrical. Once client establish connection with server, each of the two peers can send user messages and ping requests at any time.

When user layer requests sending of user message, transport layer will encode and segment original message into segments that do not exceed configured maximum segment length. Then each segment is sequentially sent where all segments except for last are prepended with package type 1 and last is prepended with package type 0. Only when all segments of single user message are sent, transport layer can send next user message.

When peer receives ping request package (package type 2) it must immediately respond with ping response (package type 3) containing same payload as ping request. Ping response should be sent without concern to active segment sequence - it can occur as additional package between two packages containing segments of single user message.

User layer

Communication between peers is asymmetrical - distinct client and server entities are identified. Entity responsible for initiating Web socket connection is considered client. Entity which receives request for Web socket initialization is considered server.

After Web socket initialization, Juggler user layer enables communication which can be classified as:

  • request/response

  • server state synchronization

  • server notification

Each of these communication models is independent of one another and can be conducted in parallel using single Juggler transport layer.

Request/response

Request/response communication is based on message exchange where client sends request message after which server sends associated response message.

request messages include:

  • id

    Request message identifier unique to corresponding Juggler connection, generated by client.

  • name

    Label describing request semantics.

  • data

    Arbitrary request payload with structure corresponding to associated name.

response messages include:

  • id

    Response identifier matching associated request identifier.

  • success

    Boolean flag indicating successful execution of action initiated by client’s request.

  • data

    Arbitrary response payload. In case success flag is true, this data represents result of action execution. In case success flag is false, this data represents error description associated with action execution.

At any time, client can send new request message. Upon receiving request message, server must respond with response message containing same id as provided by associated request message.

Parallel execution of multiple request/response sessions should be supported (client can send new requests without receiving responses for all previously sent requests).

Server state synchronization

After Web socket initialization, server and client should assume existence of single data, refereed as server state, with initial value of null.

At any time, server can change it’s local value of server state. These changes should be accompanied with state messages sent to client. state message contains description of change that is made to server’s local server state formatted as JSON Patch.

Consecutive changes to servers local server state can be buffered (with appropriate timeout) and sent to client as single state message. Eventually, client should be able to reconstruct exact value of server state by consecutive application of received changes to it’s own local server state data.

Server notification

At any time, server can send unsolicited notify messages to client.

notify messages include:

  • name

    Label describing notification semantics.

  • data

    Arbitrary notification payload with structure corresponding to associated name.

Messages

$schema: "https://json-schema.org/draft/2020-12/schema"
$id: "hat-juggler://messages.yaml"
$defs:
    request:
        type: object
        required:
            - type
            - id
            - name
            - data
        properties:
            type:
                const: request
            id:
                type: integer
            name:
                type: string
    response:
        type: object
        required:
            - type
            - id
            - success
            - data
        properties:
            type:
                const: response
            id:
                type: integer
            success:
                type: boolean
    state:
        type: object
        required:
            - type
            - diff
        properties:
            type:
                const: state
    notify:
        type: object
        required:
            - type
            - name
            - data
        properties:
            type:
                const: notify
            name:
                type: string