diff --git a/lib/units/device/plugins/screen/stream.js b/lib/units/device/plugins/screen/stream.js index 5b4eb26b..8810533d 100644 --- a/lib/units/device/plugins/screen/stream.js +++ b/lib/units/device/plugins/screen/stream.js @@ -2,7 +2,7 @@ var util = require('util') var Promise = require('bluebird') var syrup = require('stf-syrup') -var WebSocketServer = require('ws').Server +var WebSocket = require('ws') var uuid = require('node-uuid') var EventEmitter = require('eventemitter3').EventEmitter var split = require('split') @@ -400,7 +400,7 @@ module.exports = syrup.serial() function createServer() { log.info('Starting WebSocket server on port %d', screenOptions.publicPort) - var wss = new WebSocketServer({ + var wss = new WebSocket.Server({ port: screenOptions.publicPort , perMessageDeflate: false }) @@ -448,19 +448,59 @@ module.exports = syrup.serial() , JSON.stringify(frameProducer.banner) ) - broadcastSet.values().forEach(function(ws) { - ws.send(message) + broadcastSet.keys().forEach(function(id) { + var ws = broadcastSet.get(id) + switch (ws.readyState) { + case WebSocket.OPENING: + // This should never happen. + log.warn('Unable to send banner to OPENING client "%s"', id) + break + case WebSocket.OPEN: + // This is what SHOULD happen. + ws.send(message) + break + case WebSocket.CLOSING: + // Ok, a 'close' event should remove the client from the set + // soon. + break + case WebSocket.CLOSED: + // This should never happen. + log.warn('Unable to send banner to CLOSED client "%s"', id) + broadcastSet.remove(id) + break + } }) }) frameProducer.on('readable', function next() { var frame if ((frame = frameProducer.nextFrame())) { - Promise.settle([broadcastSet.values().map(function(ws) { - return new Promise(function(resolve/*, reject*/) { - ws.send(frame, { - binary: true - }, resolve) + Promise.settle([broadcastSet.keys().map(function(id) { + return new Promise(function(resolve, reject) { + var ws = broadcastSet.get(id) + switch (ws.readyState) { + case WebSocket.OPENING: + // This should never happen. + return reject(new Error(util.format( + 'Unable to send frame to OPENING client "%s"', id))) + case WebSocket.OPEN: + // This is what SHOULD happen. + ws.send(frame, { + binary: true + }, function(err) { + return err ? reject(err) : resolve() + }) + return + case WebSocket.CLOSING: + // Ok, a 'close' event should remove the client from the set + // soon. + return + case WebSocket.CLOSED: + // This should never happen. + broadcastSet.remove(id) + return reject(new Error(util.format( + 'Unable to send frame to CLOSED client "%s"', id))) + } }) })]).then(next) } diff --git a/lib/units/device/plugins/screen/util/broadcastset.js b/lib/units/device/plugins/screen/util/broadcastset.js index 1b1cf78e..9b1a0720 100644 --- a/lib/units/device/plugins/screen/util/broadcastset.js +++ b/lib/units/device/plugins/screen/util/broadcastset.js @@ -37,4 +37,12 @@ BroadcastSet.prototype.values = function() { }, this) } +BroadcastSet.prototype.keys = function() { + return Object.keys(this.set) +} + +BroadcastSet.prototype.get = function(id) { + return this.set[id] +} + module.exports = BroadcastSet