/*! * socket.io-node * Copyright(c) 2011 LearnBoost * MIT Licensed */ /** * Module dependencies. */ var 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.packets = 0; this.disconnected = false; 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; }); /** * 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) { this.store.join(this.nsp.name + '/' + 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; 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.packets; packet.ack = fn.length ? 'data' : true; this.acks[packet.id] = fn; } return this.packet(packet); }; /** * 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' }; if ('function' == typeof lastArg) { packet.id = ++this.packets; packet.ack = lastArg.length ? 'data' : true; this.acks[packet.id] = fn; args = args.slice(0, args.length - 1); } packet.args = args; return this.packet(packet); };