/** * socket.io * Copyright(c) 2011 LearnBoost * MIT Licensed */ (function (exports, io) { /** * Expose constructor. */ exports.SocketNamespace = SocketNamespace; /** * Socket namespace constructor. * * @constructor * @api public */ function SocketNamespace (socket, name) { this.socket = socket; this.name = name || ''; this.flags = {}; this.json = new Flag(this, 'json'); this.ackPackets = 0; this.acks = {}; }; /** * Apply EventEmitter mixin. */ io.util.mixin(SocketNamespace, io.EventEmitter); /** * Copies emit since we override it * * @api private */ SocketNamespace.prototype.$emit = io.EventEmitter.prototype.emit; /** * Creates a new namespace, by proxying the request to the socket. This * allows us to use the synax as we do on the server. * * @api public */ SocketNamespace.prototype.of = function () { return this.socket.of.apply(this.socket, arguments); }; /** * Sends a packet. * * @api private */ SocketNamespace.prototype.packet = function (packet) { packet.endpoint = this.name; this.socket.packet(packet); this.flags = {}; return this; }; /** * Sends a message * * @api public */ SocketNamespace.prototype.send = function (data, fn) { var packet = { type: this.flags.json ? 'json' : 'message' , data: data }; if ('function' == typeof fn) { packet.id = ++this.ackPackets; packet.ack = true; this.acks[packet.id] = fn; } return this.packet(packet); }; /** * Emits an event * * @api public */ SocketNamespace.prototype.emit = function (name) { var args = Array.prototype.slice.call(arguments, 1) , lastArg = args[args.length - 1] , packet = { type: 'event' , name: name }; if ('function' == typeof lastArg) { packet.id = ++this.ackPackets; packet.ack = 'data'; this.acks[packet.id] = lastArg; args = args.slice(0, args.length - 1); } packet.args = args; return this.packet(packet); }; /** * Disconnects the namespace * * @api private */ SocketNamespace.prototype.disconnect = function () { if (this.name === '') { this.socket.disconnect(); } else { this.packet({ type: 'disconnect' }); this.$emit('disconnect'); } return this; }; /** * Handles a packet * * @api private */ SocketNamespace.prototype.onPacket = function (packet) { var self = this; function ack () { self.packet({ type: 'ack' , args: io.util.toArray(arguments) , ackId: packet.id }); }; switch (packet.type) { case 'connect': this.$emit('connect'); break; case 'disconnect': if (this.name === '') { this.socket.onDisconnect(packet.reason || 'booted'); } else { this.$emit('disconnect', packet.reason); } break; case 'message': case 'json': var params = ['message', packet.data]; if (packet.ack == 'data') { params.push(ack); } else if (packet.ack) { this.packet({ type: 'ack', ackId: packet.id }); } this.$emit.apply(this, params); break; case 'event': var params = [packet.name].concat(packet.args); if (packet.ack == 'data') params.push(ack); this.$emit.apply(this, params); break; case 'ack': if (this.acks[packet.ackId]) { this.acks[packet.ackId].apply(this, packet.args); delete this.acks[packet.ackId]; } break; case 'error': if (packet.advice){ this.socket.onError(packet); } else { if (packet.reason == 'unauthorized') { this.$emit('connect_failed', packet.reason); } else { this.$emit('error', packet.reason); } } break; } }; /** * Flag interface. * * @api private */ function Flag (nsp, name) { this.namespace = nsp; this.name = name; }; /** * Send a message * * @api public */ Flag.prototype.send = function () { this.namespace.flags[this.name] = true; this.namespace.send.apply(this.namespace, arguments); }; /** * Emit an event * * @api public */ Flag.prototype.emit = function () { this.namespace.flags[this.name] = true; this.namespace.emit.apply(this.namespace, arguments); }; })( 'undefined' != typeof io ? io : module.exports , 'undefined' != typeof io ? io : module.parent.exports );