13.3. SharedWorkerChannel and ChannelID

The Channel classes handle the actual communication through the Channel Messaging API. The Channel instance stores the MessagePort instance that can be used to send messages to other processes (in our case, from the client page to the PDR). In the case of the SharedWorkerChannel, it receives that port by creating a SharedWorker with the script perspectives-sharedworker.js. Notice that only de FIRST page actually creates the SharedWorker (as a separate process) but that the others merely connect to it! Nevertheless, each page has its own instance of SharedWorkerChannel and its own MessagePort. Once the SharedWorkerChannel has been created, we resolve the SharedWorkerChannelPromise with it (using the sharedWorkerChannelResolver).

Notice that the SharedWorkerChannel has the MessagePort that is the client side endpoint of the connection between PDR and client page. So the SharedWorkerChannel uses its port to connect to the PDR that runs in a SharedWorker:

  • its send function calls its postMessage function, relaying calls to the PDR;

  • it puts an event handler on the onmessage property of the MessagePort it has received, listening for responses from the SharedWorker/PDR.

13.3.1. ChannelID

Each time a new Perspectives page creates its SharedWorkerChannel, it receives a ChannelID from the SharedWorker. The SharedWorkerChannel instance stores this and sends it along with each request to the PDR or SharedWorker. The SharedWorker uses this ID to send responses from the PDR to the right client page. The PDR itself has no notion of different clients; it is the SharedWorker that keeps them apart. This is entirely in line with the way the PDR works. It handles client calls that modificate Perspectives State in exactly the same way that it handles similar modifications from peers through the Transactions they send. It is quite democratically in that respect!

13.3.2. Calling and receiving responses: Correlation identifiers

It is important to realise that the SharedWorker communicates out of process with the PDR. So it performs a kind of remote procedure call through the Messaging API. All functions in the PerspectivesProxy API expect a response, but because of the out of process character we must treat them as asynchronous functions (they either take a callback or return a promise and this translates to a callback under the hood). The SharedWorker class takes care of all callback functions, storing them internally with a key called a Correlation Identifier. The Correlation Identifier is sent along to the SharedWorker/PDR and when it returns a result, the Correlation Identifier will be part of it. The SharedWorker class then selects the associated callback function and applies it to the result.

All this is transparent from the perspective of the PerspectivesProxy class. It just delegates calls to its Channel, sending the client-supplied callbacks along and never thinks about then again.

13.3.3. Handling PDR responses

The PDR exposes two APIs:

  • one defined in the module Perspectives.Api. These are functions to query Perspectives State or to modify it.

  • one loosely defined in the Main module of the PDR. These are functions to start the PDR, to register a new account, etc. All these 'housekeeping' functions return promises to the client. They are one-time-only functions.

13.3.4. Streams versus one-time-only responses

A modification to Perspectives State should be made just once and will return a success or failure message (its format depending on the nature of the call). In contrast, a query returns a result that depends very much on the current state of affairs. Whenever that changes, the client wants to be informed. Hence, we can regard the result of a query call through the proxy as a stream of responses at successive moments in time, as measured by relevant state change.

This translates, in the Channel classes, to callbacks that are registered to be used just once or to be called again and again. The Channel send function has a parameter fireAndForget that decides this. The value to this parameter is supplied by the various functions in the PerspectivesProxy API.

There may be circumstances that the client is not interested in any updates on a query result. It may call the query function with a value FIREANDFORGET to have the Channel classes treat it like a one-time-only call.

Those API functions that are one-time-only by their nature return a promise and do not take a callback. All others take a callback.

Note
In the future we may replace the callback interface with a Stream-like abstraction.