4 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
12 var parser = require('./parser')
13 , util = require('./util')
14 , EventEmitter = process.EventEmitter
17 * Export the constructor.
20 exports = module.exports = Socket;
23 * Default error event listener to prevent uncaught exceptions.
26 var defaultError = function () {};
31 * @param {Manager} manager instance
32 * @param {String} session id
33 * @param {Namespace} namespace the socket belongs to
34 * @param {Boolean} whether the
38 function Socket (manager, id, nsp, readable) {
41 this.manager = manager;
42 this.disconnected = false;
46 this.readable = readable;
47 this.store = this.manager.store.client(this.id);
48 this.on('error', defaultError);
52 * Inherits from EventEmitter.
55 Socket.prototype.__proto__ = EventEmitter.prototype;
58 * Accessor shortcut for the handshake data
63 Socket.prototype.__defineGetter__('handshake', function () {
64 return this.manager.handshaken[this.id];
68 * Accessor shortcut for the transport type
73 Socket.prototype.__defineGetter__('transport', function () {
74 return this.manager.transports[this.id].name;
78 * Accessor shortcut for the logger.
83 Socket.prototype.__defineGetter__('log', function () {
84 return this.manager.log;
93 Socket.prototype.__defineGetter__('json', function () {
94 this.flags.json = true;
99 * Volatile message flag.
104 Socket.prototype.__defineGetter__('volatile', function () {
105 this.flags.volatile = true;
110 * Broadcast message flag.
115 Socket.prototype.__defineGetter__('broadcast', function () {
116 this.flags.broadcast = true;
121 * Overrides the room to broadcast messages to (flag)
126 Socket.prototype.to = Socket.prototype.in = function (room) {
127 this.flags.room = room;
137 Socket.prototype.setFlags = function () {
139 endpoint: this.namespace.name
146 * Triggered on disconnect
151 Socket.prototype.onDisconnect = function (reason) {
152 if (!this.disconnected) {
153 this.$emit('disconnect', reason);
154 this.disconnected = true;
159 * Joins a user to a room.
164 Socket.prototype.join = function (name, fn) {
165 var nsp = this.namespace.name
166 , name = (nsp + '/') + name;
168 this.manager.onJoin(this.id, name);
169 this.manager.store.publish('join', this.id, name);
172 this.log.warn('Client#join callback is deprecated');
180 * Un-joins a user from a room.
185 Socket.prototype.leave = function (name, fn) {
186 var nsp = this.namespace.name
187 , name = (nsp + '/') + name;
189 this.manager.onLeave(this.id, name);
190 this.manager.store.publish('leave', this.id, name);
193 this.log.warn('Client#leave callback is deprecated');
201 * Transmits a packet.
206 Socket.prototype.packet = function (packet) {
207 if (this.flags.broadcast) {
208 this.log.debug('broadcasting packet');
209 this.namespace.in(this.flags.room).except(this.id).packet(packet);
211 packet.endpoint = this.flags.endpoint;
212 packet = parser.encodePacket(packet);
214 this.dispatch(packet, this.flags.volatile);
223 * Dispatches a packet
228 Socket.prototype.dispatch = function (packet, volatile) {
229 if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
230 this.manager.transports[this.id].onDispatch(packet, volatile);
233 this.manager.onClientDispatch(this.id, packet, volatile);
236 this.manager.store.publish('dispatch:' + this.id, packet, volatile);
241 * Stores data for the client.
246 Socket.prototype.set = function (key, value, fn) {
247 this.store.set(key, value, fn);
252 * Retrieves data for the client
257 Socket.prototype.get = function (key, fn) {
258 this.store.get(key, fn);
263 * Checks data for the client
268 Socket.prototype.has = function (key, fn) {
269 this.store.has(key, fn);
274 * Deletes data for the client
279 Socket.prototype.del = function (key, fn) {
280 this.store.del(key, fn);
290 Socket.prototype.disconnect = function () {
291 if (!this.disconnected) {
292 this.log.info('booting client');
294 if ('' === this.namespace.name) {
295 if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
296 this.manager.transports[this.id].onForcedDisconnect();
298 this.manager.onClientDisconnect(this.id);
299 this.manager.store.publish('disconnect:' + this.id);
302 this.packet({type: 'disconnect'});
303 this.manager.onLeave(this.id, this.namespace.name);
304 this.$emit('disconnect', 'booted');
318 Socket.prototype.send = function (data, fn) {
320 type: this.flags.json ? 'json' : 'message'
325 packet.id = ++this.ackPackets;
327 this.acks[packet.id] = fn;
330 return this.packet(packet);
334 * Original emit function.
339 Socket.prototype.$emit = EventEmitter.prototype.emit;
342 * Emit override for custom events.
347 Socket.prototype.emit = function (ev) {
348 if (ev == 'newListener') {
349 return this.$emit.apply(this, arguments);
352 var args = util.toArray(arguments).slice(1)
353 , lastArg = args[args.length - 1]
359 if ('function' == typeof lastArg) {
360 packet.id = ++this.ackPackets;
361 packet.ack = lastArg.length ? 'data' : true;
362 this.acks[packet.id] = lastArg;
363 args = args.slice(0, args.length - 1);
368 return this.packet(packet);