Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 449 lines (356 sloc) 9.74 KB

nes Protocol v2.4.x

Message

The nes protocol consists of JSON messages sent between the client and server.

Each incoming request from the client to the server contains:

  • type - the message type:
    • 'ping' - heartbeat response.
    • 'hello' - connection initialization and authentication.
    • 'reauth' - authentication refresh.
    • 'request' - endpoint request.
    • 'sub' - subscribe to a path.
    • 'unsub' - unsubscribe from a path.
    • 'message' - send custom message.
  • id - a unique per-client request id (number or string).
  • additional type-specific fields.

Each outgoing request from the server to the client contains:

  • type - the message type:
    • 'ping' - heartbeat request.
    • 'hello' - connection initialization and authentication.
    • 'reauth' - authentication refresh.
    • 'request' - endpoint request.
    • 'sub' - subscribe to a path.
    • 'unsub' - unsubscribe from a path.
    • 'message' - send custom message.
    • 'update' - a custom message push from the server.
    • 'pub' - a subscription update.
    • 'revoke' - server forcedly removed the client from a subscription.
  • additional type-specific fields.

If a message is too large to send as a single WebSocket update, it can be chunked into multiple messages. After constructing the JSON message string, the string is sliced into chunked and each is sent with the '+' prefix except for the last chunk sent with the '!' prefix.

Errors

When a message indicates an error, the message will include in addition to the message-specific fields:

  • statusCode - an HTTP equivalent status code (4xx, 5xx).
  • headers - optional headers related to the request.
  • payload - the error details which include:
    • error - the HTTP equivalent error message.
    • message - a description of the error.
    • additional error-specific fields.

For example:

{
    type: 'hello',
    id: 1,
    statusCode: 401,
    payload: {
        error: 'Unauthorized',
        message: 'Unknown username or incorrect password'
    }
}

Heartbeat

Flow: server -> client -> server

For cases where it is not possible for the TCP connection to determine if the connection is still active, the server sends a heartbeat message to the client every configured interval, and then expects the client to respond within a configured timeout. The server sends:

  • type - set to 'ping'.

For example:

{
    type: 'ping'
}

When the client receives the message, it sends back:

  • type - set to 'ping'.
  • id - a unique per-client request id (number or string).

For example:

{
    type: 'ping',
    id: 6
}

Hello

Flow: client -> server -> client

Every client connection must first be initialized with a hello message. The client sends a message to the server with the following:

  • type - set to 'hello'.
  • id - a unique per-client request id (number or string).
  • version - set to '2'.
  • auth - optional authentication credentials. Can be any value understood by the server.
  • subs - an optional array of strings indicating the path subscriptions the client is interested in.

For example:

{
    type: 'hello',
    id: 1,
    version: '2',
    auth: {
        headers: {
            authorization: 'Basic am9objpzZWNyZXQ='
        }
    },
    subs: ['/a', '/b']
}

The server responds by sending a message back with the following:

  • type - set to 'hello'.
  • id - the same id received from the client.
  • heartbeat - the server heartbeat configuration which can be:
    • false - no heartbeats will be sent.
    • an object with:
      • interval - the heartbeat interval in milliseconds.
      • timeout - the time from sending a heartbeat to the client until a response is expected before a connection is considered closed by the server.
  • socket - the server generated socket identifier for the connection.

Note: the client should assume the connection is closed if it has not heard from the server in heartbeat.interval + heartbeat.timeout.

For example:

{
    type: 'hello',
    id: 1,
    heartbeat: {
        interval: 15000,
        timeout: 5000
    },
    socket: 'abc-123'
}

If the request failed (including subscription errors), the server includes the standard error fields.

For example:

{
    type: 'hello',
    id: 1,
    statusCode: 401,
    payload: {
        error: 'Unauthorized',
        message: 'Unknown username or incorrect password'
    }
}

If the request fails due to a subscription error, the server will include the failed subscription path in the response:

  • path - the requested path which failed to subscribe.

For example:

{
    type: 'hello',
    id: 1,
    path: '/a',
    statusCode: 403,
    payload: {
        error: 'Subscription not found'
    }
}

Reauthenticate

Flow: client -> server -> client

When the authentication credentials have an expiry, the client may want to update the authentication information for the connection:

  • type - set to 'reauth'.
  • id - a unique per-client request id (number or string).
  • auth - authentication credentials. Can be any value understood by the server.

For example:

{
    type: 'reauth',
    id: 1,
    auth: {
        headers: {
            authorization: 'Basic am9objpzZWNyZXQ='
        }
    }
}

The server responds by sending a message back with the following:

  • type - set to 'reauth'.
  • id - the same id received from the client.

For example:

{
    type: 'reauth',
    id: 1
}

If the request failed, the server includes the standard error fields.

For example:

{
    type: 'reauth',
    id: 1,
    statusCode: 401,
    payload: {
        error: 'Unauthorized',
        message: 'Unknown username or incorrect password'
    }
}

Request

Flow: client -> server -> client

Request a resource from the server where:

  • type - set to 'request'.
  • id - a unique per-client request id (number or string).
  • method - the corresponding HTTP method (e.g. 'GET').
  • path - the requested resource (can be an HTTP path or resource name).
  • headers - an optional object with the request headers (each header name is a key with a corresponding value).
  • payload - an optional value to send with the request.

For example:

{
    type: 'request',
    id: 2,
    method: 'POST',
    path: '/item/5',
    payload: {
        id: 5,
        status: 'done'
    }
}

The server response includes:

  • type - set to 'request'.
  • id - the same id received from the client.
  • statusCode - an HTTP equivalent status code.
  • payload - the requested resource.
  • headers - optional headers related to the request (e.g. `{ 'content-type': 'text/html; charset=utf-8' }').

For example:

{
    type: 'request',
    id: 2,
    statusCode: 200,
    payload: {
        status: 'ok'
    }
}

If the request fails, the statusCode, headers, and payload fields will comply with the standard error values.

Message

Flow: client -> server [-> client]

Sends a custom message to the server where:

  • type - set to 'message'.
  • id - a unique per-client request id (number or string).
  • message - any value (string, object, etc.).

For example:

{
    type: 'message',
    id: 3,
    message: 'hi'
}

The server response includes:

  • type - set to 'message'.
  • id - the same id received from the client.
  • message - any value (string, object, etc.).

For example:

{
    type: 'message',
    id: 3,
    message: 'hello back'
}

If the request fails, the response will include the standard error fields.

Subscribe

Flow: client -> server [-> client]

Sends a subscription request to the server:

  • type - set to 'sub'.
  • id - a unique per-client request id (number or string).
  • path - the requested subscription path.

For example:

{
    type: 'sub',
    id: 4,
    path: '/box/blue'
}

The server response includes:

  • type - set to 'sub'.
  • id - the same id received from the client.
  • path - the requested path which failed to subscribe.
  • the standard error fields if failed.

For example:

{
    type: 'sub',
    id: 4,
    path: '/box/blue',
    statusCode: 403,
    payload: {
        error: 'Forbidden'
    }
}

Unsubscribe

Flow: client -> server -> client

Unsubscribe from a server subscription:

  • type - set to 'unsub'.
  • id - a unique per-client request id (number or string).
  • path - the subscription path.

For example:

{
    type: 'unsub',
    id: 5,
    path: '/box/blue'
}

The server response includes:

For example:

{
    type: 'unsub',
    id: 5
}

Update

Flow: server -> client

A custom message sent from the server to a specific client or to all connected clients:

  • type - set to 'update'.
  • message - any value (string, object, etc.).
{
    type: 'update',
    message: {
        some: 'message'
    }
}

Publish

Flow: server -> client

A message sent from the server to all subscribed clients:

  • type - set to 'pub'.
  • path - the subscription path.
  • message - any value (string, object, etc.).
{
    type: 'pub',
    path: '/box/blue',
    message: {
        status: 'closed'
    }
}

Revoked

Flow: server -> client

The server forcefully removed the client from a subscription:

  • type - set to 'revoke'.
  • path - the subscription path.
  • message - any value (string, object, etc.). An optional last message sent to the client for the specified subscription.

For example:

{
    type: 'revoke',
    path: '/box/blue',
    message: {
        reason: 'channel permissions changed'
    }
}