UNPKG

11.4 kBJavaScriptView Raw
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//# sourceMappingURL=Server.js.map
\No newline at end of file