From d7aaef63ceb9413c7711a0d57feb6da9de001380 Mon Sep 17 00:00:00 2001 From: Loonride Date: Tue, 28 May 2019 11:16:13 -0500 Subject: [PATCH] refactor(server): encapsulate socket server implementation (#1904) --- lib/Server.js | 45 +++--------------------- lib/servers/BaseServer.js | 9 +++++ lib/servers/SockJSServer.js | 64 ++++++++++++++++++++++++++++++++++ lib/servers/WebsocketServer.js | 8 +++++ lib/servers/baseServer.js | 9 +++++ lib/servers/sockjsServer.js | 64 ++++++++++++++++++++++++++++++++++ package-lock.json | 29 +++++---------- 7 files changed, 167 insertions(+), 61 deletions(-) create mode 100644 lib/servers/BaseServer.js create mode 100644 lib/servers/SockJSServer.js create mode 100644 lib/servers/WebsocketServer.js create mode 100644 lib/servers/baseServer.js create mode 100644 lib/servers/sockjsServer.js diff --git a/lib/Server.js b/lib/Server.js index 8041b5ef99..70ab40b747 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -12,7 +12,6 @@ const url = require('url'); const http = require('http'); const https = require('https'); const ip = require('ip'); -const sockjs = require('sockjs'); const semver = require('semver'); const killable = require('killable'); const chokidar = require('chokidar'); @@ -32,26 +31,7 @@ const createDomain = require('./utils/createDomain'); const runBonjour = require('./utils/runBonjour'); const routes = require('./utils/routes'); const schema = require('./options.json'); - -// Workaround for sockjs@~0.3.19 -// sockjs will remove Origin header, however Origin header is required for checking host. -// See https://github.com/webpack/webpack-dev-server/issues/1604 for more information -{ - // eslint-disable-next-line global-require - const SockjsSession = require('sockjs/lib/transport').Session; - const decorateConnection = SockjsSession.prototype.decorateConnection; - SockjsSession.prototype.decorateConnection = function(req) { - decorateConnection.call(this, req); - const connection = this.connection; - if ( - connection.headers && - !('origin' in connection.headers) && - 'origin' in req.headers - ) { - connection.headers.origin = req.headers.origin; - } - }; -} +const SockJSServer = require('./servers/SockJSServer'); // Workaround for node ^8.6.0, ^9.0.0 // DEFAULT_ECDH_CURVE is default to prime256v1 in these version @@ -671,20 +651,9 @@ class Server { } createSocketServer() { - const socket = sockjs.createServer({ - // Use provided up-to-date sockjs-client - sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js', - // Limit useless logs - log: (severity, line) => { - if (severity === 'error') { - this.log.error(line); - } else { - this.log.debug(line); - } - }, - }); + this.socketServer = new SockJSServer(this); - socket.on('connection', (connection) => { + this.socketServer.onConnection((connection) => { if (!connection) { return; } @@ -736,10 +705,6 @@ class Server { this._sendStats([connection], this.getStats(this._stats), true); }); - - socket.installHandlers(this.listeningApp, { - prefix: this.sockPath, - }); } listen(port, hostname, fn) { @@ -762,7 +727,7 @@ class Server { close(cb) { this.sockets.forEach((socket) => { - socket.close(); + this.socketServer.close(socket); }); this.sockets = []; @@ -923,7 +888,7 @@ class Server { // eslint-disable-next-line sockWrite(sockets, type, data) { sockets.forEach((socket) => { - socket.write(JSON.stringify({ type, data })); + this.socketServer.send(socket, JSON.stringify({ type, data })); }); } diff --git a/lib/servers/BaseServer.js b/lib/servers/BaseServer.js new file mode 100644 index 0000000000..e22bd2a058 --- /dev/null +++ b/lib/servers/BaseServer.js @@ -0,0 +1,9 @@ +'use strict'; + +// base class that users should extend if they are making their own +// server implementation +module.exports = class BaseServer { + constructor(server) { + this.server = server; + } +}; diff --git a/lib/servers/SockJSServer.js b/lib/servers/SockJSServer.js new file mode 100644 index 0000000000..8c67abd4e5 --- /dev/null +++ b/lib/servers/SockJSServer.js @@ -0,0 +1,64 @@ +'use strict'; + +/* eslint-disable + class-methods-use-this, + func-names +*/ +const sockjs = require('sockjs'); +const BaseServer = require('./BaseServer'); + +// Workaround for sockjs@~0.3.19 +// sockjs will remove Origin header, however Origin header is required for checking host. +// See https://github.com/webpack/webpack-dev-server/issues/1604 for more information +{ + // eslint-disable-next-line global-require + const SockjsSession = require('sockjs/lib/transport').Session; + const decorateConnection = SockjsSession.prototype.decorateConnection; + SockjsSession.prototype.decorateConnection = function(req) { + decorateConnection.call(this, req); + const connection = this.connection; + if ( + connection.headers && + !('origin' in connection.headers) && + 'origin' in req.headers + ) { + connection.headers.origin = req.headers.origin; + } + }; +} + +module.exports = class SockJSServer extends BaseServer { + // options has: error (function), debug (function), server (http/s server), path (string) + constructor(server) { + super(server); + this.socket = sockjs.createServer({ + // Use provided up-to-date sockjs-client + sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js', + // Limit useless logs + log: (severity, line) => { + if (severity === 'error') { + this.server.log.error(line); + } else { + this.server.log.debug(line); + } + }, + }); + + this.socket.installHandlers(this.server.listeningApp, { + prefix: this.server.sockPath, + }); + } + + send(connection, message) { + connection.write(message); + } + + close(connection) { + connection.close(); + } + + // f should return the resulting connection + onConnection(f) { + this.socket.on('connection', f); + } +}; diff --git a/lib/servers/WebsocketServer.js b/lib/servers/WebsocketServer.js new file mode 100644 index 0000000000..e95f088f56 --- /dev/null +++ b/lib/servers/WebsocketServer.js @@ -0,0 +1,8 @@ +'use strict'; + +// const ws = require('ws'); +const BaseServer = require('./BaseServer'); + +// ws server implementation under construction +// will need changes in the client as well to function +module.exports = class WebsocketServer extends BaseServer {}; diff --git a/lib/servers/baseServer.js b/lib/servers/baseServer.js new file mode 100644 index 0000000000..e22bd2a058 --- /dev/null +++ b/lib/servers/baseServer.js @@ -0,0 +1,9 @@ +'use strict'; + +// base class that users should extend if they are making their own +// server implementation +module.exports = class BaseServer { + constructor(server) { + this.server = server; + } +}; diff --git a/lib/servers/sockjsServer.js b/lib/servers/sockjsServer.js new file mode 100644 index 0000000000..8c67abd4e5 --- /dev/null +++ b/lib/servers/sockjsServer.js @@ -0,0 +1,64 @@ +'use strict'; + +/* eslint-disable + class-methods-use-this, + func-names +*/ +const sockjs = require('sockjs'); +const BaseServer = require('./BaseServer'); + +// Workaround for sockjs@~0.3.19 +// sockjs will remove Origin header, however Origin header is required for checking host. +// See https://github.com/webpack/webpack-dev-server/issues/1604 for more information +{ + // eslint-disable-next-line global-require + const SockjsSession = require('sockjs/lib/transport').Session; + const decorateConnection = SockjsSession.prototype.decorateConnection; + SockjsSession.prototype.decorateConnection = function(req) { + decorateConnection.call(this, req); + const connection = this.connection; + if ( + connection.headers && + !('origin' in connection.headers) && + 'origin' in req.headers + ) { + connection.headers.origin = req.headers.origin; + } + }; +} + +module.exports = class SockJSServer extends BaseServer { + // options has: error (function), debug (function), server (http/s server), path (string) + constructor(server) { + super(server); + this.socket = sockjs.createServer({ + // Use provided up-to-date sockjs-client + sockjs_url: '/__webpack_dev_server__/sockjs.bundle.js', + // Limit useless logs + log: (severity, line) => { + if (severity === 'error') { + this.server.log.error(line); + } else { + this.server.log.debug(line); + } + }, + }); + + this.socket.installHandlers(this.server.listeningApp, { + prefix: this.server.sockPath, + }); + } + + send(connection, message) { + connection.write(message); + } + + close(connection) { + connection.close(); + } + + // f should return the resulting connection + onConnection(f) { + this.socket.on('connection', f); + } +}; diff --git a/package-lock.json b/package-lock.json index 22fb013266..87a1c9bcd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5400,8 +5400,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -5438,8 +5437,7 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", @@ -5448,8 +5446,7 @@ }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -5552,8 +5549,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -5563,7 +5559,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5589,7 +5584,6 @@ "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5606,7 +5600,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5690,7 +5683,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5766,8 +5758,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -5797,7 +5788,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5815,7 +5805,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5854,13 +5843,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -9090,7 +9077,7 @@ }, "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "resolved": false, "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true },