/**
* socket.io
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* 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
);