Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / socket.io-client / components / learnboost-engine.io-client / lib / socket.js
1 /**
2  * Module dependencies.
3  */
4
5 var util = require('./util')
6   , transports = require('./transports')
7   , Emitter = require('./emitter')
8   , debug = require('debug')('engine-client:socket');
9
10 /**
11  * Module exports.
12  */
13
14 module.exports = Socket;
15
16 /**
17  * Global reference.
18  */
19
20 var global = 'undefined' != typeof window ? window : global;
21
22 /**
23  * Socket constructor.
24  *
25  * @param {Object} options
26  * @api public
27  */
28
29 function Socket(opts){
30   if (!(this instanceof Socket)) return new Socket(opts);
31
32   if ('string' == typeof opts) {
33     var uri = util.parseUri(opts);
34     opts = arguments[1] || {};
35     opts.host = uri.host;
36     opts.secure = uri.protocol == 'https' || uri.protocol == 'wss';
37     opts.port = uri.port;
38   }
39
40   opts = opts || {};
41   this.secure = null != opts.secure ? opts.secure : (global.location && 'https:' == location.protocol);
42   this.host = opts.host || opts.hostname || (global.location ? location.hostname : 'localhost');
43   this.port = opts.port || (global.location && location.port ? location.port : (this.secure ? 443 : 80));
44   this.query = opts.query || {};
45   this.query.uid = rnd();
46   this.upgrade = false !== opts.upgrade;
47   this.resource = opts.resource || 'default';
48   this.path = (opts.path || '/engine.io').replace(/\/$/, '');
49   this.path += '/' + this.resource + '/';
50   this.forceJSONP = !!opts.forceJSONP;
51   this.timestampParam = opts.timestampParam || 't';
52   this.timestampRequests = !!opts.timestampRequests;
53   this.flashPath = opts.flashPath || '';
54   this.transports = opts.transports || ['polling', 'websocket', 'flashsocket'];
55   this.readyState = '';
56   this.writeBuffer = [];
57   this.policyPort = opts.policyPort || 843;
58   this.open();
59
60   Socket.sockets.push(this);
61   Socket.sockets.evs.emit('add', this);
62 };
63
64 /**
65  * Mix in `Emitter`.
66  */
67
68 Emitter(Socket.prototype);
69
70 /**
71  * Protocol version.
72  *
73  * @api public
74  */
75
76 Socket.protocol = 1;
77
78 /**
79  * Static EventEmitter.
80  */
81
82 Socket.sockets = [];
83 Socket.sockets.evs = new Emitter;
84
85 /**
86  * Expose deps for legacy compatibility
87  * and standalone browser access.
88  */
89
90 Socket.Socket = Socket;
91 Socket.Transport = require('./transport');
92 Socket.Emitter = require('./emitter');
93 Socket.transports = require('./transports');
94 Socket.util = require('./util');
95 Socket.parser = require('./parser');
96
97 /**
98  * Creates transport of the given type.
99  *
100  * @param {String} transport name
101  * @return {Transport}
102  * @api private
103  */
104
105 Socket.prototype.createTransport = function (name) {
106   debug('creating transport "%s"', name);
107   var query = clone(this.query);
108   query.transport = name;
109
110   if (this.id) {
111     query.sid = this.id;
112   }
113
114   var transport = new transports[name]({
115       host: this.host
116     , port: this.port
117     , secure: this.secure
118     , path: this.path
119     , query: query
120     , forceJSONP: this.forceJSONP
121     , timestampRequests: this.timestampRequests
122     , timestampParam: this.timestampParam
123     , flashPath: this.flashPath
124     , policyPort: this.policyPort
125   });
126
127   return transport;
128 };
129
130 function clone (obj) {
131   var o = {};
132   for (var i in obj) {
133     if (obj.hasOwnProperty(i)) {
134       o[i] = obj[i];
135     }
136   }
137   return o;
138 }
139
140 /**
141  * Initializes transport to use and starts probe.
142  *
143  * @api private
144  */
145
146 Socket.prototype.open = function () {
147   this.readyState = 'opening';
148   var transport = this.createTransport(this.transports[0]);
149   transport.open();
150   this.setTransport(transport);
151 };
152
153 /**
154  * Sets the current transport. Disables the existing one (if any).
155  *
156  * @api private
157  */
158
159 Socket.prototype.setTransport = function (transport) {
160   var self = this;
161
162   if (this.transport) {
163     debug('clearing existing transport');
164     this.transport.removeAllListeners();
165   }
166
167   // set up transport
168   this.transport = transport;
169
170   // set up transport listeners
171   transport
172     .on('drain', function () {
173       self.flush();
174     })
175     .on('packet', function (packet) {
176       self.onPacket(packet);
177     })
178     .on('error', function (e) {
179       self.onError(e);
180     })
181     .on('close', function () {
182       self.onClose('transport close');
183     });
184 };
185
186 /**
187  * Probes a transport.
188  *
189  * @param {String} transport name
190  * @api private
191  */
192
193 Socket.prototype.probe = function (name) {
194   debug('probing transport "%s"', name);
195   var transport = this.createTransport(name, { probe: 1 })
196     , failed = false
197     , self = this;
198
199   transport.once('open', function () {
200     if (failed) return;
201
202     debug('probe transport "%s" opened', name);
203     transport.send([{ type: 'ping', data: 'probe' }]);
204     transport.once('packet', function (msg) {
205       if (failed) return;
206       if ('pong' == msg.type && 'probe' == msg.data) {
207         debug('probe transport "%s" pong', name);
208         self.upgrading = true;
209         self.emit('upgrading', transport);
210
211         debug('pausing current transport "%s"', self.transport.name);
212         self.transport.pause(function () {
213           if (failed) return;
214           if ('closed' == self.readyState || 'closing' == self.readyState) {
215             return;
216           }
217           debug('changing transport and sending upgrade packet');
218           transport.removeListener('error', onerror);
219           self.emit('upgrade', transport);
220           self.setTransport(transport);
221           transport.send([{ type: 'upgrade' }]);
222           transport = null;
223           self.upgrading = false;
224           self.flush();
225         });
226       } else {
227         debug('probe transport "%s" failed', name);
228         var err = new Error('probe error');
229         err.transport = transport.name;
230         self.emit('error', err);
231       }
232     });
233   });
234
235   transport.once('error', onerror);
236   function onerror(err) {
237     if (failed) return;
238
239     // Any callback called by transport should be ignored since now
240     failed = true;
241
242     var error = new Error('probe error: ' + err);
243     error.transport = transport.name;
244
245     transport.close();
246     transport = null;
247
248     debug('probe transport "%s" failed because of error: %s', name, err);
249
250     self.emit('error', error);
251   };
252
253   transport.open();
254
255   this.once('close', function () {
256     if (transport) {
257       debug('socket closed prematurely - aborting probe');
258       failed = true;
259       transport.close();
260       transport = null;
261     }
262   });
263
264   this.once('upgrading', function (to) {
265     if (transport && to.name != transport.name) {
266       debug('"%s" works - aborting "%s"', to.name, transport.name);
267       transport.close();
268       transport = null;
269     }
270   });
271 };
272
273 /**
274  * Called when connection is deemed open.
275  *
276  * @api public
277  */
278
279 Socket.prototype.onOpen = function () {
280   debug('socket open');
281   this.readyState = 'open';
282   this.emit('open');
283   this.onopen && this.onopen.call(this);
284   this.flush();
285
286   // we check for `readyState` in case an `open`
287   // listener alreay closed the socket
288   if ('open' == this.readyState && this.upgrade && this.transport.pause) {
289     debug('starting upgrade probes');
290     for (var i = 0, l = this.upgrades.length; i < l; i++) {
291       this.probe(this.upgrades[i]);
292     }
293   }
294 };
295
296 /**
297  * Handles a packet.
298  *
299  * @api private
300  */
301
302 Socket.prototype.onPacket = function (packet) {
303   if ('opening' == this.readyState || 'open' == this.readyState) {
304     debug('socket receive: type "%s", data "%s"', packet.type, packet.data);
305
306     this.emit('packet', packet);
307
308     // Socket is live - any packet counts
309     this.emit('heartbeat');
310
311     switch (packet.type) {
312       case 'open':
313         this.onHandshake(util.parseJSON(packet.data));
314         break;
315
316       case 'pong':
317         this.ping();
318         break;
319
320       case 'error':
321         var err = new Error('server error');
322         err.code = packet.data;
323         this.emit('error', err);
324         break;
325
326       case 'message':
327         this.emit('message', packet.data);
328         var event = { data: packet.data };
329         event.toString = function () {
330           return packet.data;
331         };
332         this.onmessage && this.onmessage.call(this, event);
333         break;
334     }
335   } else {
336     debug('packet received with socket readyState "%s"', this.readyState);
337   }
338 };
339
340 /**
341  * Called upon handshake completion.
342  *
343  * @param {Object} handshake obj
344  * @api private
345  */
346
347 Socket.prototype.onHandshake = function (data) {
348   this.emit('handshake', data);
349   this.id = data.sid;
350   this.transport.query.sid = data.sid;
351   this.upgrades = data.upgrades;
352   this.pingInterval = data.pingInterval;
353   this.pingTimeout = data.pingTimeout;
354   this.onOpen();
355   this.ping();
356
357   // Prolong liveness of socket on heartbeat
358   this.removeListener('heartbeat', this.onHeartbeat);
359   this.on('heartbeat', this.onHeartbeat);
360 };
361
362 /**
363  * Resets ping timeout.
364  *
365  * @api private
366  */
367
368 Socket.prototype.onHeartbeat = function (timeout) {
369   clearTimeout(this.pingTimeoutTimer);
370   var self = this;
371   self.pingTimeoutTimer = setTimeout(function () {
372     if ('closed' == self.readyState) return;
373     self.onClose('ping timeout');
374   }, timeout || (self.pingInterval + self.pingTimeout));
375 };
376
377 /**
378  * Pings server every `this.pingInterval` and expects response
379  * within `this.pingTimeout` or closes connection.
380  *
381  * @api private
382  */
383
384 Socket.prototype.ping = function () {
385   var self = this;
386   clearTimeout(self.pingIntervalTimer);
387   self.pingIntervalTimer = setTimeout(function () {
388     debug('writing ping packet - expecting pong within %sms', self.pingTimeout);
389     self.sendPacket('ping');
390     self.onHeartbeat(self.pingTimeout);
391   }, self.pingInterval);
392 };
393
394 /**
395  * Flush write buffers.
396  *
397  * @api private
398  */
399
400 Socket.prototype.flush = function () {
401   if ('closed' != this.readyState && this.transport.writable &&
402     !this.upgrading && this.writeBuffer.length) {
403     debug('flushing %d packets in socket', this.writeBuffer.length);
404     this.transport.send(this.writeBuffer);
405     this.writeBuffer = [];
406   }
407 };
408
409 /**
410  * Sends a message.
411  *
412  * @param {String} message.
413  * @return {Socket} for chaining.
414  * @api public
415  */
416
417 Socket.prototype.write =
418 Socket.prototype.send = function (msg) {
419   this.sendPacket('message', msg);
420   return this;
421 };
422
423 /**
424  * Sends a packet.
425  *
426  * @param {String} packet type.
427  * @param {String} data.
428  * @api private
429  */
430
431 Socket.prototype.sendPacket = function (type, data) {
432   var packet = { type: type, data: data };
433   this.emit('packetCreate', packet);
434   this.writeBuffer.push(packet);
435   this.flush();
436 };
437
438 /**
439  * Closes the connection.
440  *
441  * @api private
442  */
443
444 Socket.prototype.close = function () {
445   if ('opening' == this.readyState || 'open' == this.readyState) {
446     this.onClose('forced close');
447     debug('socket closing - telling transport to close');
448     this.transport.close();
449     this.transport.removeAllListeners();
450   }
451
452   return this;
453 };
454
455 /**
456  * Called upon transport error
457  *
458  * @api private
459  */
460
461 Socket.prototype.onError = function (err) {
462   this.emit('error', err);
463   this.onClose('transport error', err);
464 };
465
466 /**
467  * Called upon transport close.
468  *
469  * @api private
470  */
471
472 Socket.prototype.onClose = function (reason, desc) {
473   if ('closed' != this.readyState) {
474     debug('socket close with reason: "%s"', reason);
475     clearTimeout(this.pingIntervalTimer);
476     clearTimeout(this.pingTimeoutTimer);
477     this.readyState = 'closed';
478     this.emit('close', reason, desc);
479     this.onclose && this.onclose.call(this);
480     this.id = null;
481   }
482 };
483
484 /**
485  * Generates a random uid.
486  *
487  * @api private
488  */
489
490 function rnd () {
491   return String(Math.random()).substr(5) + String(Math.random()).substr(5);
492 }