arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/server/node_modules/socket.io-client/lib/socket.js
server/node_modules/socket.io-client/lib/socket.jsRaw
  1
  2/**
  3 * Module dependencies.
  4 */
  5
  6var parser = require('socket.io-parser');
  7var Emitter = require('component-emitter');
  8var toArray = require('to-array');
  9var on = require('./on');
 10var bind = require('component-bind');
 11var debug = require('debug')('socket.io-client:socket');
 12var hasBin = require('has-binary');
 13
 14/**
 15 * Module exports.
 16 */
 17
 18module.exports = exports = Socket;
 19
 20/**
 21 * Internal events (blacklisted).
 22 * These events can't be emitted by the user.
 23 *
 24 * @api private
 25 */
 26
 27var events = {
 28  connect: 1,
 29  connect_error: 1,
 30  connect_timeout: 1,
 31  connecting: 1,
 32  disconnect: 1,
 33  error: 1,
 34  reconnect: 1,
 35  reconnect_attempt: 1,
 36  reconnect_failed: 1,
 37  reconnect_error: 1,
 38  reconnecting: 1,
 39  ping: 1,
 40  pong: 1
 41};
 42
 43/**
 44 * Shortcut to `Emitter#emit`.
 45 */
 46
 47var emit = Emitter.prototype.emit;
 48
 49/**
 50 * `Socket` constructor.
 51 *
 52 * @api public
 53 */
 54
 55function Socket (io, nsp, opts) {
 56  this.io = io;
 57  this.nsp = nsp;
 58  this.json = this; // compat
 59  this.ids = 0;
 60  this.acks = {};
 61  this.receiveBuffer = [];
 62  this.sendBuffer = [];
 63  this.connected = false;
 64  this.disconnected = true;
 65  if (opts && opts.query) {
 66    this.query = opts.query;
 67  }
 68  if (this.io.autoConnect) this.open();
 69}
 70
 71/**
 72 * Mix in `Emitter`.
 73 */
 74
 75Emitter(Socket.prototype);
 76
 77/**
 78 * Subscribe to open, close and packet events
 79 *
 80 * @api private
 81 */
 82
 83Socket.prototype.subEvents = function () {
 84  if (this.subs) return;
 85
 86  var io = this.io;
 87  this.subs = [
 88    on(io, 'open', bind(this, 'onopen')),
 89    on(io, 'packet', bind(this, 'onpacket')),
 90    on(io, 'close', bind(this, 'onclose'))
 91  ];
 92};
 93
 94/**
 95 * "Opens" the socket.
 96 *
 97 * @api public
 98 */
 99
100Socket.prototype.open =
101Socket.prototype.connect = function () {
102  if (this.connected) return this;
103
104  this.subEvents();
105  this.io.open(); // ensure open
106  if ('open' === this.io.readyState) this.onopen();
107  this.emit('connecting');
108  return this;
109};
110
111/**
112 * Sends a `message` event.
113 *
114 * @return {Socket} self
115 * @api public
116 */
117
118Socket.prototype.send = function () {
119  var args = toArray(arguments);
120  args.unshift('message');
121  this.emit.apply(this, args);
122  return this;
123};
124
125/**
126 * Override `emit`.
127 * If the event is in `events`, it's emitted normally.
128 *
129 * @param {String} event name
130 * @return {Socket} self
131 * @api public
132 */
133
134Socket.prototype.emit = function (ev) {
135  if (events.hasOwnProperty(ev)) {
136    emit.apply(this, arguments);
137    return this;
138  }
139
140  var args = toArray(arguments);
141  var parserType = parser.EVENT; // default
142  if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary
143  var packet = { type: parserType, data: args };
144
145  packet.options = {};
146  packet.options.compress = !this.flags || false !== this.flags.compress;
147
148  // event ack callback
149  if ('function' === typeof args[args.length - 1]) {
150    debug('emitting packet with ack id %d', this.ids);
151    this.acks[this.ids] = args.pop();
152    packet.id = this.ids++;
153  }
154
155  if (this.connected) {
156    this.packet(packet);
157  } else {
158    this.sendBuffer.push(packet);
159  }
160
161  delete this.flags;
162
163  return this;
164};
165
166/**
167 * Sends a packet.
168 *
169 * @param {Object} packet
170 * @api private
171 */
172
173Socket.prototype.packet = function (packet) {
174  packet.nsp = this.nsp;
175  this.io.packet(packet);
176};
177
178/**
179 * Called upon engine `open`.
180 *
181 * @api private
182 */
183
184Socket.prototype.onopen = function () {
185  debug('transport is open - connecting');
186
187  // write connect packet if necessary
188  if ('/' !== this.nsp) {
189    if (this.query) {
190      this.packet({type: parser.CONNECT, query: this.query});
191    } else {
192      this.packet({type: parser.CONNECT});
193    }
194  }
195};
196
197/**
198 * Called upon engine `close`.
199 *
200 * @param {String} reason
201 * @api private
202 */
203
204Socket.prototype.onclose = function (reason) {
205  debug('close (%s)', reason);
206  this.connected = false;
207  this.disconnected = true;
208  delete this.id;
209  this.emit('disconnect', reason);
210};
211
212/**
213 * Called with socket packet.
214 *
215 * @param {Object} packet
216 * @api private
217 */
218
219Socket.prototype.onpacket = function (packet) {
220  if (packet.nsp !== this.nsp) return;
221
222  switch (packet.type) {
223    case parser.CONNECT:
224      this.onconnect();
225      break;
226
227    case parser.EVENT:
228      this.onevent(packet);
229      break;
230
231    case parser.BINARY_EVENT:
232      this.onevent(packet);
233      break;
234
235    case parser.ACK:
236      this.onack(packet);
237      break;
238
239    case parser.BINARY_ACK:
240      this.onack(packet);
241      break;
242
243    case parser.DISCONNECT:
244      this.ondisconnect();
245      break;
246
247    case parser.ERROR:
248      this.emit('error', packet.data);
249      break;
250  }
251};
252
253/**
254 * Called upon a server event.
255 *
256 * @param {Object} packet
257 * @api private
258 */
259
260Socket.prototype.onevent = function (packet) {
261  var args = packet.data || [];
262  debug('emitting event %j', args);
263
264  if (null != packet.id) {
265    debug('attaching ack callback to event');
266    args.push(this.ack(packet.id));
267  }
268
269  if (this.connected) {
270    emit.apply(this, args);
271  } else {
272    this.receiveBuffer.push(args);
273  }
274};
275
276/**
277 * Produces an ack callback to emit with an event.
278 *
279 * @api private
280 */
281
282Socket.prototype.ack = function (id) {
283  var self = this;
284  var sent = false;
285  return function () {
286    // prevent double callbacks
287    if (sent) return;
288    sent = true;
289    var args = toArray(arguments);
290    debug('sending ack %j', args);
291
292    var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK;
293    self.packet({
294      type: type,
295      id: id,
296      data: args
297    });
298  };
299};
300
301/**
302 * Called upon a server acknowlegement.
303 *
304 * @param {Object} packet
305 * @api private
306 */
307
308Socket.prototype.onack = function (packet) {
309  var ack = this.acks[packet.id];
310  if ('function' === typeof ack) {
311    debug('calling ack %s with %j', packet.id, packet.data);
312    ack.apply(this, packet.data);
313    delete this.acks[packet.id];
314  } else {
315    debug('bad ack %s', packet.id);
316  }
317};
318
319/**
320 * Called upon server connect.
321 *
322 * @api private
323 */
324
325Socket.prototype.onconnect = function () {
326  this.connected = true;
327  this.disconnected = false;
328  this.emit('connect');
329  this.emitBuffered();
330};
331
332/**
333 * Emit buffered events (received and emitted).
334 *
335 * @api private
336 */
337
338Socket.prototype.emitBuffered = function () {
339  var i;
340  for (i = 0; i < this.receiveBuffer.length; i++) {
341    emit.apply(this, this.receiveBuffer[i]);
342  }
343  this.receiveBuffer = [];
344
345  for (i = 0; i < this.sendBuffer.length; i++) {
346    this.packet(this.sendBuffer[i]);
347  }
348  this.sendBuffer = [];
349};
350
351/**
352 * Called upon server disconnect.
353 *
354 * @api private
355 */
356
357Socket.prototype.ondisconnect = function () {
358  debug('server disconnect (%s)', this.nsp);
359  this.destroy();
360  this.onclose('io server disconnect');
361};
362
363/**
364 * Called upon forced client/server side disconnections,
365 * this method ensures the manager stops tracking us and
366 * that reconnections don't get triggered for this.
367 *
368 * @api private.
369 */
370
371Socket.prototype.destroy = function () {
372  if (this.subs) {
373    // clean subscriptions to avoid reconnections
374    for (var i = 0; i < this.subs.length; i++) {
375      this.subs[i].destroy();
376    }
377    this.subs = null;
378  }
379
380  this.io.destroy(this);
381};
382
383/**
384 * Disconnects the socket manually.
385 *
386 * @return {Socket} self
387 * @api public
388 */
389
390Socket.prototype.close =
391Socket.prototype.disconnect = function () {
392  if (this.connected) {
393    debug('performing disconnect (%s)', this.nsp);
394    this.packet({ type: parser.DISCONNECT });
395  }
396
397  // remove socket from pool
398  this.destroy();
399
400  if (this.connected) {
401    // fire events
402    this.onclose('io client disconnect');
403  }
404  return this;
405};
406
407/**
408 * Sets the compress flag.
409 *
410 * @param {Boolean} if `true`, compresses the sending data
411 * @return {Socket} self
412 * @api public
413 */
414
415Socket.prototype.compress = function (compress) {
416  this.flags = this.flags || {};
417  this.flags.compress = compress;
418  return this;
419};