Files
socket.io/lib/socket.js
Guillermo Rauch aac298d212 Fixed Socket#to and Socket#join. Make sure that the name of the room preserves the
namespace as prefix, unless the namespace is ''. This prevents collisions between
rooms of the '' endpoint with other arbitrary endpoints.
2011-05-24 23:46:59 -07:00

287 lines
4.6 KiB
JavaScript

/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var parser = require('./parser')
, util = require('./util')
, EventEmitter = process.EventEmitter;
/**
* Export the constructor.
*/
exports = module.exports = Socket;
/**
* Reserved event names.
*/
var events = {
message: 1
, connect: 1
, disconnect: 1
, open: 1
, close: 1
, error: 1
, retry: 1
, reconnect: 1
, newListener: 1
};
/**
* Socket constructor.
*
* @param {Manager} manager instance
* @param {String} session id
* @param {Namespace} namespace the socket belongs to
* @param {Boolean} whether the
* @api public
*/
function Socket (manager, id, nsp, readable) {
this.id = id;
this.namespace = nsp;
this.manager = manager;
this.flags = {};
this.disconnected = false;
this.ackPackets = 0;
this.acks = {};
if (readable) {
var self = this;
this.store.once('disconnect:' + id, function (reason) {
self.onDisconnect(reason);
});
}
};
/**
* Inherits from EventEmitter.
*/
Socket.prototype.__proto__ = EventEmitter.prototype;
/**
* Accessor shortcut for the store.
*
* @api private
*/
Socket.prototype.__defineGetter__('store', function () {
return this.manager.store;
});
/**
* Accessor shortcut for the logger.
*
* @api private
*/
Socket.prototype.__defineGetter__('log', function () {
return this.manager.log;
});
/**
* JSON message flag.
*
* @api public
*/
Socket.prototype.__defineGetter__('json', function () {
this.flags.json = true;
return this;
});
/**
* Volatile message flag.
*
* @api public
*/
Socket.prototype.__defineGetter__('volatile', function () {
this.flags.volatile = true;
return this;
});
/**
* Broadcast message flag.
*
* @api public
*/
Socket.prototype.__defineGetter__('broadcast', function () {
this.flags.broadcast = true;
return this;
});
/**
* Overrides the room to broadcast messages to (flag)
*
* @api public
*/
Socket.prototype.to = function (room) {
var nsp = this.namespace.name;
this.flags.endpoint = (nsp === '' ? '' : (nsp + '/')) + room;
return this;
};
/**
* Triggered on disconnect
*
* @api private
*/
Socket.prototype.onDisconnect = function (reason) {
if (!this.disconnected) {
this.emit('disconnect', reason);
this.disconnected = true;
}
};
/**
* Joins a user to a room.
*
* @api public
*/
Socket.prototype.join = function (name, fn) {
var nsp = this.namespace.name;
this.store.join(this.id, (nsp === '' ? '' : (nsp + '/')) + name, fn);
return this;
};
/**
* Joins a user to a room.
*
* @api public
*/
Socket.prototype.leave = function (name, fn) {
this.store.leave(this.nsp.name + '/' + name, fn);
return this;
};
/**
* Transmits a packet.
*
* @api private
*/
Socket.prototype.packet = function (packet) {
packet.endpoint = this.namespace.name;
packet = parser.encodePacket(packet);
if (this.flags.volatile) {
this.store.publish('volatile:' + this.id, packet);
} else {
this.store.client(this.id).publish(packet);
}
return this;
};
/**
* Stores data for the client.
*
* @api public
*/
Socket.prototype.set = function (key, value, fn) {
this.store.client(this.id).set(key, value, fn);
return this;
};
/**
* Retrieves data for the client
*
* @api public
*/
Socket.prototype.get = function (key, fn) {
this.store.client(this.id).get(key, fn);
return this;
};
/**
* Kicks client
*
* @api public
*/
Socket.prototype.disconnect = function () {
if (!this.disconnected) {
this.log.info('booting client');
this.store.disconnect(this.id, true);
}
return this;
};
/**
* Send a message.
*
* @api public
*/
Socket.prototype.send = function (data, fn) {
var packet = {
type: this.flags.json ? 'json' : 'message'
, data: data
};
if (fn) {
packet.id = ++this.ackPackets;
packet.ack = fn.length ? 'data' : true;
this.acks[packet.id] = fn;
}
return this.packet(packet);
};
/**
* Original emit function.
*
* @api private
*/
Socket.prototype.$emit = EventEmitter.prototype.emit;
/**
* Emit override for custom events.
*
* @api public
*/
Socket.prototype.emit = function (ev) {
if (events[ev]) {
return EventEmitter.prototype.emit.apply(this, arguments);
}
var args = util.toArray(arguments).slice(1)
, lastArg = args[args.length - 1]
, packet = {
type: 'event'
, name: ev
};
if ('function' == typeof lastArg) {
packet.id = ++this.ackPackets;
packet.ack = lastArg.length ? 'data' : true;
this.acks[packet.id] = lastArg;
args = args.slice(0, args.length - 1);
}
packet.args = args;
return this.packet(packet);
};