1 | (function (factory) {
|
2 | if (typeof module === "object" && typeof module.exports === "object") {
|
3 | var v = factory(require, exports);
|
4 | if (v !== undefined) module.exports = v;
|
5 | }
|
6 | else if (typeof define === "function" && define.amd) {
|
7 | define(["require", "exports", "body-parser", "express", "ws", "./common/util", "./node/util", "./middleware/instrument", "./middleware/unhandled", "./middleware/finalError", "./middleware/resolveSuites", "./middleware/post", "./middleware/filterUrl"], factory);
|
8 | }
|
9 | })(function (require, exports) {
|
10 | "use strict";
|
11 | Object.defineProperty(exports, "__esModule", { value: true });
|
12 | var body_parser_1 = require("body-parser");
|
13 | var express = require("express");
|
14 | var WebSocket = require("ws");
|
15 | var util_1 = require("./common/util");
|
16 | var util_2 = require("./node/util");
|
17 | var instrument_1 = require("./middleware/instrument");
|
18 | var unhandled_1 = require("./middleware/unhandled");
|
19 | var finalError_1 = require("./middleware/finalError");
|
20 | var resolveSuites_1 = require("./middleware/resolveSuites");
|
21 | var post_1 = require("./middleware/post");
|
22 | var filterUrl_1 = require("./middleware/filterUrl");
|
23 | var Server = (function () {
|
24 | function Server(options) {
|
25 | Object.assign(this, {
|
26 | basePath: '.',
|
27 | runInSync: false
|
28 | }, options);
|
29 | }
|
30 | Object.defineProperty(Server.prototype, "stopped", {
|
31 | get: function () {
|
32 | return !this._httpServer;
|
33 | },
|
34 | enumerable: true,
|
35 | configurable: true
|
36 | });
|
37 | Server.prototype.start = function () {
|
38 | var _this = this;
|
39 | var startupError;
|
40 | var wsServer;
|
41 | var httpServer;
|
42 | return new Promise(function (resolve, reject) {
|
43 | var app = (_this._app = express());
|
44 | _this._sessions = {};
|
45 | _this.executor.log('Listening for WebSocket connections on port', _this.socketPort);
|
46 | wsServer = new WebSocket.Server({ port: _this.socketPort });
|
47 | wsServer.on('connection', function (client) {
|
48 | _this.executor.log('WebSocket connection opened:', client);
|
49 | _this._handleWebSocket(client);
|
50 | });
|
51 | wsServer.on('error', function (error) {
|
52 | if (util_2.isErrnoException(error) && error.code === 'EADDRINUSE') {
|
53 | var err = new Error("Something is already listening on the websocket server port (" + _this.socketPort + ")");
|
54 | err.code = error.code;
|
55 | err.errno = error.errno;
|
56 | reject(err);
|
57 | }
|
58 | else if (!_this._wsServer) {
|
59 | reject(error);
|
60 | }
|
61 | else {
|
62 | _this.executor.emit('error', error);
|
63 | }
|
64 | });
|
65 | var context = Object.create(null, {
|
66 | stopped: {
|
67 | enumerable: true,
|
68 | get: function () { return _this.stopped; }
|
69 | },
|
70 | basePath: {
|
71 | enumerable: true,
|
72 | get: function () { return _this.basePath; }
|
73 | },
|
74 | executor: {
|
75 | enumerable: true,
|
76 | get: function () { return _this.executor; }
|
77 | },
|
78 | handleMessage: {
|
79 | enumerable: false,
|
80 | writable: false,
|
81 | configurable: false,
|
82 | value: function (message) { return _this._handleMessage(message); }
|
83 | }
|
84 | });
|
85 | Object.defineProperty(app.request, 'intern', {
|
86 | enumerable: true,
|
87 | get: function () { return context; }
|
88 | });
|
89 | Object.defineProperty(app.response, 'intern', {
|
90 | enumerable: true,
|
91 | get: function () { return context; }
|
92 | });
|
93 | app.use(filterUrl_1.default());
|
94 | app.use(body_parser_1.json({ limit: '1mb' }), body_parser_1.urlencoded({ extended: true }));
|
95 | app.use(function (request, _response, next) {
|
96 | _this.executor.log(request.method + " request for " + request.url);
|
97 | return next();
|
98 | });
|
99 | var internPath = _this.executor.config.internPath;
|
100 | app.use(["/" + internPath + "__resolveSuites__", '/__intern/__resolveSuites__'], resolveSuites_1.default(context));
|
101 | app.use('/__intern', express.static(internPath, { fallthrough: false }));
|
102 | app.use(instrument_1.default(context), express.static(_this.basePath), post_1.default(context), unhandled_1.default(), finalError_1.default());
|
103 | httpServer = app.listen(_this.port, resolve);
|
104 | httpServer.on('error', function (error) {
|
105 | if (util_2.isErrnoException(error) && error.code === 'EADDRINUSE') {
|
106 | var err = new Error("Something is already listening on the server port (" + _this.port + ")");
|
107 | err.code = error.code;
|
108 | err.errno = error.errno;
|
109 | reject(err);
|
110 | }
|
111 | else if (!_this._httpServer) {
|
112 | reject(error);
|
113 | }
|
114 | else {
|
115 | _this.executor.emit('error', error);
|
116 | }
|
117 | });
|
118 | var sockets = [];
|
119 | httpServer.on('close', function () {
|
120 | var socket;
|
121 | while ((socket = sockets.pop())) {
|
122 | socket.destroy();
|
123 | }
|
124 | });
|
125 | httpServer.on('connection', function (socket) {
|
126 | sockets.push(socket);
|
127 | _this.executor.log('HTTP connection opened,', sockets.length, 'open connections');
|
128 | socket.on('close', function () {
|
129 | var index = sockets.indexOf(socket);
|
130 | index !== -1 && sockets.splice(index, 1);
|
131 | _this.executor.log('HTTP connection closed,', sockets.length, 'open connections');
|
132 | });
|
133 | });
|
134 | })
|
135 | .then(function () {
|
136 | _this._wsServer = wsServer;
|
137 | _this._httpServer = httpServer;
|
138 | })
|
139 | .catch(function (error) {
|
140 | startupError = error;
|
141 | try {
|
142 | wsServer.close();
|
143 | }
|
144 | catch (_error) { }
|
145 | try {
|
146 | httpServer.close();
|
147 | }
|
148 | catch (_error) { }
|
149 | })
|
150 | .then(function () {
|
151 | if (startupError) {
|
152 | throw startupError;
|
153 | }
|
154 | });
|
155 | };
|
156 | Server.prototype.stop = function () {
|
157 | var _this = this;
|
158 | this.executor.log('Stopping server...');
|
159 | var promises = [];
|
160 | if (this._app && this._httpServer) {
|
161 | promises.push(new Promise(function (resolve) {
|
162 | _this._httpServer.close(resolve);
|
163 | }).then(function () {
|
164 | _this.executor.log('Stopped http server');
|
165 | _this._app = _this._httpServer = undefined;
|
166 | }));
|
167 | }
|
168 | if (this._wsServer) {
|
169 | promises.push(new Promise(function (resolve) {
|
170 | _this._wsServer.close(resolve);
|
171 | }).then(function () {
|
172 | _this.executor.log('Stopped ws server');
|
173 | _this._wsServer = undefined;
|
174 | }));
|
175 | }
|
176 | return Promise.all(promises);
|
177 | };
|
178 | Server.prototype.subscribe = function (sessionId, listener) {
|
179 | var listeners = this._getSession(sessionId).listeners;
|
180 | listeners.push(listener);
|
181 | return {
|
182 | destroy: function () {
|
183 | this.destroy = function () { };
|
184 | util_1.pullFromArray(listeners, listener);
|
185 | }
|
186 | };
|
187 | };
|
188 | Server.prototype._getSession = function (sessionId) {
|
189 | var session = this._sessions[sessionId];
|
190 | if (!session) {
|
191 | session = this._sessions[sessionId] = { listeners: [] };
|
192 | }
|
193 | return session;
|
194 | };
|
195 | Server.prototype._handleMessage = function (message) {
|
196 | var _this = this;
|
197 | this.executor.log('Processing message [', message.id, '] for ', message.sessionId, ': ', message.name);
|
198 | var promise = this._publish(message);
|
199 | if (getShouldWait(this.runInSync, message)) {
|
200 | return promise;
|
201 | }
|
202 | promise.catch(function (error) {
|
203 | _this.executor.emit('error', error);
|
204 | });
|
205 | return resolvedPromise;
|
206 | };
|
207 | Server.prototype._handleWebSocket = function (client) {
|
208 | var _this = this;
|
209 | client.on('message', function (data) {
|
210 | _this.executor.log('Received WebSocket message');
|
211 | var message = JSON.parse(data.toString());
|
212 | _this._handleMessage(message)
|
213 | .catch(function (error) { return _this.executor.emit('error', error); })
|
214 | .then(function () {
|
215 | _this.executor.log('Sending ack for [', message.id, ']');
|
216 | client.send(JSON.stringify({ id: message.id }), function (error) {
|
217 | if (error) {
|
218 | _this.executor.emit('error', new Error("Error sending ack for [ " + message.id + " ]: " + error.message));
|
219 | }
|
220 | });
|
221 | });
|
222 | });
|
223 | client.on('error', function (error) {
|
224 | _this.executor.log('WebSocket client error:', error);
|
225 | _this.executor.emit('error', error);
|
226 | });
|
227 | };
|
228 | Server.prototype._publish = function (message) {
|
229 | var listeners = this._getSession(message.sessionId).listeners;
|
230 | return Promise.all(listeners.map(function (listener) { return listener(message.name, message.data); }));
|
231 | };
|
232 | return Server;
|
233 | }());
|
234 | exports.default = Server;
|
235 | var resolvedPromise = Promise.resolve();
|
236 | function getShouldWait(waitMode, message) {
|
237 | var eventName = message.name;
|
238 | if (eventName === 'runEnd') {
|
239 | return false;
|
240 | }
|
241 | var shouldWait = false;
|
242 | if (waitMode === 'fail') {
|
243 | if ((eventName === 'testEnd' && message.data.error) ||
|
244 | (eventName === 'suiteEnd' && message.data.error) ||
|
245 | eventName === 'error') {
|
246 | shouldWait = true;
|
247 | }
|
248 | }
|
249 | else if (waitMode === true) {
|
250 | shouldWait = true;
|
251 | }
|
252 | else if (Array.isArray(waitMode) && waitMode.indexOf(eventName) !== -1) {
|
253 | shouldWait = true;
|
254 | }
|
255 | return shouldWait;
|
256 | }
|
257 | });
|
258 |
|
\ | No newline at end of file |