Protocol - element-ts/lithium GitHub Wiki

When a client starts a new connection to a server via the LiSocket.init() static async method, it generates a new socket using the ws package. It then waits to get its id from the server using an internal command.

Once an id is generated by the server, and the server has processed the new connection, the init() method on LiSocket sets its id and resolves the promise. This is why the method is async.

When a command is invoked by a socket, it creates an LiMessage object which looks like below:

{
    timestamp: Date.now(),
    command: "the-command-name",
    param: 42,
    id: "an-id-created",
    peerToPeer: false
}

It sets the timestamp to the current time. The command and param are self-explanatory. For id, the LiMessageManager instance attached to the LiBaseSocket generates a new non-colliding identifier and adds the new message's handler to an internal map.

The message object is stringified by @elijahjcobb/better-json. All this package does is stringify it but correctly handles the conversion for Buffer objects. The string is then converted into a Buffer and sent through the socket. On the other side, the corresponding LiBaseSocket parses the binary data and gets it back to an LiMesage.

The socket then checks the types of the message and finds the handler provided by the implement method in the socket's LiCommandRegistry instance. It runs the handler. If the handler throws an error the socket will catch it. Then it packages up the response of the handler whether it be a correct response or error and creates a new LiMessage where the timestamp, is the original message's timestamp, the command, is either "return" or "error". The param is the return value or error, the id is the original message's id, and peerToPeer is set to false unless it is a peer-to-peer command.