What is a good overall design using the TypeScript language features for an RPC-style communication channel between Windows and workers?
SharedWorkers are lists of JavaScript code that are launched by the browser outside the context of a specific browser window. A single SharedWorker (via a script URI) is used by all open browser windows whose native code requests it. Windows and workers communicate through intricate worker.port objects to which the sender can postMessage () and from which the receiver can listen for "message" events. The most consistently supported type allowed for publication is a single string , which can be easily JSON.stringify(ofSomeObject) , but can be of any user-defined format.
TypeScript is a JavaScript extension that provides some useful security features and other useful application code management features.
Remote procedure call libraries , such as WCF, use SOA front-end interfaces shared by both (all) sides of the communication channel and abstract away the monotonous and error-prone need for serializing and deserializing queries.
Communication between the Windows browser and their Worker is similar to RPC, because we cannot transmit code in the form of data through the channel. One of the main differences is that the connection is one-way. The sender can post a message, but cannot block and wait for the result. Instead, the application layer is responsible for matching the received data with the sent requests (if necessary).
To take advantage of TypeScript input functions, it seems to me that after a contract paradigm, this is a good choice. We need:
- one interface for each receiver service contract.
- execution of the receiver of each contract
- proxy implementation of each contract
First, we need to teach TypeScript about SharedWorkers, based on the definitions of lib.d.ts. SharedWorker.d.ts:
interface ConnectEvent extends Event { ports: MessagePort[]; }; interface SharedWorker extends EventTarget, AbstractWorker { port: MessagePort; }; declare var SharedWorker: { prototype: SharedWorker; new (scriptURL: any, name: any): SharedWorker; new (scriptURL: any): SharedWorker; }
In WCF, we have OperationContext ambient to learn about the connected client. We also return a value in most cases to send a response to a request.
In JavaScript, we don't have a ThreadStatic, and I doubt that we can reliably provide the equivalent of ambientConttext. (Each list of codes runs in a single-threaded way, but the asynchronous method is implemented using timer callbacks and is probably used by the Worker implementation, I donโt think we could track this correctly.)
With MessagePorts, we cannot return a value. Instead, we must send another one-way response back to the requestor, and therefore we need a handle to the returned MessagePort. However, this MessagePort message cannot be part of Contact because it will not be required to implement a proxy server. All I can think of is to create a new instance of the implementation class, initialized using the differences between the receiver and the proxy server, such as the returned MessagePort and any other data, such as an array of all connected MessagePort for broadcast messages. Then the implementation member methods can refer to those that can be in the OperationContext.
And an example message event handler:
worker.port.addEventListener('message', (e: MessageEvent) => { var data = JSON.parse(e.data); new ReceiverImplementation(worker.port)[data.name].apply(this, data.params); }, false);
A proxy server implementation may have a function such as:
SessionLogin(username: string) { this.worker.port.postMessage(Command('SessionLogin', arguments)); }
The message event handler applies the received parameters to the specified method name. The ReceiverImplementation object should be independent, as shown, possibly from any other class, since we want to avoid collisions of method names. Maybe not, but we're talking about running client code on a client machine. There are no identical security issues (or the ability to provide security for security guards).
The wiring of the entire prototype is too long / complicated, and because of the subject, it will not fit into jsfiddle. And in any case, what I have is not so great. It still looks like a bunch of template code for very little functionality.
And Iโm sure that all this applies to non-collaborative web workers, but with all this communication problem I donโt see a value proposition for a non-common variety!
This is a stretching question, but I hope I did OK to explain it. What are your ideas for solving this Window-Worker relationship? How can you use the laid-back nature of JavaScript and just the illusion of TypeScript security for a simpler and less error prone communication? I suspect I'm using WCF with .NET restrictions and ported them too close to JavaScript.
Thanks.