PageRenderTime 169ms CodeModel.GetById 5ms app.highlight 126ms RepoModel.GetById 1ms app.codeStats 2ms

/socket.io.js

https://github.com/petey/socket.io-client
JavaScript | 5965 lines | 3358 code | 919 blank | 1688 comment | 951 complexity | 1a99e4a476cb06d22efb5bd543ae37d9 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.io=e():"undefined"!=typeof global?global.io=e():"undefined"!=typeof self&&(self.io=e())}(function(){var define,module,exports;
   2return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
   3
   4module.exports = require('./lib/');
   5
   6},{"./lib/":2}],2:[function(require,module,exports){
   7
   8/**
   9 * Module dependencies.
  10 */
  11
  12var url = require('./url');
  13var parser = require('socket.io-parser');
  14var Manager = require('./manager');
  15var debug = require('debug')('socket.io-client');
  16
  17/**
  18 * Module exports.
  19 */
  20
  21module.exports = exports = lookup;
  22
  23/**
  24 * Managers cache.
  25 */
  26
  27var cache = exports.managers = {};
  28
  29/**
  30 * Looks up an existing `Manager` for multiplexing.
  31 * If the user summons:
  32 *
  33 *   `io('http://localhost/a');`
  34 *   `io('http://localhost/b');`
  35 *
  36 * We reuse the existing instance based on same scheme/port/host,
  37 * and we initialize sockets for each namespace.
  38 *
  39 * @api public
  40 */
  41
  42function lookup(uri, opts) {
  43  if (typeof uri == 'object') {
  44    opts = uri;
  45    uri = undefined;
  46  }
  47
  48  opts = opts || {};
  49
  50  var parsed = url(uri);
  51  var source = parsed.source;
  52  var id = parsed.id;
  53  var io;
  54
  55  if (opts.forceNew || false === opts.multiplex) {
  56    debug('ignoring socket cache for %s', source);
  57    io = Manager(source, opts);
  58  } else {
  59    if (!cache[id]) {
  60      debug('new io instance for %s', source);
  61      cache[id] = Manager(source, opts);
  62    }
  63    io = cache[id];
  64  }
  65
  66  return io.socket(parsed.path);
  67}
  68
  69/**
  70 * Protocol version.
  71 *
  72 * @api public
  73 */
  74
  75exports.protocol = parser.protocol;
  76
  77/**
  78 * `connect`.
  79 *
  80 * @param {String} uri
  81 * @api public
  82 */
  83
  84exports.connect = lookup;
  85
  86/**
  87 * Expose constructors for standalone build.
  88 *
  89 * @api public
  90 */
  91
  92exports.Manager = require('./manager');
  93exports.Socket = require('./socket');
  94
  95},{"./manager":3,"./socket":5,"./url":6,"debug":8,"socket.io-parser":39}],3:[function(require,module,exports){
  96
  97/**
  98 * Module dependencies.
  99 */
 100
 101var url = require('./url');
 102var eio = require('engine.io-client');
 103var Socket = require('./socket');
 104var Emitter = require('emitter');
 105var parser = require('socket.io-parser');
 106var on = require('./on');
 107var bind = require('bind');
 108var object = require('object-component');
 109var debug = require('debug')('socket.io-client:manager');
 110
 111/**
 112 * Module exports
 113 */
 114
 115module.exports = Manager;
 116
 117/**
 118 * `Manager` constructor.
 119 *
 120 * @param {String} engine instance or engine uri/opts
 121 * @param {Object} options
 122 * @api public
 123 */
 124
 125function Manager(uri, opts){
 126  if (!(this instanceof Manager)) return new Manager(uri, opts);
 127  if ('object' == typeof uri) {
 128    opts = uri;
 129    uri = undefined;
 130  }
 131  opts = opts || {};
 132
 133  opts.path = opts.path || '/socket.io';
 134  this.nsps = {};
 135  this.subs = [];
 136  this.opts = opts;
 137  this.reconnection(opts.reconnection !== false);
 138  this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);
 139  this.reconnectionDelay(opts.reconnectionDelay || 1000);
 140  this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);
 141  this.timeout(null == opts.timeout ? 20000 : opts.timeout);
 142  this.readyState = 'closed';
 143  this.uri = uri;
 144  this.connected = 0;
 145  this.attempts = 0;
 146  this.encoding = false;
 147  this.packetBuffer = [];
 148  this.encoder = new parser.Encoder();
 149  this.decoder = new parser.Decoder();
 150  this.open();
 151}
 152
 153/**
 154 * Mix in `Emitter`.
 155 */
 156
 157Emitter(Manager.prototype);
 158
 159/**
 160 * Sets the `reconnection` config.
 161 *
 162 * @param {Boolean} true/false if it should automatically reconnect
 163 * @return {Manager} self or value
 164 * @api public
 165 */
 166
 167Manager.prototype.reconnection = function(v){
 168  if (!arguments.length) return this._reconnection;
 169  this._reconnection = !!v;
 170  return this;
 171};
 172
 173/**
 174 * Sets the reconnection attempts config.
 175 *
 176 * @param {Number} max reconnection attempts before giving up
 177 * @return {Manager} self or value
 178 * @api public
 179 */
 180
 181Manager.prototype.reconnectionAttempts = function(v){
 182  if (!arguments.length) return this._reconnectionAttempts;
 183  this._reconnectionAttempts = v;
 184  return this;
 185};
 186
 187/**
 188 * Sets the delay between reconnections.
 189 *
 190 * @param {Number} delay
 191 * @return {Manager} self or value
 192 * @api public
 193 */
 194
 195Manager.prototype.reconnectionDelay = function(v){
 196  if (!arguments.length) return this._reconnectionDelay;
 197  this._reconnectionDelay = v;
 198  return this;
 199};
 200
 201/**
 202 * Sets the maximum delay between reconnections.
 203 *
 204 * @param {Number} delay
 205 * @return {Manager} self or value
 206 * @api public
 207 */
 208
 209Manager.prototype.reconnectionDelayMax = function(v){
 210  if (!arguments.length) return this._reconnectionDelayMax;
 211  this._reconnectionDelayMax = v;
 212  return this;
 213};
 214
 215/**
 216 * Sets the connection timeout. `false` to disable
 217 *
 218 * @return {Manager} self or value
 219 * @api public
 220 */
 221
 222Manager.prototype.timeout = function(v){
 223  if (!arguments.length) return this._timeout;
 224  this._timeout = v;
 225  return this;
 226};
 227
 228/**
 229 * Starts trying to reconnect if reconnection is enabled and we have not
 230 * started reconnecting yet
 231 *
 232 * @api private
 233 */
 234
 235Manager.prototype.maybeReconnectOnOpen = function() {
 236  if (!this.openReconnect && !this.reconnecting && this._reconnection) {
 237    // keeps reconnection from firing twice for the same reconnection loop
 238    this.openReconnect = true;
 239    this.reconnect();
 240  }
 241};
 242
 243
 244/**
 245 * Sets the current transport `socket`.
 246 *
 247 * @param {Function} optional, callback
 248 * @return {Manager} self
 249 * @api public
 250 */
 251
 252Manager.prototype.open =
 253Manager.prototype.connect = function(fn){
 254  debug('readyState %s', this.readyState);
 255  if (~this.readyState.indexOf('open')) return this;
 256
 257  debug('opening %s', this.uri);
 258  this.engine = eio(this.uri, this.opts);
 259  var socket = this.engine;
 260  var self = this;
 261  this.readyState = 'opening';
 262
 263  // emit `open`
 264  var openSub = on(socket, 'open', function() {
 265    self.onopen();
 266    fn && fn();
 267  });
 268
 269  // emit `connect_error`
 270  var errorSub = on(socket, 'error', function(data){
 271    debug('connect_error');
 272    self.cleanup();
 273    self.readyState = 'closed';
 274    self.emit('connect_error', data);
 275    if (fn) {
 276      var err = new Error('Connection error');
 277      err.data = data;
 278      fn(err);
 279    }
 280
 281    self.maybeReconnectOnOpen();
 282  });
 283
 284  // emit `connect_timeout`
 285  if (false !== this._timeout) {
 286    var timeout = this._timeout;
 287    debug('connect attempt will timeout after %d', timeout);
 288
 289    // set timer
 290    var timer = setTimeout(function(){
 291      debug('connect attempt timed out after %d', timeout);
 292      openSub.destroy();
 293      socket.close();
 294      socket.emit('error', 'timeout');
 295      self.emit('connect_timeout', timeout);
 296    }, timeout);
 297
 298    this.subs.push({
 299      destroy: function(){
 300        clearTimeout(timer);
 301      }
 302    });
 303  }
 304
 305  this.subs.push(openSub);
 306  this.subs.push(errorSub);
 307
 308  return this;
 309};
 310
 311/**
 312 * Called upon transport open.
 313 *
 314 * @api private
 315 */
 316
 317Manager.prototype.onopen = function(){
 318  debug('open');
 319
 320  // clear old subs
 321  this.cleanup();
 322
 323  // mark as open
 324  this.readyState = 'open';
 325  this.emit('open');
 326
 327  // add new subs
 328  var socket = this.engine;
 329  this.subs.push(on(socket, 'data', bind(this, 'ondata')));
 330  this.subs.push(on(this.decoder, 'decoded', bind(this, 'ondecoded')));
 331  this.subs.push(on(socket, 'error', bind(this, 'onerror')));
 332  this.subs.push(on(socket, 'close', bind(this, 'onclose')));
 333};
 334
 335/**
 336 * Called with data.
 337 *
 338 * @api private
 339 */
 340
 341Manager.prototype.ondata = function(data){
 342  this.decoder.add(data);
 343};
 344
 345/**
 346 * Called when parser fully decodes a packet.
 347 *
 348 * @api private
 349 */
 350
 351Manager.prototype.ondecoded = function(packet) {
 352  this.emit('packet', packet);
 353};
 354
 355/**
 356 * Called upon socket error.
 357 *
 358 * @api private
 359 */
 360
 361Manager.prototype.onerror = function(err){
 362  debug('error', err);
 363  this.emit('error', err);
 364};
 365
 366/**
 367 * Creates a new socket for the given `nsp`.
 368 *
 369 * @return {Socket}
 370 * @api public
 371 */
 372
 373Manager.prototype.socket = function(nsp){
 374  var socket = this.nsps[nsp];
 375  if (!socket) {
 376    socket = new Socket(this, nsp);
 377    this.nsps[nsp] = socket;
 378    var self = this;
 379    socket.on('connect', function(){
 380      self.connected++;
 381    });
 382  }
 383  return socket;
 384};
 385
 386/**
 387 * Called upon a socket close.
 388 *
 389 * @param {Socket} socket
 390 */
 391
 392Manager.prototype.destroy = function(socket){
 393  --this.connected || this.close();
 394};
 395
 396/**
 397 * Writes a packet.
 398 *
 399 * @param {Object} packet
 400 * @api private
 401 */
 402
 403Manager.prototype.packet = function(packet){
 404  debug('writing packet %j', packet);
 405  var self = this;
 406
 407  if (!self.encoding) {
 408    // encode, then write to engine with result
 409    self.encoding = true;
 410    this.encoder.encode(packet, function(encodedPackets) {
 411      for (var i = 0; i < encodedPackets.length; i++) {
 412        self.engine.write(encodedPackets[i]);
 413      }
 414      self.encoding = false;
 415      self.processPacketQueue();
 416    });
 417  } else { // add packet to the queue
 418    self.packetBuffer.push(packet);
 419  }
 420};
 421
 422/**
 423 * If packet buffer is non-empty, begins encoding the
 424 * next packet in line.
 425 *
 426 * @api private
 427 */
 428
 429Manager.prototype.processPacketQueue = function() {
 430  if (this.packetBuffer.length > 0 && !this.encoding) {
 431    var pack = this.packetBuffer.shift();
 432    this.packet(pack);
 433  }
 434};
 435
 436/**
 437 * Clean up transport subscriptions and packet buffer.
 438 *
 439 * @api private
 440 */
 441
 442Manager.prototype.cleanup = function(){
 443  var sub;
 444  while (sub = this.subs.shift()) sub.destroy();
 445
 446  this.packetBuffer = [];
 447  this.encoding = false;
 448
 449  this.decoder.destroy();
 450};
 451
 452/**
 453 * Close the current socket.
 454 *
 455 * @api private
 456 */
 457
 458Manager.prototype.close =
 459Manager.prototype.disconnect = function(){
 460  this.skipReconnect = true;
 461  this.engine.close();
 462};
 463
 464/**
 465 * Called upon engine close.
 466 *
 467 * @api private
 468 */
 469
 470Manager.prototype.onclose = function(reason){
 471  debug('close');
 472  this.cleanup();
 473  this.readyState = 'closed';
 474  this.emit('close', reason);
 475  if (this._reconnection && !this.skipReconnect) {
 476    this.reconnect();
 477  }
 478};
 479
 480/**
 481 * Attempt a reconnection.
 482 *
 483 * @api private
 484 */
 485
 486Manager.prototype.reconnect = function(){
 487  if (this.reconnecting) return this;
 488
 489  var self = this;
 490  this.attempts++;
 491
 492  if (this.attempts > this._reconnectionAttempts) {
 493    debug('reconnect failed');
 494    this.emit('reconnect_failed');
 495    this.reconnecting = false;
 496  } else {
 497    var delay = this.attempts * this.reconnectionDelay();
 498    delay = Math.min(delay, this.reconnectionDelayMax());
 499    debug('will wait %dms before reconnect attempt', delay);
 500
 501    this.reconnecting = true;
 502    var timer = setTimeout(function(){
 503      debug('attempting reconnect');
 504      self.emit('reconnect_attempt');
 505      self.open(function(err){
 506        if (err) {
 507          debug('reconnect attempt error');
 508          self.reconnecting = false;
 509          self.reconnect();
 510          self.emit('reconnect_error', err.data);
 511        } else {
 512          debug('reconnect success');
 513          self.onreconnect();
 514        }
 515      });
 516    }, delay);
 517
 518    this.subs.push({
 519      destroy: function(){
 520        clearTimeout(timer);
 521      }
 522    });
 523  }
 524};
 525
 526/**
 527 * Called upon successful reconnect.
 528 *
 529 * @api private
 530 */
 531
 532Manager.prototype.onreconnect = function(){
 533  var attempt = this.attempts;
 534  this.attempts = 0;
 535  this.reconnecting = false;
 536  this.emit('reconnect', attempt);
 537};
 538
 539},{"./on":4,"./socket":5,"./url":6,"bind":7,"debug":8,"emitter":9,"engine.io-client":10,"object-component":36,"socket.io-parser":39}],4:[function(require,module,exports){
 540
 541/**
 542 * Module exports.
 543 */
 544
 545module.exports = on;
 546
 547/**
 548 * Helper for subscriptions.
 549 *
 550 * @param {Object|EventEmitter} obj with `Emitter` mixin or `EventEmitter`
 551 * @param {String} event name
 552 * @param {Function} callback
 553 * @api public
 554 */
 555
 556function on(obj, ev, fn) {
 557  obj.on(ev, fn);
 558  return {
 559    destroy: function(){
 560      obj.removeListener(ev, fn);
 561    }
 562  };
 563}
 564
 565},{}],5:[function(require,module,exports){
 566
 567/**
 568 * Module dependencies.
 569 */
 570
 571var parser = require('socket.io-parser');
 572var Emitter = require('emitter');
 573var toArray = require('to-array');
 574var on = require('./on');
 575var bind = require('bind');
 576var debug = require('debug')('socket.io-client:socket');
 577var hasBin = require('has-binary-data');
 578var indexOf = require('indexof');
 579
 580/**
 581 * Module exports.
 582 */
 583
 584module.exports = exports = Socket;
 585
 586/**
 587 * Internal events (blacklisted).
 588 * These events can't be emitted by the user.
 589 *
 590 * @api private
 591 */
 592
 593var events = {
 594  connect: 1,
 595  disconnect: 1,
 596  error: 1
 597};
 598
 599/**
 600 * Shortcut to `Emitter#emit`.
 601 */
 602
 603var emit = Emitter.prototype.emit;
 604
 605/**
 606 * `Socket` constructor.
 607 *
 608 * @api public
 609 */
 610
 611function Socket(io, nsp){
 612  this.io = io;
 613  this.nsp = nsp;
 614  this.json = this; // compat
 615  this.ids = 0;
 616  this.acks = {};
 617  this.open();
 618  this.buffer = [];
 619  this.connected = false;
 620  this.disconnected = true;
 621}
 622
 623/**
 624 * Mix in `Emitter`.
 625 */
 626
 627Emitter(Socket.prototype);
 628
 629/**
 630 * Called upon engine `open`.
 631 *
 632 * @api private
 633 */
 634
 635Socket.prototype.open =
 636Socket.prototype.connect = function(){
 637  if (this.connected) return this;
 638  var io = this.io;
 639  io.open(); // ensure open
 640  this.subs = [
 641    on(io, 'open', bind(this, 'onopen')),
 642    on(io, 'error', bind(this, 'onerror')),
 643    on(io, 'packet', bind(this, 'onpacket')),
 644    on(io, 'close', bind(this, 'onclose'))
 645  ];
 646  if ('open' == this.io.readyState) this.onopen();
 647  return this;
 648};
 649
 650/**
 651 * Sends a `message` event.
 652 *
 653 * @return {Socket} self
 654 * @api public
 655 */
 656
 657Socket.prototype.send = function(){
 658  var args = toArray(arguments);
 659  args.unshift('message');
 660  this.emit.apply(this, args);
 661  return this;
 662};
 663
 664/**
 665 * Override `emit`.
 666 * If the event is in `events`, it's emitted normally.
 667 *
 668 * @param {String} event name
 669 * @return {Socket} self
 670 * @api public
 671 */
 672
 673Socket.prototype.emit = function(ev){
 674  if (events.hasOwnProperty(ev)) {
 675    emit.apply(this, arguments);
 676    return this;
 677  }
 678
 679  var args = toArray(arguments);
 680  var parserType = parser.EVENT; // default
 681  if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary
 682  var packet = { type: parserType, data: args };
 683
 684  // event ack callback
 685  if ('function' == typeof args[args.length - 1]) {
 686    debug('emitting packet with ack id %d', this.ids);
 687    this.acks[this.ids] = args.pop();
 688    packet.id = this.ids++;
 689  }
 690
 691  this.packet(packet);
 692
 693  return this;
 694};
 695
 696/**
 697 * Sends a packet.
 698 *
 699 * @param {Object} packet
 700 * @api private
 701 */
 702
 703Socket.prototype.packet = function(packet){
 704  packet.nsp = this.nsp;
 705  this.io.packet(packet);
 706};
 707
 708/**
 709 * Called upon `error`.
 710 *
 711 * @param {Object} data
 712 * @api private
 713 */
 714
 715Socket.prototype.onerror = function(data){
 716  this.emit('error', data);
 717};
 718
 719/**
 720 * "Opens" the socket.
 721 *
 722 * @api private
 723 */
 724
 725Socket.prototype.onopen = function(){
 726  debug('transport is open - connecting');
 727
 728  // write connect packet if necessary
 729  if ('/' != this.nsp) {
 730    this.packet({ type: parser.CONNECT });
 731  }
 732};
 733
 734/**
 735 * Called upon engine `close`.
 736 *
 737 * @param {String} reason
 738 * @api private
 739 */
 740
 741Socket.prototype.onclose = function(reason){
 742  debug('close (%s)', reason);
 743  this.connected = false;
 744  this.disconnected = true;
 745  this.emit('disconnect', reason);
 746};
 747
 748/**
 749 * Called with socket packet.
 750 *
 751 * @param {Object} packet
 752 * @api private
 753 */
 754
 755Socket.prototype.onpacket = function(packet){
 756  if (packet.nsp != this.nsp) return;
 757
 758  switch (packet.type) {
 759    case parser.CONNECT:
 760      this.onconnect();
 761      break;
 762
 763    case parser.EVENT:
 764      this.onevent(packet);
 765      break;
 766
 767    case parser.BINARY_EVENT:
 768      this.onevent(packet);
 769      break;
 770
 771    case parser.ACK:
 772      this.onack(packet);
 773      break;
 774
 775    case parser.DISCONNECT:
 776      this.ondisconnect();
 777      break;
 778
 779    case parser.ERROR:
 780      this.emit('error', packet.data);
 781      break;
 782  }
 783};
 784
 785/**
 786 * Called upon a server event.
 787 *
 788 * @param {Object} packet
 789 * @api private
 790 */
 791
 792Socket.prototype.onevent = function(packet){
 793  var args = packet.data || [];
 794  debug('emitting event %j', args);
 795
 796  if (null != packet.id) {
 797    debug('attaching ack callback to event');
 798    args.push(this.ack(packet.id));
 799  }
 800
 801  if (this.connected) {
 802    emit.apply(this, args);
 803  } else {
 804    this.buffer.push(args);
 805  }
 806};
 807
 808/**
 809 * Produces an ack callback to emit with an event.
 810 *
 811 * @api private
 812 */
 813
 814Socket.prototype.ack = function(id){
 815  var self = this;
 816  var sent = false;
 817  return function(){
 818    // prevent double callbacks
 819    if (sent) return;
 820    sent = true;
 821    var args = toArray(arguments);
 822    debug('sending ack %j', args);
 823    self.packet({
 824      type: parser.ACK,
 825      id: id,
 826      data: args
 827    });
 828  };
 829};
 830
 831/**
 832 * Called upon a server acknowlegement.
 833 *
 834 * @param {Object} packet
 835 * @api private
 836 */
 837
 838Socket.prototype.onack = function(packet){
 839  debug('calling ack %s with %j', packet.id, packet.data);
 840  var fn = this.acks[packet.id];
 841  fn.apply(this, packet.data);
 842  delete this.acks[packet.id];
 843};
 844
 845/**
 846 * Called upon server connect.
 847 *
 848 * @api private
 849 */
 850
 851Socket.prototype.onconnect = function(){
 852  this.connected = true;
 853  this.disconnected = false;
 854  this.emit('connect');
 855  this.emitBuffered();
 856};
 857
 858/**
 859 * Emit buffered events.
 860 *
 861 * @api private
 862 */
 863
 864Socket.prototype.emitBuffered = function(){
 865  for (var i = 0; i < this.buffer.length; i++) {
 866    emit.apply(this, this.buffer[i]);
 867  }
 868  this.buffer = [];
 869};
 870
 871/**
 872 * Called upon server disconnect.
 873 *
 874 * @api private
 875 */
 876
 877Socket.prototype.ondisconnect = function(){
 878  debug('server disconnect (%s)', this.nsp);
 879  this.destroy();
 880  this.onclose('io server disconnect');
 881};
 882
 883/**
 884 * Called upon forced client/server side disconnections,
 885 * this method ensures the manager stops tracking us and
 886 * that reconnections don't get triggered for this.
 887 *
 888 * @api private.
 889 */
 890
 891Socket.prototype.destroy = function(){
 892  // clean subscriptions to avoid reconnections
 893  for (var i = 0; i < this.subs.length; i++) {
 894    this.subs[i].destroy();
 895  }
 896
 897  this.io.destroy(this);
 898};
 899
 900/**
 901 * Disconnects the socket manually.
 902 *
 903 * @return {Socket} self
 904 * @api public
 905 */
 906
 907Socket.prototype.close =
 908Socket.prototype.disconnect = function(){
 909  if (!this.connected) return this;
 910
 911  debug('performing disconnect (%s)', this.nsp);
 912  this.packet({ type: parser.DISCONNECT });
 913
 914  // remove socket from pool
 915  this.destroy();
 916
 917  // fire events
 918  this.onclose('io client disconnect');
 919  return this;
 920};
 921
 922},{"./on":4,"bind":7,"debug":8,"emitter":9,"has-binary-data":31,"indexof":35,"socket.io-parser":39,"to-array":42}],6:[function(require,module,exports){
 923var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
 924/**
 925 * Module dependencies.
 926 */
 927
 928var parseuri = require('parseuri');
 929var debug = require('debug')('socket.io-client:url');
 930
 931/**
 932 * Module exports.
 933 */
 934
 935module.exports = url;
 936
 937/**
 938 * URL parser.
 939 *
 940 * @param {String} url
 941 * @param {Object} An object meant to mimic window.location.
 942 *                 Defaults to window.location.
 943 * @api public
 944 */
 945
 946function url(uri, loc){
 947  var obj = uri;
 948
 949  // default to window.location
 950  var loc = loc || global.location;
 951  if (null == uri) uri = loc.protocol + '//' + loc.hostname;
 952
 953  // relative path support
 954  if ('string' == typeof uri) {
 955    if ('/' == uri.charAt(0)) {
 956      if ('undefined' != typeof loc) {
 957        uri = loc.hostname + uri;
 958      }
 959    }
 960
 961    if (!/^(https?|wss?):\/\//.test(uri)) {
 962      debug('protocol-less url %s', uri);
 963      if ('undefined' != typeof loc) {
 964        uri = loc.protocol + '//' + uri;
 965      } else {
 966        uri = 'https://' + uri;
 967      }
 968    }
 969
 970    // parse
 971    debug('parse %s', uri);
 972    obj = parseuri(uri);
 973  }
 974
 975  // make sure we treat `localhost:80` and `localhost` equally
 976  if ((/(http|ws)/.test(obj.protocol) && 80 == obj.port) ||
 977     (/(http|ws)s/.test(obj.protocol) && 443 == obj.port)) {
 978    delete obj.port;
 979  }
 980
 981  obj.path = obj.path || '/';
 982
 983  // define unique id
 984  obj.id = obj.protocol + obj.host + (obj.port ? (':' + obj.port) : '');
 985
 986  // define href
 987  obj.href = obj.protocol + '://' + obj.host + (obj.port ? (':' + obj.port) : '');
 988
 989  return obj;
 990}
 991
 992},{"debug":8,"parseuri":37}],7:[function(require,module,exports){
 993
 994/**
 995 * Slice reference.
 996 */
 997
 998var slice = [].slice;
 999
1000/**
1001 * Bind `obj` to `fn`.
1002 *
1003 * @param {Object} obj
1004 * @param {Function|String} fn or string
1005 * @return {Function}
1006 * @api public
1007 */
1008
1009module.exports = function(obj, fn){
1010  if ('string' == typeof fn) fn = obj[fn];
1011  if ('function' != typeof fn) throw new Error('bind() requires a function');
1012  var args = [].slice.call(arguments, 2);
1013  return function(){
1014    return fn.apply(obj, args.concat(slice.call(arguments)));
1015  }
1016};
1017
1018},{}],8:[function(require,module,exports){
1019
1020/**
1021 * Expose `debug()` as the module.
1022 */
1023
1024module.exports = debug;
1025
1026/**
1027 * Create a debugger with the given `name`.
1028 *
1029 * @param {String} name
1030 * @return {Type}
1031 * @api public
1032 */
1033
1034function debug(name) {
1035  if (!debug.enabled(name)) return function(){};
1036
1037  return function(fmt){
1038    fmt = coerce(fmt);
1039
1040    var curr = new Date;
1041    var ms = curr - (debug[name] || curr);
1042    debug[name] = curr;
1043
1044    fmt = name
1045      + ' '
1046      + fmt
1047      + ' +' + debug.humanize(ms);
1048
1049    // This hackery is required for IE8
1050    // where `console.log` doesn't have 'apply'
1051    window.console
1052      && console.log
1053      && Function.prototype.apply.call(console.log, console, arguments);
1054  }
1055}
1056
1057/**
1058 * The currently active debug mode names.
1059 */
1060
1061debug.names = [];
1062debug.skips = [];
1063
1064/**
1065 * Enables a debug mode by name. This can include modes
1066 * separated by a colon and wildcards.
1067 *
1068 * @param {String} name
1069 * @api public
1070 */
1071
1072debug.enable = function(name) {
1073  try {
1074    localStorage.debug = name;
1075  } catch(e){}
1076
1077  var split = (name || '').split(/[\s,]+/)
1078    , len = split.length;
1079
1080  for (var i = 0; i < len; i++) {
1081    name = split[i].replace('*', '.*?');
1082    if (name[0] === '-') {
1083      debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
1084    }
1085    else {
1086      debug.names.push(new RegExp('^' + name + '$'));
1087    }
1088  }
1089};
1090
1091/**
1092 * Disable debug output.
1093 *
1094 * @api public
1095 */
1096
1097debug.disable = function(){
1098  debug.enable('');
1099};
1100
1101/**
1102 * Humanize the given `ms`.
1103 *
1104 * @param {Number} m
1105 * @return {String}
1106 * @api private
1107 */
1108
1109debug.humanize = function(ms) {
1110  var sec = 1000
1111    , min = 60 * 1000
1112    , hour = 60 * min;
1113
1114  if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
1115  if (ms >= min) return (ms / min).toFixed(1) + 'm';
1116  if (ms >= sec) return (ms / sec | 0) + 's';
1117  return ms + 'ms';
1118};
1119
1120/**
1121 * Returns true if the given mode name is enabled, false otherwise.
1122 *
1123 * @param {String} name
1124 * @return {Boolean}
1125 * @api public
1126 */
1127
1128debug.enabled = function(name) {
1129  for (var i = 0, len = debug.skips.length; i < len; i++) {
1130    if (debug.skips[i].test(name)) {
1131      return false;
1132    }
1133  }
1134  for (var i = 0, len = debug.names.length; i < len; i++) {
1135    if (debug.names[i].test(name)) {
1136      return true;
1137    }
1138  }
1139  return false;
1140};
1141
1142/**
1143 * Coerce `val`.
1144 */
1145
1146function coerce(val) {
1147  if (val instanceof Error) return val.stack || val.message;
1148  return val;
1149}
1150
1151// persist
1152
1153try {
1154  if (window.localStorage) debug.enable(localStorage.debug);
1155} catch(e){}
1156
1157},{}],9:[function(require,module,exports){
1158
1159/**
1160 * Module dependencies.
1161 */
1162
1163var index = require('indexof');
1164
1165/**
1166 * Expose `Emitter`.
1167 */
1168
1169module.exports = Emitter;
1170
1171/**
1172 * Initialize a new `Emitter`.
1173 *
1174 * @api public
1175 */
1176
1177function Emitter(obj) {
1178  if (obj) return mixin(obj);
1179};
1180
1181/**
1182 * Mixin the emitter properties.
1183 *
1184 * @param {Object} obj
1185 * @return {Object}
1186 * @api private
1187 */
1188
1189function mixin(obj) {
1190  for (var key in Emitter.prototype) {
1191    obj[key] = Emitter.prototype[key];
1192  }
1193  return obj;
1194}
1195
1196/**
1197 * Listen on the given `event` with `fn`.
1198 *
1199 * @param {String} event
1200 * @param {Function} fn
1201 * @return {Emitter}
1202 * @api public
1203 */
1204
1205Emitter.prototype.on = function(event, fn){
1206  this._callbacks = this._callbacks || {};
1207  (this._callbacks[event] = this._callbacks[event] || [])
1208    .push(fn);
1209  return this;
1210};
1211
1212/**
1213 * Adds an `event` listener that will be invoked a single
1214 * time then automatically removed.
1215 *
1216 * @param {String} event
1217 * @param {Function} fn
1218 * @return {Emitter}
1219 * @api public
1220 */
1221
1222Emitter.prototype.once = function(event, fn){
1223  var self = this;
1224  this._callbacks = this._callbacks || {};
1225
1226  function on() {
1227    self.off(event, on);
1228    fn.apply(this, arguments);
1229  }
1230
1231  fn._off = on;
1232  this.on(event, on);
1233  return this;
1234};
1235
1236/**
1237 * Remove the given callback for `event` or all
1238 * registered callbacks.
1239 *
1240 * @param {String} event
1241 * @param {Function} fn
1242 * @return {Emitter}
1243 * @api public
1244 */
1245
1246Emitter.prototype.off =
1247Emitter.prototype.removeListener =
1248Emitter.prototype.removeAllListeners = function(event, fn){
1249  this._callbacks = this._callbacks || {};
1250
1251  // all
1252  if (0 == arguments.length) {
1253    this._callbacks = {};
1254    return this;
1255  }
1256
1257  // specific event
1258  var callbacks = this._callbacks[event];
1259  if (!callbacks) return this;
1260
1261  // remove all handlers
1262  if (1 == arguments.length) {
1263    delete this._callbacks[event];
1264    return this;
1265  }
1266
1267  // remove specific handler
1268  var i = index(callbacks, fn._off || fn);
1269  if (~i) callbacks.splice(i, 1);
1270  return this;
1271};
1272
1273/**
1274 * Emit `event` with the given args.
1275 *
1276 * @param {String} event
1277 * @param {Mixed} ...
1278 * @return {Emitter}
1279 */
1280
1281Emitter.prototype.emit = function(event){
1282  this._callbacks = this._callbacks || {};
1283  var args = [].slice.call(arguments, 1)
1284    , callbacks = this._callbacks[event];
1285
1286  if (callbacks) {
1287    callbacks = callbacks.slice(0);
1288    for (var i = 0, len = callbacks.length; i < len; ++i) {
1289      callbacks[i].apply(this, args);
1290    }
1291  }
1292
1293  return this;
1294};
1295
1296/**
1297 * Return array of callbacks for `event`.
1298 *
1299 * @param {String} event
1300 * @return {Array}
1301 * @api public
1302 */
1303
1304Emitter.prototype.listeners = function(event){
1305  this._callbacks = this._callbacks || {};
1306  return this._callbacks[event] || [];
1307};
1308
1309/**
1310 * Check if this emitter has `event` handlers.
1311 *
1312 * @param {String} event
1313 * @return {Boolean}
1314 * @api public
1315 */
1316
1317Emitter.prototype.hasListeners = function(event){
1318  return !! this.listeners(event).length;
1319};
1320
1321},{"indexof":35}],10:[function(require,module,exports){
1322
1323module.exports =  require('./lib/');
1324
1325},{"./lib/":11}],11:[function(require,module,exports){
1326
1327module.exports = require('./socket');
1328
1329/**
1330 * Exports parser
1331 *
1332 * @api public
1333 *
1334 */
1335module.exports.parser = require('engine.io-parser');
1336
1337},{"./socket":12,"engine.io-parser":20}],12:[function(require,module,exports){
1338var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
1339 * Module dependencies.
1340 */
1341
1342var transports = require('./transports');
1343var Emitter = require('emitter');
1344var debug = require('debug')('engine.io-client:socket');
1345var index = require('indexof');
1346var parser = require('engine.io-parser');
1347var parseuri = require('parseuri');
1348var parsejson = require('parsejson');
1349var parseqs = require('parseqs');
1350
1351/**
1352 * Module exports.
1353 */
1354
1355module.exports = Socket;
1356
1357/**
1358 * Noop function.
1359 *
1360 * @api private
1361 */
1362
1363function noop(){}
1364
1365/**
1366 * Socket constructor.
1367 *
1368 * @param {String|Object} uri or options
1369 * @param {Object} options
1370 * @api public
1371 */
1372
1373function Socket(uri, opts){
1374  if (!(this instanceof Socket)) return new Socket(uri, opts);
1375
1376  opts = opts || {};
1377
1378  if (uri && 'object' == typeof uri) {
1379    opts = uri;
1380    uri = null;
1381  }
1382
1383  if (uri) {
1384    uri = parseuri(uri);
1385    opts.host = uri.host;
1386    opts.secure = uri.protocol == 'https' || uri.protocol == 'wss';
1387    opts.port = uri.port;
1388    if (uri.query) opts.query = uri.query;
1389  }
1390
1391  this.secure = null != opts.secure ? opts.secure :
1392    (global.location && 'https:' == location.protocol);
1393
1394  if (opts.host) {
1395    var pieces = opts.host.split(':');
1396    opts.hostname = pieces.shift();
1397    if (pieces.length) opts.port = pieces.pop();
1398  }
1399
1400  this.agent = opts.agent || false;
1401  this.hostname = opts.hostname ||
1402    (global.location ? location.hostname : 'localhost');
1403  this.port = opts.port || (global.location && location.port ?
1404       location.port :
1405       (this.secure ? 443 : 80));
1406  this.query = opts.query || {};
1407  if ('string' == typeof this.query) this.query = parseqs.decode(this.query);
1408  this.upgrade = false !== opts.upgrade;
1409  this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/';
1410  this.forceJSONP = !!opts.forceJSONP;
1411  this.forceBase64 = !!opts.forceBase64;
1412  this.timestampParam = opts.timestampParam || 't';
1413  this.timestampRequests = opts.timestampRequests;
1414  this.transports = opts.transports || ['polling', 'websocket'];
1415  this.readyState = '';
1416  this.writeBuffer = [];
1417  this.callbackBuffer = [];
1418  this.policyPort = opts.policyPort || 843;
1419  this.rememberUpgrade = opts.rememberUpgrade || false;
1420  this.open();
1421  this.binaryType = null;
1422  this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades;
1423}
1424
1425Socket.priorWebsocketSuccess = false;
1426
1427/**
1428 * Mix in `Emitter`.
1429 */
1430
1431Emitter(Socket.prototype);
1432
1433/**
1434 * Protocol version.
1435 *
1436 * @api public
1437 */
1438
1439Socket.protocol = parser.protocol; // this is an int
1440
1441/**
1442 * Expose deps for legacy compatibility
1443 * and standalone browser access.
1444 */
1445
1446Socket.Socket = Socket;
1447Socket.Transport = require('./transport');
1448Socket.transports = require('./transports');
1449Socket.parser = require('engine.io-parser');
1450
1451/**
1452 * Creates transport of the given type.
1453 *
1454 * @param {String} transport name
1455 * @return {Transport}
1456 * @api private
1457 */
1458
1459Socket.prototype.createTransport = function (name) {
1460  debug('creating transport "%s"', name);
1461  var query = clone(this.query);
1462
1463  // append engine.io protocol identifier
1464  query.EIO = parser.protocol;
1465
1466  // transport name
1467  query.transport = name;
1468
1469  // session id if we already have one
1470  if (this.id) query.sid = this.id;
1471
1472  var transport = new transports[name]({
1473    agent: this.agent,
1474    hostname: this.hostname,
1475    port: this.port,
1476    secure: this.secure,
1477    path: this.path,
1478    query: query,
1479    forceJSONP: this.forceJSONP,
1480    forceBase64: this.forceBase64,
1481    timestampRequests: this.timestampRequests,
1482    timestampParam: this.timestampParam,
1483    policyPort: this.policyPort,
1484    socket: this
1485  });
1486
1487  return transport;
1488};
1489
1490function clone (obj) {
1491  var o = {};
1492  for (var i in obj) {
1493    if (obj.hasOwnProperty(i)) {
1494      o[i] = obj[i];
1495    }
1496  }
1497  return o;
1498}
1499
1500/**
1501 * Initializes transport to use and starts probe.
1502 *
1503 * @api private
1504 */
1505Socket.prototype.open = function () {
1506  var transport;
1507  if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') != -1) {
1508    transport = 'websocket';
1509  } else {
1510    transport = this.transports[0];
1511  }
1512  this.readyState = 'opening';
1513  var transport = this.createTransport(transport);
1514  transport.open();
1515  this.setTransport(transport);
1516};
1517
1518/**
1519 * Sets the current transport. Disables the existing one (if any).
1520 *
1521 * @api private
1522 */
1523
1524Socket.prototype.setTransport = function(transport){
1525  debug('setting transport %s', transport.name);
1526  var self = this;
1527
1528  if (this.transport) {
1529    debug('clearing existing transport %s', this.transport.name);
1530    this.transport.removeAllListeners();
1531  }
1532
1533  // set up transport
1534  this.transport = transport;
1535
1536  // set up transport listeners
1537  transport
1538  .on('drain', function(){
1539    self.onDrain();
1540  })
1541  .on('packet', function(packet){
1542    self.onPacket(packet);
1543  })
1544  .on('error', function(e){
1545    self.onError(e);
1546  })
1547  .on('close', function(){
1548    self.onClose('transport close');
1549  });
1550};
1551
1552/**
1553 * Probes a transport.
1554 *
1555 * @param {String} transport name
1556 * @api private
1557 */
1558
1559Socket.prototype.probe = function (name) {
1560  debug('probing transport "%s"', name);
1561  var transport = this.createTransport(name, { probe: 1 })
1562    , failed = false
1563    , self = this;
1564
1565  Socket.priorWebsocketSuccess = false;
1566
1567  function onTransportOpen(){
1568    if (self.onlyBinaryUpgrades) {
1569      var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary;
1570      failed = failed || upgradeLosesBinary;
1571    }
1572    if (failed) return;
1573
1574    debug('probe transport "%s" opened', name);
1575    transport.send([{ type: 'ping', data: 'probe' }]);
1576    transport.once('packet', function (msg) {
1577      if (failed) return;
1578      if ('pong' == msg.type && 'probe' == msg.data) {
1579        debug('probe transport "%s" pong', name);
1580        self.upgrading = true;
1581        self.emit('upgrading', transport);
1582        Socket.priorWebsocketSuccess = 'websocket' == transport.name;
1583
1584        debug('pausing current transport "%s"', self.transport.name);
1585        self.transport.pause(function () {
1586          if (failed) return;
1587          if ('closed' == self.readyState || 'closing' == self.readyState) {
1588            return;
1589          }
1590          debug('changing transport and sending upgrade packet');
1591
1592          cleanup();
1593
1594          self.setTransport(transport);
1595          transport.send([{ type: 'upgrade' }]);
1596          self.emit('upgrade', transport);
1597          transport = null;
1598          self.upgrading = false;
1599          self.flush();
1600        });
1601      } else {
1602        debug('probe transport "%s" failed', name);
1603        var err = new Error('probe error');
1604        err.transport = transport.name;
1605        self.emit('upgradeError', err);
1606      }
1607    });
1608  }
1609
1610  function freezeTransport() {
1611    if (failed) return;
1612
1613    // Any callback called by transport should be ignored since now
1614    failed = true;
1615
1616    cleanup();
1617
1618    transport.close();
1619    transport = null;
1620  }
1621
1622  //Handle any error that happens while probing
1623  function onerror(err) {
1624    var error = new Error('probe error: ' + err);
1625    error.transport = transport.name;
1626
1627    freezeTransport();
1628
1629    debug('probe transport "%s" failed because of error: %s', name, err);
1630
1631    self.emit('upgradeError', error);
1632  }
1633
1634  function onTransportClose(){
1635    onerror("transport closed");
1636  }
1637
1638  //When the socket is closed while we're probing
1639  function onclose(){
1640    onerror("socket closed");
1641  }
1642
1643  //When the socket is upgraded while we're probing
1644  function onupgrade(to){
1645    if (transport && to.name != transport.name) {
1646      debug('"%s" works - aborting "%s"', to.name, transport.name);
1647      freezeTransport();
1648    }
1649  }
1650
1651  //Remove all listeners on the transport and on self
1652  function cleanup(){
1653    transport.removeListener('open', onTransportOpen);
1654    transport.removeListener('error', onerror);
1655    transport.removeListener('close', onTransportClose);
1656    self.removeListener('close', onclose);
1657    self.removeListener('upgrading', onupgrade);
1658  }
1659
1660  transport.once('open', onTransportOpen);
1661  transport.once('error', onerror);
1662  transport.once('close', onTransportClose);
1663
1664  this.once('close', onclose);
1665  this.once('upgrading', onupgrade);
1666
1667  transport.open();
1668
1669};
1670
1671/**
1672 * Called when connection is deemed open.
1673 *
1674 * @api public
1675 */
1676
1677Socket.prototype.onOpen = function () {
1678  debug('socket open');
1679  this.readyState = 'open';
1680  Socket.priorWebsocketSuccess = 'websocket' == this.transport.name;
1681  this.emit('open');
1682  this.flush();
1683
1684  // we check for `readyState` in case an `open`
1685  // listener already closed the socket
1686  if ('open' == this.readyState && this.upgrade && this.transport.pause) {
1687    debug('starting upgrade probes');
1688    for (var i = 0, l = this.upgrades.length; i < l; i++) {
1689      this.probe(this.upgrades[i]);
1690    }
1691  }
1692};
1693
1694/**
1695 * Handles a packet.
1696 *
1697 * @api private
1698 */
1699
1700Socket.prototype.onPacket = function (packet) {
1701  if ('opening' == this.readyState || 'open' == this.readyState) {
1702    debug('socket receive: type "%s", data "%s"', packet.type, packet.data);
1703
1704    this.emit('packet', packet);
1705
1706    // Socket is live - any packet counts
1707    this.emit('heartbeat');
1708
1709    switch (packet.type) {
1710      case 'open':
1711        this.onHandshake(parsejson(packet.data));
1712        break;
1713
1714      case 'pong':
1715        this.setPing();
1716        break;
1717
1718      case 'error':
1719        var err = new Error('server error');
1720        err.code = packet.data;
1721        this.emit('error', err);
1722        break;
1723
1724      case 'message':
1725        this.emit('data', packet.data);
1726        this.emit('message', packet.data);
1727        break;
1728    }
1729  } else {
1730    debug('packet received with socket readyState "%s"', this.readyState);
1731  }
1732};
1733
1734/**
1735 * Called upon handshake completion.
1736 *
1737 * @param {Object} handshake obj
1738 * @api private
1739 */
1740
1741Socket.prototype.onHandshake = function (data) {
1742  this.emit('handshake', data);
1743  this.id = data.sid;
1744  this.transport.query.sid = data.sid;
1745  this.upgrades = this.filterUpgrades(data.upgrades);
1746  this.pingInterval = data.pingInterval;
1747  this.pingTimeout = data.pingTimeout;
1748  this.onOpen();
1749  // In case open handler closes socket
1750  if  ('closed' == this.readyState) return;
1751  this.setPing();
1752
1753  // Prolong liveness of socket on heartbeat
1754  this.removeListener('heartbeat', this.onHeartbeat);
1755  this.on('heartbeat', this.onHeartbeat);
1756};
1757
1758/**
1759 * Resets ping timeout.
1760 *
1761 * @api private
1762 */
1763
1764Socket.prototype.onHeartbeat = function (timeout) {
1765  clearTimeout(this.pingTimeoutTimer);
1766  var self = this;
1767  self.pingTimeoutTimer = setTimeout(function () {
1768    if ('closed' == self.readyState) return;
1769    self.onClose('ping timeout');
1770  }, timeout || (self.pingInterval + self.pingTimeout));
1771};
1772
1773/**
1774 * Pings server every `this.pingInterval` and expects response
1775 * within `this.pingTimeout` or closes connection.
1776 *
1777 * @api private
1778 */
1779
1780Socket.prototype.setPing = function () {
1781  var self = this;
1782  clearTimeout(self.pingIntervalTimer);
1783  self.pingIntervalTimer = setTimeout(function () {
1784    debug('writing ping packet - expecting pong within %sms', self.pingTimeout);
1785    self.ping();
1786    self.onHeartbeat(self.pingTimeout);
1787  }, self.pingInterval);
1788};
1789
1790/**
1791* Sends a ping packet.
1792*
1793* @api public
1794*/
1795
1796Socket.prototype.ping = function () {
1797  this.sendPacket('ping');
1798};
1799
1800/**
1801 * Called on `drain` event
1802 *
1803 * @api private
1804 */
1805
1806Socket.prototype.onDrain = function() {
1807  for (var i = 0; i < this.prevBufferLen; i++) {
1808    if (this.callbackBuffer[i]) {
1809      this.callbackBuffer[i]();
1810    }
1811  }
1812
1813  this.writeBuffer.splice(0, this.prevBufferLen);
1814  this.callbackBuffer.splice(0, this.prevBufferLen);
1815
1816  // setting prevBufferLen = 0 is very important
1817  // for example, when upgrading, upgrade packet is sent over,
1818  // and a nonzero prevBufferLen could cause problems on `drain`
1819  this.prevBufferLen = 0;
1820
1821  if (this.writeBuffer.length == 0) {
1822    this.emit('drain');
1823  } else {
1824    this.flush();
1825  }
1826};
1827
1828/**
1829 * Flush write buffers.
1830 *
1831 * @api private
1832 */
1833
1834Socket.prototype.flush = function () {
1835  if ('closed' != this.readyState && this.transport.writable &&
1836    !this.upgrading && this.writeBuffer.length) {
1837    debug('flushing %d packets in socket', this.writeBuffer.length);
1838    this.transport.send(this.writeBuffer);
1839    // keep track of current length of writeBuffer
1840    // splice writeBuffer and callbackBuffer on `drain`
1841    this.prevBufferLen = this.writeBuffer.length;
1842    this.emit('flush');
1843  }
1844};
1845
1846/**
1847 * Sends a message.
1848 *
1849 * @param {String} message.
1850 * @param {Function} callback function.
1851 * @return {Socket} for chaining.
1852 * @api public
1853 */
1854
1855Socket.prototype.write =
1856Socket.prototype.send = function (msg, fn) {
1857  this.sendPacket('message', msg, fn);
1858  return this;
1859};
1860
1861/**
1862 * Sends a packet.
1863 *
1864 * @param {String} packet type.
1865 * @param {String} data.
1866 * @param {Function} callback function.
1867 * @api private
1868 */
1869
1870Socket.prototype.sendPacket = function (type, data, fn) {
1871  var packet = { type: type, data: data };
1872  this.emit('packetCreate', packet);
1873  this.writeBuffer.push(packet);
1874  this.callbackBuffer.push(fn);
1875  this.flush();
1876};
1877
1878/**
1879 * Closes the connection.
1880 *
1881 * @api private
1882 */
1883
1884Socket.prototype.close = function () {
1885  if ('opening' == this.readyState || 'open' == this.readyState) {
1886    this.onClose('forced close');
1887    debug('socket closing - telling transport to close');
1888    this.transport.close();
1889  }
1890
1891  return this;
1892};
1893
1894/**
1895 * Called upon transport error
1896 *
1897 * @api private
1898 */
1899
1900Socket.prototype.onError = function (err) {
1901  debug('socket error %j', err);
1902  Socket.priorWebsocketSuccess = false;
1903  this.emit('error', err);
1904  this.onClose('transport error', err);
1905};
1906
1907/**
1908 * Called upon transport close.
1909 *
1910 * @api private
1911 */
1912
1913Socket.prototype.onClose = function (reason, desc) {
1914  if ('opening' == this.readyState || 'open' == this.readyState) {
1915    debug('socket close with reason: "%s"', reason);
1916    var self = this;
1917
1918    // clear timers
1919    clearTimeout(this.pingIntervalTimer);
1920    clearTimeout(this.pingTimeoutTimer);
1921
1922    // clean buffers in next tick, so developers can still
1923    // grab the buffers on `close` event
1924    setTimeout(function() {
1925      self.writeBuffer = [];
1926      self.callbackBuffer = [];
1927      self.prevBufferLen = 0;
1928    }, 0);
1929
1930    // stop event from firing again for transport
1931    this.transport.removeAllListeners('close');
1932
1933    // ensure transport won't stay open
1934    this.transport.close();
1935
1936    // ignore further transport communication
1937    this.transport.removeAllListeners();
1938
1939    // set ready state
1940    this.readyState = 'closed';
1941
1942    // clear session id
1943    this.id = null;
1944
1945    // emit close event
1946    this.emit('close', reason, desc);
1947  }
1948};
1949
1950/**
1951 * Filters upgrades, returning only those matching client transports.
1952 *
1953 * @param {Array} server upgrades
1954 * @api private
1955 *
1956 */
1957
1958Socket.prototype.filterUpgrades = function (upgrades) {
1959  var filteredUpgrades = [];
1960  for (var i = 0, j = upgrades.length; i<j; i++) {
1961    if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]);
1962  }
1963  return filteredUpgrades;
1964};
1965
1966},{"./transport":13,"./transports":14,"debug":8,"emitter":9,"engine.io-parser":20,"indexof":35,"parsejson":28,"parseqs":29,"parseuri":37}],13:[function(require,module,exports){
1967/**
1968 * Module dependencies.
1969 */
1970
1971var parser = require('engine.io-parser');
1972var Emitter = require('emitter');
1973
1974/**
1975 * Module exports.
1976 */
1977
1978module.exports = Transport;
1979
1980/**
1981 * Transport abstract constructor.
1982 *
1983 * @param {Object} options.
1984 * @api private
1985 */
1986
1987function Transport (opts) {
1988  this.path = opts.path;
1989  this.hostname = opts.hostname;
1990  this.port = opts.port;
1991  this.secure = opts.secure;
1992  this.query = opts.query;
1993  this.timestampParam = opts.timestampParam;
1994  this.timestampRequests = opts.timestampRequests;
1995  this.readyState = '';
1996  this.agent = opts.agent || false;
1997  this.socket = opts.socket;
1998}
1999
2000/**
2001 * Mix in `Emitter`.
2002 */
2003
2004Emitter(Transport.prototype);
2005
2006/**
2007 * A counter used to prevent collisions in the timestamps used
2008 * for cache busting.
2009 */
2010
2011Transport.timestamps = 0;
2012
2013/**
2014 * Emits an error.
2015 *
2016 * @param {String} str
2017 * @return {Transport} for chaining
2018 * @api public
2019 */
2020
2021Transport.prototype.onError = function (msg, desc) {
2022  var err = new Error(msg);
2023  err.type = 'TransportError';
2024  err.description = desc;
2025  this.emit('error', err);
2026  return this;
2027};
2028
2029/**
2030 * Opens the transport.
2031 *
2032 * @api public
2033 */
2034
2035Transport.prototype.open = function () {
2036  if ('closed' == this.readyState || '' == this.readyState) {
2037    this.readyState = 'opening';
2038    this.doOpen();
2039  }
2040
2041  return this;
2042};
2043
2044/**
2045 * Closes the transport.
2046 *
2047 * @api private
2048 */
2049
2050Transport.prototype.close = function () {
2051  if ('opening' == this.readyState || 'open' == this.readyState) {
2052    this.doClose();
2053    this.onClose();
2054  }
2055
2056  return this;
2057};
2058
2059/**
2060 * Sends multiple packets.
2061 *
2062 * @param {Array} packets
2063 * @api private
2064 */
2065
2066Transport.prototype.send = function(packets){
2067  if ('open' == this.readyState) {
2068    this.write(packets);
2069  } else {
2070    throw new Error('Transport not open');
2071  }
2072};
2073
2074/**
2075 * Called upon open
2076 *
2077 * @api private
2078 */
2079
2080Transport.prototype.onOpen = function () {
2081  this.readyState = 'open';
2082  this.writable = true;
2083  this.emit('open');
2084};
2085
2086/**
2087 * Called with data.
2088 *
2089 * @param {String} data
2090 * @api private
2091 */
2092
2093Transport.prototype.onData = function (data) {
2094  this.onPacket(parser.decodePacket(data, this.socket.binaryType));
2095};
2096
2097/**
2098 * Called with a decoded packet.
2099 */
2100
2101Transport.prototype.onPacket = function (packet) {
2102  this.emit('packet', packet);
2103};
2104
2105/**
2106 * Called upon close.
2107 *
2108 * @api private
2109 */
2110
2111Transport.prototype.onClose = function () {
2112  this.readyState = 'closed';
2113  this.emit('close');
2114};
2115
2116},{"emitter":9,"engine.io-parser":20}],14:[function(require,module,exports){
2117var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
2118 * Module dependencies
2119 */
2120
2121var XMLHttpRequest = require('xmlhttprequest');
2122var XHR = require('./polling-xhr');
2123var JSONP = require('./polling-jsonp');
2124var websocket = require('./websocket');
2125
2126/**
2127 * Export transports.
2128 */
2129
2130exports.polling = polling;
2131exports.websocket = websocket;
2132
2133/**
2134 * Polling transport polymorphic constructor.
2135 * Decides on xhr vs jsonp based on feature detection.
2136 *
2137 * @api private
2138 */
2139
2140function polling(opts){
2141  var xhr;
2142  var xd = false;
2143
2144  if (global.location) {
2145    var isSSL = 'https:' == location.protocol;
2146    var port = location.port;
2147
2148    // some user agents have empty `location.port`
2149    if (!port) {
2150      port = isSSL ? 443 : 80;
2151    }
2152
2153    xd = opts.hostname != location.hostname || port != opts.port;
2154  }
2155
2156  opts.xdomain = xd;
2157  xhr = new XMLHttpRequest(opts);
2158
2159  if ('open' in xhr && !opts.forceJSONP) {
2160    return new XHR(opts);
2161  } else {
2162    return new JSONP(opts);
2163  }
2164}
2165
2166},{"./polling-jsonp":15,"./polling-xhr":16,"./websocket":18,"xmlhttprequest":19}],15:[function(require,module,exports){
2167var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
2168/**
2169 * Module requirements.
2170 */
2171
2172var Polling = require('./polling');
2173var inherit = require('inherits');
2174
2175/**
2176 * Module exports.
2177 */
2178
2179module.exports = JSONPPolling;
2180
2181/**
2182 * Cached regular expressions.
2183 */
2184
2185var rNewline = /\n/g;
2186var rEscapedNewline = /\\n/g;
2187
2188/**
2189 * Global JSONP callbacks.
2190 */
2191
2192var callbacks;
2193
2194/**
2195 * Callbacks count.
2196 */
2197
2198var index = 0;
2199
2200/**
2201 * Noop.
2202 */
2203
2204function empty () { }
2205
2206/**
2207 * JSONP Polling constructor.
2208 *
2209 * @param {Object} opts.
2210 * @api public
2211 */
2212
2213function JSONPPolling (opts) {
2214  Polling.call(this, opts);
2215
2216  this.query = this.query || {};
2217
2218  // define global callbacks array if not present
2219  // we do this here (lazily) to avoid unneeded global pollution
2220  if (!callbacks) {
2221    // we need to consider multiple engines in the same page
2222    if (!global.___eio) global.___eio = [];
2223    callbacks = global.___eio;
2224  }
2225
2226  // callback identifier
2227  this.index = callbacks.length;
2228
2229  // add callback to jsonp global
2230  var self = this;
2231  callbacks.push(function (msg) {
2232    self.onData(msg);
2233  });
2234
2235  // append to query string
2236  this.query.j = this.index;
2237
2238  // prevent spurious errors from being emitted when the window is unloaded
2239  if (global.document && global.addEventListener) {
2240    global.addEventListener('beforeunload', function () {
2241      if (self.script) self.script.onerror = empty;
2242    });
2243  }
2244}
2245
2246/**
2247 * Inherits from Polling.
2248 */
2249
2250inherit(JSONPPolling, Polling);
2251
2252/*
2253 * JSONP only supports binary as base64 encoded strings
2254 */
2255
2256JSONPPolling.prototype.supportsBinary = false;
2257
2258/**
2259 * Closes the socket.
2260 *
2261 * @api private
2262 */
2263
2264JSONPPolling.prototype.doClose = function () {
2265  if (this.script) {
2266    this.script.parentNode.removeChild(this.script);
2267    this.script = null;
2268  }
2269
2270  if (this.form) {
2271    this.form.parentNode.removeChild(this.form);
2272    this.form = null;
2273  }
2274
2275  Polling.prototype.doClose.call(this);
2276};
2277
2278/**
2279 * Starts a poll cycle.
2280 *
2281 * @api private
2282 */
2283
2284JSONPPolling.prototype.doPoll = function () {
2285  var self = this;
2286  var script = document.createElement('script');
2287
2288  if (this.script) {
2289    this.script.parentNode.removeChild(this.script);
2290    this.script = null;
2291  }
2292
2293  script.async = true;
2294  script.src = this.uri();
2295  script.onerror = function(e){
2296    self.onError('jsonp poll error',e);
2297  };
2298
2299  var insertAt = document.getElementsByTagName('script')[0];
2300  insertAt.parentNode.insertBefore(script, insertAt);
2301  this.script = script;
2302
2303  var isUAgecko = 'undefined' != typeof navigator && /gecko/i.test(navigator.userAgent);
2304  
2305  if (isUAgecko) {
2306    setTimeout(function () {
2307      var iframe = document.createElement('iframe');
2308      document.body.appendChild(iframe);
2309      document.body.removeChild(iframe);
2310    }, 100);
2311  }
2312};
2313
2314/**
2315 * Writes with a hidden iframe.
2316 *
2317 * @param {String} data to send
2318 * @param {Function} called upon flush.
2319 * @api private
2320 */
2321
2322JSONPPolling.prototype.doWrite = function (data, fn) {
2323  var self = this;
2324
2325  if (!this.form) {
2326    var form = document.createElement('form');
2327    var area = document.createElement('textarea');
2328    var id = this.iframeId = 'eio_iframe_' + this.index;
2329    var iframe;
2330
2331    form.className = 'socketio';
2332    form.style.position = 'absolute';
2333    form.style.top = '-1000px';
2334    form.style.left = '-1000px';
2335    form.target = id;
2336    form.method = 'POST';
2337    form.setAttribute('accept-charset', 'utf-8');
2338    area.name = 'd';
2339    form.appendChild(area);
2340    document.body.appendChild(form);
2341
2342    this.form = form;
2343    this.area = area;
2344  }
2345
2346  this.form.action = this.uri();
2347
2348  function complete () {
2349    initIframe();
2350    fn();
2351  }
2352
2353  function initIframe () {
2354    if (self.iframe) {
2355      try {
2356        self.form.removeChild(self.iframe);
2357      } catch (e) {
2358        self.onError('jsonp polling iframe removal error', e);
2359      }
2360    }
2361
2362    try {
2363      // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
2364      var html = '<iframe src="javascript:0" name="'+ self.iframeId +'">';
2365      iframe = document.createElement(html);
2366    } catch (e) {
2367      iframe = document.createElement('iframe');
2368      iframe.name = self.iframeId;
2369      iframe.src = 'javascript:0';
2370    }
2371
2372    iframe.id = self.iframeId;
2373
2374    self.form.appendChild(iframe);
2375    self.iframe = iframe;
2376  }
2377
2378  initIframe();
2379
2380  // escape \n to prevent it from being converted into \r\n by some UAs
2381  // double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side
2382  data = data.replace(rEscapedNewline, '\\\n');
2383  this.area.value = data.replace(rNewline, '\\n');
2384
2385  try {
2386    this.form.submit();
2387  } catch(e) {}
2388
2389  if (this.

Large files files are truncated, but you can click here to view the full file