diff --git a/src/configuration/ioconfig.js b/src/configuration/ioconfig.js index edb3093b..8e18447f 100644 --- a/src/configuration/ioconfig.js +++ b/src/configuration/ioconfig.js @@ -6,11 +6,47 @@ export default class IOConfiguration { getSocketEndpoints() { return this.config.endpoints.slice(); } + + getUWSEndpoints() { + return this.config.uwsEndpoints.slice(); + } +} + +function getUWSEndpoints(oldConfig) { + const uwsEndpoints = oldConfig.get('listen').filter(it => it.uws) + .map(it => { + let domain; + if (it.https) { + domain = oldConfig.get('https.domain') + .replace(/^https/, 'wss'); + } else { + domain = oldConfig.get('io.domain') + .replace(/^http/, 'ws'); + } + + return { + secure: !!it.https, + url: `${domain}:${it.port}` + }; + }); + + uwsEndpoints.sort((a, b) => { + if (a.secure && !b.secure) { + return -1; + } else if (b.secure && !a.secure) { + return 1; + } else { + return 0; + } + }); + + return uwsEndpoints; } IOConfiguration.fromOldConfig = function (oldConfig) { const config = { - endpoints: [] + endpoints: [], + uwsEndpoints: getUWSEndpoints(oldConfig) }; if (oldConfig.get('io.ipv4-ssl')) { diff --git a/src/io/cluster/nullclusterclient.js b/src/io/cluster/nullclusterclient.js index 5accc375..9c62456f 100644 --- a/src/io/cluster/nullclusterclient.js +++ b/src/io/cluster/nullclusterclient.js @@ -7,8 +7,10 @@ export default class NullClusterClient { getSocketConfig(_channel) { const servers = this.ioConfig.getSocketEndpoints(); + const uwsServers = this.ioConfig.getUWSEndpoints(); return Promise.resolve({ - servers: servers + servers: servers, + uwsServers: uwsServers }); } } diff --git a/src/io/ioserver.js b/src/io/ioserver.js index 390b621d..f392d8c9 100644 --- a/src/io/ioserver.js +++ b/src/io/ioserver.js @@ -278,18 +278,20 @@ class IOServer { uws.use(this.cookieParsingMiddleware.bind(this)); uws.use(this.ipSessionCookieMiddleware.bind(this)); uws.use(this.authUserMiddleware.bind(this)); - uws.use(this.metricsEmittingMiddleware.bind(this)); uws.on('connection', this.handleConnection.bind(this)); } - bindTo(servers) { + bindTo(sioServers, uwsServers) { if (!this.io) { throw new Error('Cannot bind: socket.io has not been initialized yet'); } - servers.forEach(server => { + sioServers.forEach(server => { this.io.attach(server); }); + uwsServers.forEach(server => { + this.uws.attach(server); + }); } } @@ -425,12 +427,19 @@ module.exports = { const uniqueListenAddresses = new Set(); const servers = []; + const uwsServers = []; Config.get("listen").forEach(function (bind) { - if (!bind.io) { + if (bind.io && bind.uws) { + throw new Error( + 'Cannot bind both socket.io and uws to the same listener' + ); + } else if (!bind.io && !bind.uws) { return; } + const serverList = bind.io ? servers : uwsServers; + const id = bind.ip + ":" + bind.port; if (uniqueListenAddresses.has(id)) { LOGGER.warn("Ignoring duplicate listen address %s", id); @@ -438,16 +447,16 @@ module.exports = { } if (srv.servers.hasOwnProperty(id)) { - servers.push(srv.servers[id]); + serverList.push(srv.servers[id]); } else { const server = http.createServer().listen(bind.port, bind.ip); - servers.push(server); + serverList.push(server); } uniqueListenAddresses.add(id); }); - ioServer.bindTo(servers); + ioServer.bindTo(servers, uwsServers); }, IOServer: IOServer, diff --git a/src/io/uws.js b/src/io/uws.js index b3d3b6c3..80a2bda3 100644 --- a/src/io/uws.js +++ b/src/io/uws.js @@ -165,18 +165,26 @@ class UWSServer extends EventEmitter { constructor() { super(); - this._server = new uws.Server({ port: 3000, host: '127.0.0.1' }); + this._servers = []; this._middleware = []; - - this._server.on('connection', socket => this._onConnection(socket)); - this._server.on('listening', () => this.emit('listening')); - this._server.on('error', e => this.emit('error', e)); } use(cb) { this._middleware.push(cb); } + attach(server) { + const uwsServer = new uws.Server({ + server, + perMessageDeflate: false + }); + this._servers.push(uwsServer); + + uwsServer.on('connection', socket => this._onConnection(socket)); + server.on('listening', () => this.emit('listening')); + uwsServer.on('error', e => this.emit('error', e)); + } + _onConnection(uwsSocket) { const socket = new UWSWrapper(uwsSocket); @@ -212,7 +220,7 @@ class UWSServer extends EventEmitter { } shutdown() { - this._server.close(); + this._servers.forEach(sv => sv.close()); } } diff --git a/test/io/uws.js b/test/io/uws.js index a6aecea1..0742e18d 100644 --- a/test/io/uws.js +++ b/test/io/uws.js @@ -3,14 +3,20 @@ const assert = require('assert'); const { UWSServer } = require('../../lib/io/uws'); const inRoom = require('../../lib/io/uws')['in']; const WebSocket = require('uws'); +const http = require('http'); describe('UWSServer', () => { const endpoint = 'ws://127.0.0.1:3000'; + let httpServer; let server; let socket; beforeEach(done => { + httpServer = http.createServer(); + httpServer.listen(3000); + server = new UWSServer(); + server.attach(httpServer); server.on('error', e => { throw e; }); server.once('listening', done); }); @@ -38,6 +44,8 @@ describe('UWSServer', () => { socket = null; if (server) server.shutdown(); server = null; + if (httpServer) httpServer.close(); + httpServer = null; }); it('accepts a connection immediately if there is no middleware', done => { diff --git a/www/js/callbacks.js b/www/js/callbacks.js index 9ab90a54..4c5a985a 100644 --- a/www/js/callbacks.js +++ b/www/js/callbacks.js @@ -1221,7 +1221,19 @@ function ioServerConnect(socketConfig) { var USING_LETS_ENCRYPT = false; +function initSocket(socketConfig) { + if (socketConfig.uwsServers && socketConfig.uwsServers.length > 0) { + initWS(socketConfig.uwsServers); + } else { + initSocketIO(socketConfig); + } + + setupCallbacks(); +} + function initSocketIO(socketConfig) { + console.log('Using socket.io'); + function genericConnectionError() { var message = "The socket.io library could not be loaded from " + source + ". Ensure that it is not being blocked " + @@ -1295,16 +1307,16 @@ function checkLetsEncrypt(socketConfig, nonLetsEncryptError) { }); } -function initWS() { - window.socket = new WSShim('ws://localhost:3000/'); - setupCallbacks(); +function initWS(servers) { + console.log('Using WSShim'); + console.log("Connecting to " + JSON.stringify(servers[0])); + window.socket = new WSShim(servers[0].url); } (function () { $.getJSON("/socketconfig/" + CHANNEL.name + ".json") .done(function (socketConfig) { - //initSocketIO(socketConfig); - initWS(); + initSocket(socketConfig); }).fail(function () { makeAlert("Error", "Failed to retrieve socket.io configuration. " + "Please try again in a few minutes.", diff --git a/www/js/ws.js b/www/js/ws.js index 2adf1efc..d243f816 100644 --- a/www/js/ws.js +++ b/www/js/ws.js @@ -113,7 +113,6 @@ WSShim.prototype._onmessage = function _onmessage(message) { try { var parsed = JSON.parse(message.data); - console.log(parsed); var type = parsed.type; var frame = parsed.frame; var payload = parsed.payload;