Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / socket.io-client / lib / socket.js
1 /**
2  * socket.io
3  * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
4  * MIT Licensed
5  */
6
7 (function (exports, io, global) {
8
9   /**
10    * Expose constructor.
11    */
12
13   exports.Socket = Socket;
14
15   /**
16    * Create a new `Socket.IO client` which can establish a persistent
17    * connection with a Socket.IO enabled server.
18    *
19    * @api public
20    */
21
22   function Socket (options) {
23     this.options = {
24         port: 80
25       , secure: false
26       , document: 'document' in global ? document : false
27       , resource: 'socket.io'
28       , transports: io.transports
29       , 'connect timeout': 10000
30       , 'try multiple transports': true
31       , 'reconnect': true
32       , 'reconnection delay': 500
33       , 'reconnection limit': Infinity
34       , 'reopen delay': 3000
35       , 'max reconnection attempts': 10
36       , 'sync disconnect on unload': false
37       , 'auto connect': true
38       , 'flash policy port': 10843
39       , 'manualFlush': false
40     };
41
42     io.util.merge(this.options, options);
43
44     this.connected = false;
45     this.open = false;
46     this.connecting = false;
47     this.reconnecting = false;
48     this.namespaces = {};
49     this.buffer = [];
50     this.doBuffer = false;
51
52     if (this.options['sync disconnect on unload'] &&
53         (!this.isXDomain() || io.util.ua.hasCORS)) {
54       var self = this;
55       io.util.on(global, 'beforeunload', function () {
56         self.disconnectSync();
57       }, false);
58     }
59
60     if (this.options['auto connect']) {
61       this.connect();
62     }
63 };
64
65   /**
66    * Apply EventEmitter mixin.
67    */
68
69   io.util.mixin(Socket, io.EventEmitter);
70
71   /**
72    * Returns a namespace listener/emitter for this socket
73    *
74    * @api public
75    */
76
77   Socket.prototype.of = function (name) {
78     if (!this.namespaces[name]) {
79       this.namespaces[name] = new io.SocketNamespace(this, name);
80
81       if (name !== '') {
82         this.namespaces[name].packet({ type: 'connect' });
83       }
84     }
85
86     return this.namespaces[name];
87   };
88
89   /**
90    * Emits the given event to the Socket and all namespaces
91    *
92    * @api private
93    */
94
95   Socket.prototype.publish = function () {
96     this.emit.apply(this, arguments);
97
98     var nsp;
99
100     for (var i in this.namespaces) {
101       if (this.namespaces.hasOwnProperty(i)) {
102         nsp = this.of(i);
103         nsp.$emit.apply(nsp, arguments);
104       }
105     }
106   };
107
108   /**
109    * Performs the handshake
110    *
111    * @api private
112    */
113
114   function empty () { };
115
116   Socket.prototype.handshake = function (fn) {
117     var self = this
118       , options = this.options;
119
120     function complete (data) {
121       if (data instanceof Error) {
122         self.connecting = false;
123         self.onError(data.message);
124       } else {
125         fn.apply(null, data.split(':'));
126       }
127     };
128
129     var url = [
130           'http' + (options.secure ? 's' : '') + ':/'
131         , options.host + ':' + options.port
132         , options.resource
133         , io.protocol
134         , io.util.query(this.options.query, 't=' + +new Date)
135       ].join('/');
136
137     if (this.isXDomain() && !io.util.ua.hasCORS) {
138       var insertAt = document.getElementsByTagName('script')[0]
139         , script = document.createElement('script');
140
141       script.src = url + '&jsonp=' + io.j.length;
142       insertAt.parentNode.insertBefore(script, insertAt);
143
144       io.j.push(function (data) {
145         complete(data);
146         script.parentNode.removeChild(script);
147       });
148     } else {
149       var xhr = io.util.request();
150
151       xhr.open('GET', url, true);
152       if (this.isXDomain()) {
153         xhr.withCredentials = true;
154       }
155       xhr.onreadystatechange = function () {
156         if (xhr.readyState == 4) {
157           xhr.onreadystatechange = empty;
158
159           if (xhr.status == 200) {
160             complete(xhr.responseText);
161           } else if (xhr.status == 403) {
162             self.onError(xhr.responseText);
163           } else {
164             self.connecting = false;            
165             !self.reconnecting && self.onError(xhr.responseText);
166           }
167         }
168       };
169       xhr.send(null);
170     }
171   };
172
173   /**
174    * Find an available transport based on the options supplied in the constructor.
175    *
176    * @api private
177    */
178
179   Socket.prototype.getTransport = function (override) {
180     var transports = override || this.transports, match;
181
182     for (var i = 0, transport; transport = transports[i]; i++) {
183       if (io.Transport[transport]
184         && io.Transport[transport].check(this)
185         && (!this.isXDomain() || io.Transport[transport].xdomainCheck(this))) {
186         return new io.Transport[transport](this, this.sessionid);
187       }
188     }
189
190     return null;
191   };
192
193   /**
194    * Connects to the server.
195    *
196    * @param {Function} [fn] Callback.
197    * @returns {io.Socket}
198    * @api public
199    */
200
201   Socket.prototype.connect = function (fn) {
202     if (this.connecting) {
203       return this;
204     }
205
206     var self = this;
207     self.connecting = true;
208     
209     this.handshake(function (sid, heartbeat, close, transports) {
210       self.sessionid = sid;
211       self.closeTimeout = close * 1000;
212       self.heartbeatTimeout = heartbeat * 1000;
213       if(!self.transports)
214           self.transports = self.origTransports = (transports ? io.util.intersect(
215               transports.split(',')
216             , self.options.transports
217           ) : self.options.transports);
218
219       self.setHeartbeatTimeout();
220
221       function connect (transports){
222         if (self.transport) self.transport.clearTimeouts();
223
224         self.transport = self.getTransport(transports);
225         if (!self.transport) return self.publish('connect_failed');
226
227         // once the transport is ready
228         self.transport.ready(self, function () {
229           self.connecting = true;
230           self.publish('connecting', self.transport.name);
231           self.transport.open();
232
233           if (self.options['connect timeout']) {
234             self.connectTimeoutTimer = setTimeout(function () {
235               if (!self.connected) {
236                 self.connecting = false;
237
238                 if (self.options['try multiple transports']) {
239                   var remaining = self.transports;
240
241                   while (remaining.length > 0 && remaining.splice(0,1)[0] !=
242                          self.transport.name) {}
243
244                     if (remaining.length){
245                       connect(remaining);
246                     } else {
247                       self.publish('connect_failed');
248                     }
249                 }
250               }
251             }, self.options['connect timeout']);
252           }
253         });
254       }
255
256       connect(self.transports);
257
258       self.once('connect', function (){
259         clearTimeout(self.connectTimeoutTimer);
260
261         fn && typeof fn == 'function' && fn();
262       });
263     });
264
265     return this;
266   };
267
268   /**
269    * Clears and sets a new heartbeat timeout using the value given by the
270    * server during the handshake.
271    *
272    * @api private
273    */
274
275   Socket.prototype.setHeartbeatTimeout = function () {
276     clearTimeout(this.heartbeatTimeoutTimer);
277     if(this.transport && !this.transport.heartbeats()) return;
278
279     var self = this;
280     this.heartbeatTimeoutTimer = setTimeout(function () {
281       self.transport.onClose();
282     }, this.heartbeatTimeout);
283   };
284
285   /**
286    * Sends a message.
287    *
288    * @param {Object} data packet.
289    * @returns {io.Socket}
290    * @api public
291    */
292
293   Socket.prototype.packet = function (data) {
294     if (this.connected && !this.doBuffer) {
295       this.transport.packet(data);
296     } else {
297       this.buffer.push(data);
298     }
299
300     return this;
301   };
302
303   /**
304    * Sets buffer state
305    *
306    * @api private
307    */
308
309   Socket.prototype.setBuffer = function (v) {
310     this.doBuffer = v;
311
312     if (!v && this.connected && this.buffer.length) {
313       if (!this.options['manualFlush']) {
314         this.flushBuffer();
315       }
316     }
317   };
318
319   /**
320    * Flushes the buffer data over the wire.
321    * To be invoked manually when 'manualFlush' is set to true.
322    *
323    * @api public
324    */
325
326   Socket.prototype.flushBuffer = function() {
327     this.transport.payload(this.buffer);
328     this.buffer = [];
329   };
330   
331
332   /**
333    * Disconnect the established connect.
334    *
335    * @returns {io.Socket}
336    * @api public
337    */
338
339   Socket.prototype.disconnect = function () {
340     if (this.connected || this.connecting) {
341       if (this.open) {
342         this.of('').packet({ type: 'disconnect' });
343       }
344
345       // handle disconnection immediately
346       this.onDisconnect('booted');
347     }
348
349     return this;
350   };
351
352   /**
353    * Disconnects the socket with a sync XHR.
354    *
355    * @api private
356    */
357
358   Socket.prototype.disconnectSync = function () {
359     // ensure disconnection
360     var xhr = io.util.request();
361     var uri = [
362         'http' + (this.options.secure ? 's' : '') + ':/'
363       , this.options.host + ':' + this.options.port
364       , this.options.resource
365       , io.protocol
366       , ''
367       , this.sessionid
368     ].join('/') + '/?disconnect=1';
369
370     xhr.open('GET', uri, false);
371     xhr.send(null);
372
373     // handle disconnection immediately
374     this.onDisconnect('booted');
375   };
376
377   /**
378    * Check if we need to use cross domain enabled transports. Cross domain would
379    * be a different port or different domain name.
380    *
381    * @returns {Boolean}
382    * @api private
383    */
384
385   Socket.prototype.isXDomain = function () {
386     // if node
387     return false;
388     // end node
389
390     var port = global.location.port ||
391       ('https:' == global.location.protocol ? 443 : 80);
392
393     return this.options.host !== global.location.hostname 
394       || this.options.port != port;
395   };
396
397   /**
398    * Called upon handshake.
399    *
400    * @api private
401    */
402
403   Socket.prototype.onConnect = function () {
404     if (!this.connected) {
405       this.connected = true;
406       this.connecting = false;
407       if (!this.doBuffer) {
408         // make sure to flush the buffer
409         this.setBuffer(false);
410       }
411       this.emit('connect');
412     }
413   };
414
415   /**
416    * Called when the transport opens
417    *
418    * @api private
419    */
420
421   Socket.prototype.onOpen = function () {
422     this.open = true;
423   };
424
425   /**
426    * Called when the transport closes.
427    *
428    * @api private
429    */
430
431   Socket.prototype.onClose = function () {
432     this.open = false;
433     clearTimeout(this.heartbeatTimeoutTimer);
434   };
435
436   /**
437    * Called when the transport first opens a connection
438    *
439    * @param text
440    */
441
442   Socket.prototype.onPacket = function (packet) {
443     this.of(packet.endpoint).onPacket(packet);
444   };
445
446   /**
447    * Handles an error.
448    *
449    * @api private
450    */
451
452   Socket.prototype.onError = function (err) {
453     if (err && err.advice) {
454       if (err.advice === 'reconnect' && (this.connected || this.connecting)) {
455         this.disconnect();
456         if (this.options.reconnect) {
457           this.reconnect();
458         }
459       }
460     }
461
462     this.publish('error', err && err.reason ? err.reason : err);
463   };
464
465   /**
466    * Called when the transport disconnects.
467    *
468    * @api private
469    */
470
471   Socket.prototype.onDisconnect = function (reason) {
472     var wasConnected = this.connected
473       , wasConnecting = this.connecting;
474
475     this.connected = false;
476     this.connecting = false;
477     this.open = false;
478
479     if (wasConnected || wasConnecting) {
480       this.transport.close();
481       this.transport.clearTimeouts();
482       if (wasConnected) {
483         this.publish('disconnect', reason);
484
485         if ('booted' != reason && this.options.reconnect && !this.reconnecting) {
486           this.reconnect();
487         }
488       }
489     }
490   };
491
492   /**
493    * Called upon reconnection.
494    *
495    * @api private
496    */
497
498   Socket.prototype.reconnect = function () {
499     this.reconnecting = true;
500     this.reconnectionAttempts = 0;
501     this.reconnectionDelay = this.options['reconnection delay'];
502
503     var self = this
504       , maxAttempts = this.options['max reconnection attempts']
505       , tryMultiple = this.options['try multiple transports']
506       , limit = this.options['reconnection limit'];
507
508     function reset () {
509       if (self.connected) {
510         for (var i in self.namespaces) {
511           if (self.namespaces.hasOwnProperty(i) && '' !== i) {
512               self.namespaces[i].packet({ type: 'connect' });
513           }
514         }
515         self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
516       }
517
518       clearTimeout(self.reconnectionTimer);
519
520       self.removeListener('connect_failed', maybeReconnect);
521       self.removeListener('connect', maybeReconnect);
522
523       self.reconnecting = false;
524
525       delete self.reconnectionAttempts;
526       delete self.reconnectionDelay;
527       delete self.reconnectionTimer;
528       delete self.redoTransports;
529
530       self.options['try multiple transports'] = tryMultiple;
531     };
532
533     function maybeReconnect () {
534       if (!self.reconnecting) {
535         return;
536       }
537
538       if (self.connected) {
539         return reset();
540       };
541
542       if (self.connecting && self.reconnecting) {
543         return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
544       }
545
546       if (self.reconnectionAttempts++ >= maxAttempts) {
547         if (!self.redoTransports) {
548           self.on('connect_failed', maybeReconnect);
549           self.options['try multiple transports'] = true;
550           self.transports = self.origTransports;
551           self.transport = self.getTransport();
552           self.redoTransports = true;
553           self.connect();
554         } else {
555           self.publish('reconnect_failed');
556           reset();
557         }
558       } else {
559         if (self.reconnectionDelay < limit) {
560           self.reconnectionDelay *= 2; // exponential back off
561         }
562
563         self.connect();
564         self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
565         self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
566       }
567     };
568
569     this.options['try multiple transports'] = false;
570     this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);
571
572     this.on('connect', maybeReconnect);
573   };
574
575 })(
576     'undefined' != typeof io ? io : module.exports
577   , 'undefined' != typeof io ? io : module.parent.exports
578   , this
579 );