Why?
One of the scenarii we want to support with Link is to interact not only with your physical home devices, but also with online services. A simple example is to use a voice command to book a taxi.
The Adapter approach
In Link’s current world, that would require either an adapter for each taxi service or a generic taxi adapter that can itself be configured to support different providers (eg. Lyft, Uber, you name it). However both of these options have quite severe limitations:
- one adapter per taxi service is hard to scale, especially since adapters are trusted code: we have no plans for an “adapter store”. That would also be quite inflexible when the service itself evolves.
- a taxi meta-adapter would have to implement its own way of describing various services and interacting with them, and to let users manage their preferences/accounts/etc. That would be a lot to implement for a single domain (the taxis) and would have to be redone for other use cases (eg. restaurant bookings). We would obviously try to share the underlying mechanism, but that looks once again like an attempt to describe the world, which is… a hard problem.
Workers
Let’s consider that the Link user has an account with the brand new GreatTaxis service. Instead of expecting Link to have ad-hoc support for GreatTaxis, Link will offer a way for GreatTaxis to deploy on their website an application that interacts with the Foxbox. This is already possible since all Link apps are “remote” apps that access Link apis on behalf of the authenticated user.
What is missing though, is that this application needs to be able to run (eg. waiting for the user to say “call me a great taxi”) even when the web app is not currently opened in a user’s browser. That means that the GreatTaxis app needs to run in some kind of distributed fashion, with some part of its code having permanent access to the Foxbox apis.
Web pages happen to have a way to spawn off the main thread processing : web workers. Since all the communication with the worker happens through message passing, there is no reason we can not “detach” the worker from the web browser and run it in the Foxbox instead. By not shutting down the worker when the user navigates away from the app, and reviving the message channel on demand if the user goes back to the app we can achieve what we need.
The benefits of this approach are multiple:
- no adapter bloat in the codebase.
- full control of the experience by 3rd parties.
- leverages a well known and understood security model: the web.
The capabilities available to Foxbox workers should be similar to what a “real” web worker gets in terms of web APIs. In the Foxbox, they will run on behalf of the user that created them (with their own data jar), and so will get access to all the apis this user has access to. For instance, push notifications can be sent to notify users, or voice recognition triggers can be set up.
Implementation
This plan relies on being able to run Javascript workers, with a sizeable chunk of the web stack. The big picture here is to re-use a trimmed down version of an existing web runtime tailored for our needs. Obvious candidates are Gecko and Servo. There are pros and cons to both, that I will not detail in this post. Overall the main challenge here is to use just enough resources while providing the needed set of web apis.
One interesting issue is how we setup the message passing channel between the web browser and the Foxbox worker. The first prototype will use a websocket connection, but we will likely move to a webrtc datachannel in a more finalized version. The main advantage of using a webrtc datachannel is that the traffic won’t have to go through the Link bridge when you’re outside your home network.
We will have to keep the workers “always green” by checking for potential updates and replacing old instances by newer ones when needed.
On the client side, we will expose a RemoteWorker
object with capabilities as close as possible as a normal web worker. One limitation is that we can’t support transferable arguments in postMessage()
.
Future work
Once we are done with this first feature set, there are even more interesting things we can achieve with remote workers. One idea I want to investigate further is to use them to provide content from a publicly accessible url. Much like Service Workers can intercept network requests and provide content, our workers could register themselves to provide content for a given uri space.
For instance, let’s imagine that I build a “lifestream” webapp, that let me post pictures and text. It will use a remote worker to actually store the content on my Foxbox, and register itself to serve public content at /fabrice/public/lifestream/feed.json so that anyone interested in my public posts could access them.
Another example would be a chat application, where each participant would connect to its buddies through their public worker endpoint. That would be some kind of distributed, always up-to-date messaging application.
These are basic ideas and there are lots of details to figure out, but I’m convinced that it’s a powerful way of leveraging the web technologies!
Feedback welcome!