arnaucube
arnaucube/comunicationLeapPublic Self-hosted repository
comunicationLeap/node_modules/socket.io/lib/socket.js
node_modules/socket.io/lib/socket.jsRaw
  1
  2/**
  3 * Module dependencies.
  4 */
  5
  6var Emitter = require('events').EventEmitter;
  7var parser = require('socket.io-parser');
  8var url = require('url');
  9var debug = require('debug')('socket.io:socket');
 10var hasBin = require('has-binary-data');
 11
 12/**
 13 * Module exports.
 14 */
 15
 16module.exports = exports = Socket;
 17
 18/**
 19 * Blacklisted events.
 20 *
 21 * @api public
 22 */
 23
 24exports.events = [
 25  'error',
 26  'connect',
 27  'disconnect',
 28  'newListener',
 29  'removeListener'
 30];
 31
 32/**
 33 * Flags.
 34 *
 35 * @api private
 36 */
 37
 38var flags = [
 39  'json',
 40  'volatile',
 41  'broadcast'
 42];
 43
 44/**
 45 * `EventEmitter#emit` reference.
 46 */
 47
 48var emit = Emitter.prototype.emit;
 49
 50/**
 51 * Interface to a `Client` for a given `Namespace`.
 52 *
 53 * @param {Namespace} nsp
 54 * @param {Client} client
 55 * @api public
 56 */
 57
 58function Socket(nsp, client){
 59  this.nsp = nsp;
 60  this.server = nsp.server;
 61  this.adapter = this.nsp.adapter;
 62  this.id = client.id;
 63  this.request = client.request;
 64  this.client = client;
 65  this.conn = client.conn;
 66  this.rooms = [];
 67  this.acks = {};
 68  this.connected = true;
 69  this.disconnected = false;
 70  this.handshake = this.buildHandshake();
 71}
 72
 73/**
 74 * Inherits from `EventEmitter`.
 75 */
 76
 77Socket.prototype.__proto__ = Emitter.prototype;
 78
 79/**
 80 * Apply flags from `Socket`.
 81 */
 82
 83flags.forEach(function(flag){
 84  Socket.prototype.__defineGetter__(flag, function(){
 85    this.flags = this.flags || {};
 86    this.flags[flag] = true;
 87    return this;
 88  });
 89});
 90
 91/**
 92 * `request` engine.io shorcut.
 93 *
 94 * @api public
 95 */
 96
 97Socket.prototype.__defineGetter__('request', function(){
 98  return this.conn.request;
 99});
100
101/**
102 * Builds the `handshake` BC object
103 *
104 * @api private
105 */
106
107Socket.prototype.buildHandshake = function(){
108  return {
109    headers: this.request.headers,
110    time: (new Date) + '',
111    address: this.conn.remoteAddress,
112    xdomain: !!this.request.headers.origin,
113    secure: !!this.request.connection.encrypted,
114    issued: +(new Date),
115    url: this.request.url,
116    query: url.parse(this.request.url, true).query || {}
117  };
118};
119
120/**
121 * Emits to this client.
122 *
123 * @return {Socket} self
124 * @api public
125 */
126
127Socket.prototype.emit = function(ev){
128  if (~exports.events.indexOf(ev)) {
129    emit.apply(this, arguments);
130  } else {
131    var args = Array.prototype.slice.call(arguments);
132    var packet = {};
133    packet.type = hasBin(args) ? parser.BINARY_EVENT : parser.EVENT;
134    packet.data = args;
135
136    // access last argument to see if it's an ACK callback
137    if ('function' == typeof args[args.length - 1]) {
138      if (this._rooms || (this.flags && this.flags.broadcast)) {
139        throw new Error('Callbacks are not supported when broadcasting');
140      }
141
142      debug('emitting packet with ack id %d', this.nsp.ids);
143      this.acks[this.nsp.ids] = args.pop();
144      packet.id = this.nsp.ids++;
145    }
146
147    if (this._rooms || (this.flags && this.flags.broadcast)) {
148      this.adapter.broadcast(packet, {
149        except: [this.id],
150        rooms: this._rooms,
151        flags: this.flags
152      });
153    } else {
154      // dispatch packet
155      this.packet(packet);
156    }
157
158    // reset flags
159    delete this._rooms;
160    delete this.flags;
161  }
162  return this;
163};
164
165/**
166 * Targets a room when broadcasting.
167 *
168 * @param {String} name
169 * @return {Socket} self
170 * @api public
171 */
172
173Socket.prototype.to =
174Socket.prototype.in = function(name){
175  this._rooms = this._rooms || [];
176  if (!~this._rooms.indexOf(name)) this._rooms.push(name);
177  return this;
178};
179
180/**
181 * Sends a `message` event.
182 *
183 * @return {Socket} self
184 * @api public
185 */
186
187Socket.prototype.send =
188Socket.prototype.write = function(){
189  var args = Array.prototype.slice.call(arguments);
190  args.unshift('message');
191  this.emit.apply(this, args);
192  return this;
193};
194
195/**
196 * Writes a packet.
197 *
198 * @param {Object} packet object
199 * @api private
200 */
201
202Socket.prototype.packet = function(packet, preEncoded){
203  packet.nsp = this.nsp.name;
204  var volatile = this.flags && this.flags.volatile;
205  this.client.packet(packet, preEncoded, volatile);
206};
207
208/**
209 * Joins a room.
210 *
211 * @param {String} room
212 * @param {Function} optional, callback
213 * @return {Socket} self
214 * @api private
215 */
216
217Socket.prototype.join = function(room, fn){
218  debug('joining room %s', room);
219  var self = this;
220  if (~this.rooms.indexOf(room)) return this;
221  this.adapter.add(this.id, room, function(err){
222    if (err) return fn && fn(err);
223    debug('joined room %s', room);
224    self.rooms.push(room);
225    fn && fn(null);
226  });
227  return this;
228};
229
230/**
231 * Leaves a room.
232 *
233 * @param {String} room
234 * @param {Function} optional, callback
235 * @return {Socket} self
236 * @api private
237 */
238
239Socket.prototype.leave = function(room, fn){
240  debug('leave room %s', room);
241  var self = this;
242  this.adapter.del(this.id, room, function(err){
243    if (err) return fn && fn(err);
244    debug('left room %s', room);
245    self.rooms.splice(self.rooms.indexOf(room), 1);
246    fn && fn(null);
247  });
248  return this;
249};
250
251/**
252 * Leave all rooms.
253 *
254 * @api private
255 */
256
257Socket.prototype.leaveAll = function(){
258  this.adapter.delAll(this.id);
259  this.rooms = [];
260};
261
262/**
263 * Called by `Namespace` upon succesful
264 * middleware execution (ie: authorization).
265 *
266 * @api private
267 */
268
269Socket.prototype.onconnect = function(){
270  debug('socket connected - writing packet');
271  this.join(this.id);
272  this.packet({ type: parser.CONNECT });
273  this.nsp.connected[this.id] = this;
274};
275
276/**
277 * Called with each packet. Called by `Client`.
278 *
279 * @param {Object} packet
280 * @api private
281 */
282
283Socket.prototype.onpacket = function(packet){
284  debug('got packet %j', packet);
285  switch (packet.type) {
286    case parser.EVENT:
287      this.onevent(packet);
288      break;
289
290    case parser.BINARY_EVENT:
291      this.onevent(packet);
292      break;
293
294    case parser.ACK:
295      this.onack(packet);
296      break;
297
298    case parser.BINARY_ACK:
299      this.onack(packet);
300      break;
301
302    case parser.DISCONNECT:
303      this.ondisconnect();
304      break;
305
306    case parser.ERROR:
307      this.emit('error', packet.data);
308  }
309};
310
311/**
312 * Called upon event packet.
313 *
314 * @param {Object} packet object
315 * @api private
316 */
317
318Socket.prototype.onevent = function(packet){
319  var args = packet.data || [];
320  debug('emitting event %j', args);
321
322  if (null != packet.id) {
323    debug('attaching ack callback to event');
324    args.push(this.ack(packet.id));
325  }
326
327  emit.apply(this, args);
328};
329
330/**
331 * Produces an ack callback to emit with an event.
332 *
333 * @param {Number} packet id
334 * @api private
335 */
336
337Socket.prototype.ack = function(id){
338  var self = this;
339  var sent = false;
340  return function(){
341    // prevent double callbacks
342    if (sent) return;
343    var args = Array.prototype.slice.call(arguments);
344    debug('sending ack %j', args);
345
346    var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK;
347    self.packet({
348      id: id,
349      type: type,
350      data: args
351    });
352  };
353};
354
355/**
356 * Called upon ack packet.
357 *
358 * @api private
359 */
360
361Socket.prototype.onack = function(packet){
362  var ack = this.acks[packet.id];
363  if ('function' == typeof ack) {
364    debug('calling ack %s with %j', packet.id, packet.data);
365    ack.apply(this, packet.data);
366    delete this.acks[packet.id];
367  } else {
368    debug('bad ack %s', packet.id);
369  }
370};
371
372/**
373 * Called upon client disconnect packet.
374 *
375 * @api private
376 */
377
378Socket.prototype.ondisconnect = function(){
379  debug('got disconnect packet');
380  this.onclose('client namespace disconnect');
381};
382
383/**
384 * Called upon closing. Called by `Client`.
385 *
386 * @param {String} reason
387 * @api private
388 */
389
390Socket.prototype.onclose = function(reason){
391  if (!this.connected) return this;
392  debug('closing socket - reason %s', reason);
393  this.leaveAll();
394  this.nsp.remove(this);
395  this.client.remove(this);
396  this.connected = false;
397  this.disconnected = true;
398  delete this.nsp.connected[this.id];
399  this.emit('disconnect', reason);
400};
401
402/**
403 * Produces an `error` packet.
404 *
405 * @param {Object} error object
406 * @api private
407 */
408
409Socket.prototype.error = function(err){
410  this.packet({ type: parser.ERROR, data: err });
411};
412
413/**
414 * Disconnects this client.
415 *
416 * @param {Boolean} if `true`, closes the underlying connection
417 * @return {Socket} self
418 * @api public
419 */
420
421Socket.prototype.disconnect = function(close){
422  if (!this.connected) return this;
423  if (close) {
424    this.client.disconnect();
425  } else {
426    this.packet({ type: parser.DISCONNECT });
427    this.onclose('server namespace disconnect');
428  }
429  return this;
430};