Great question.
TL;DR I Don’t know, but I’ve got some developed opinions.
I’ve got a (currently private) ember-addon that provides WebSocket integration using socket.io, and since we use it in a mobile app with a focus on performance and FPS the Websocket infrastructure is run in a WebWorker. This introduces it’s own questions of abstraction and idiomatic code structure.
My addon introduces two “new” concepts, Pushers
, and Workers
. I suspect that Pushers
may eventually become an extension of a proposed Services
api, but until that becomes better formulated and lands I’ve left it as it’s own thing. In addition to these two concepts, I utilize initializers and a single controller.
Pushers
A pusher extends …/utils/pusher.js, the methods it defines within it’s socketEvents
hash are turned into handlers for socket events (method name being the name of the event).
Workers
Workers extend /app/utils/worker.js and are moved from /app/workers to /dist/workers directly when compiling assets. The caveat here is that you cannot import any modules that are going to require the DOM, this pretty much rules out running Ember/Ember-Data in a worker (for the moment, the version running on Node right now might make this feasible soon, which I’m looking forward to to fully move my adapter/serializer/store logic into a worker).
Socket Controller
/controllers/socket-client.js
This is an abstraction that controls the WebSocket instance (in this case socket.io) and takes care of setting up and tearing down listeners, etc. It wraps all socket events expecting a return in promises, and if your app requires auth before certain events can work, it will wait to send those requests until a pending auth request has resolved. I inject and add listeners to this controller itself instead of to the socket.io instance. I’ve found this much more stable, especially in mobile environments where the app is being closed and opened often.
An initializer injects this singleton socket-client controller into the store, pushers, routes, controllers, and components (I debated on components initially, but I have some components that act like widgets and need to make their own requests).