function expressWs(app, httpServer) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var server = httpServer;
if (server === null || server === undefined) {
/* No HTTP server was explicitly provided, create one for our Express application. */
server = _http2.default.createServer(app);
app.listen = function serverListen() {
var _server;
return (_server = server).listen.apply(_server, arguments);
};
}
/* Make our custom `.ws` method available directly on the Express application. You should
* really be using Routers, though. */
(0, _addWsMethod2.default)(app);
/* Monkeypatch our custom `.ws` method into Express' Router prototype. This makes it possible,
* when using the standard Express Router, to use the `.ws` method without any further calls
* to `makeRouter`. When using a custom router, the use of `makeRouter` may still be necessary.
*
* This approach works, because Express does a strange mixin hack - the Router factory
* function is simultaneously the prototype that gets assigned to the resulting Router
* object. */
if (!options.leaveRouterUntouched) {
(0, _addWsMethod2.default)(_express2.default.Router);
}
// allow caller to pass in options to WebSocketServer constructor
var wsOptions = options.wsOptions || {};
wsOptions.server = server;
var wsServer = new _ws2.default.Server(wsOptions);
wsServer.on('connection', function (socket) {
var request = socket.upgradeReq;
request.ws = socket;
request.wsHandled = false;
/* By setting this fake `.url` on the request, we ensure that it will end up in the fake
* `.get` handler that we defined above - where the wrapper will then unpack the `.ws`
* property, indicate that the WebSocket has been handled, and call the actual handler. */
request.url = (0, _websocketUrl2.default)(request.url);
var dummyResponse = new _http2.default.ServerResponse(request);
dummyResponse.writeHead = function writeHead(statusCode) {
if (statusCode > 200) {
/* Something in the middleware chain signalled an error. */
socket.close();
}
};
app.handle(request, dummyResponse, function () {
if (!request.wsHandled) {
/* There was no matching WebSocket-specific route for this request. We'll close
* the connection, as no endpoint was able to handle the request anyway... */
socket.close();
}
});
});
return {
app: app,
getWss: function getWss() {
return wsServer;
},
applyTo: function applyTo(router) {
(0, _addWsMethod2.default)(router);
}
};
}
n/a
function addWsMethod(target) {
/* This prevents conflict with other things setting `.ws`. */
if (target.ws === null || target.ws === undefined) {
target.ws = function addWsRoute(route) {
for (var _len = arguments.length, middlewares = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
middlewares[_key - 1] = arguments[_key];
}
var wrappedMiddlewares = middlewares.map(_wrapMiddleware2.default);
/* We append `/.websocket` to the route path here. Why? To prevent conflicts when
* a non-WebSocket request is made to the same GET route - after all, we are only
* interested in handling WebSocket requests.
*
* Whereas the original `express-ws` prefixed this path segment, we suffix it -
* this makes it possible to let requests propagate through Routers like normal,
* which allows us to specify WebSocket routes on Routers as well \o/! */
var wsRoute = (0, _websocketUrl2.default)(route);
/* Here we configure our new GET route. It will never get called by a client
* directly, it's just to let our request propagate internally, so that we can
* leave the regular middleware execution and error handling to Express. */
this.get.apply(this, _toConsumableArray([wsRoute].concat(wrappedMiddlewares)));
/*
* Return `this` to allow for chaining:
*/
return this;
};
}
}
n/a
function addTrailingSlash(string) { var suffixed = string; if (suffixed.charAt(suffixed.length - 1) !== '/') { suffixed = suffixed + '/'; } return suffixed; }
n/a
function websocketUrl(url) { if (url.indexOf('?') !== -1) { var _url$split = url.split('?'), _url$split2 = _slicedToArray(_url$split, 2), baseUrl = _url$split2[0], query = _url$split2[1]; return (0, _trailingSlash2.default)(baseUrl) + '.websocket?' + query; } return (0, _trailingSlash2.default)(url) + '.websocket'; }
n/a
function wrapMiddleware(middleware) {
return function (req, res, next) {
if (req.ws !== null && req.ws !== undefined) {
req.wsHandled = true;
try {
/* Unpack the `.ws` property and call the actual handler. */
middleware(req.ws, req, next);
} catch (err) {
/* If an error is thrown, let's send that on to any error handling */
next(err);
}
} else {
/* This wasn't a WebSocket request, so skip this middleware. */
next();
}
};
}
n/a