Logux uses Back-end Protocol to make a proxy between WebSocket and HTTP. Logux Server sends the user’s authentication requests, subscriptions, and actions to an HTTP server and receives new actions by HTTP to send them to Logux clients.

Requests

Logux Server sends HTTP requests to single entry point (user specifies URL by LOGUX_BACKEND) with POST method and JSON to encode the body.

Each request contains protocol version (the latest version is 2), the secret to protect servers from unknown requests from Internet (you set this secret by LOGUX_CONTROL_SECRET) and list of commands.

{
  version: number,
  secret: string,
  commands: Command[]
}

Requests from Logux server to back-end server use auth and action commands. Requests from a back-end server to Logux server use only action command.

For performance reasons, each request can contain multiple commands from different users.

The HTTP response contains an array of responses. Responses could have a different order than commands. Some commands require more than one answer during processing.

HTTP server should use keep-alive HTTP response to write answers to TCP socket during the processing. It will be bad for performance if the server will write answers for all commands only when the latest command was processed.

Answer[]

auth

{
  command: "auth",
  authId: string,
  userId: string,
  token?: string,
  subprotocol: string,
  cookie: {
    [name]: string
  },
  headers: {
    [name]: string
  }
}

auth command asks back-end server to authenticate the user by ID, token, cookie and Logux’s headers. authId is used to specify the command, when the HTTP request contains multiple auth commands.

On correct user ID and credentials back-end server must answer authenticated with server’s subprotocol.

{
  answer: "authenticated",
  subprotocol: string,
  authId: string
}

On wrong credentials or unknown user ID:

{
  answer: "denied",
  authId: string
}

If back-end do not support client’s subprotocol, with the npm range of supported subprotocols.

{
  answer: "wrongSubprotocol",
  authId: string,
  supported: string
}

On any error during the authentication (details can be used for stack-trace):

{
  answer: "error",
  authId: string,
  details: string
}

See authentication example.

action

{
  command: "action",
  action: Action,
  meta: Meta,
  headers: {
    [name]: string
  }
}

Logux server uses action command to ask the back-end server to process action or subscription. Back-end server uses this action to ask Logux server to add action to the log and re-send it to all clients from action’s meta.

Back-end server must do three steps during action processing:

  1. Mark what users will also receive this action by writing resend answer to HTTP response. Object can use channels, nodes, clients or users to specify receivers. If Logux should not re-send this action, back-end server should not write anything. Do not worry, Logux will re-send actions only after passing validation on step 2.

    {
      answer: "resend",
      id: string,
      channels?: string[],
      clients?: string[],
      nodes?: string[],
      users?: string
    }
  2. Validate that the user has the right to do this action. Back-end server must write approved or forbidden answer to HTTP responses immediately when it finished this step.

    {
      answer: "approved",
      id: string
    }
    {
      answer: "forbidden",
      id: string
    }
  3. Process the action (for instance, apply changes to the database). Back-end server must write processed immediately when it finished this step.

    {
      answer: "processed",
      id: string
    }

Back-end server can take user ID from meta.id:

meta.id //=> '1560954012838 38:Y7bysd:O0ETfc 0'
meta.id.split(' ')[1].split(':')[0] //=> '38'

Action with type: "logux/subscribe" tells that user wants to load data and subscribe to data changes. On this action back-end server must:

  1. Validate that the user has access to this data and write:

    {
      answer: "approved",
      id: string
    }
    {
      answer: "forbidden",
      id: string
    }
  2. Send data in actions by writing answers:

    {
      answer: "action",
      id: string,
      action: Action,
      meta: Meta
    }
  3. Write processed to this response, when it will get response from Logux server.

    {
      answer: "processed",
      id: string
    }

Back-end server can take the client ID from meta.id:


meta.id //=> '1560954012838 38:Y7bysd:O0ETfc 0'
meta.id.split(' ')[1].split(':').slice(0, 2).join(':') //=> '38:Y7bysd'

If back-end server doesn’t have code to validate action it must write unknownChannel for logux/subscribe action and unknownAction for other actions.

{
  answer: "unknownAction",
  id: string
}
{
  answer: "unknownChannel",
  id: string
}

If back-end server had any errors during action validating and processing it should write error answer (details can be used for stack-trace).

{
  answer: "error",
  id: string,
  details: string
}

See action examples.