Skip to content

Instantly share code, notes, and snippets.

@einaros
Created October 13, 2011 17:58
Show Gist options
  • Save einaros/48bf9fbcdb6993605fee to your computer and use it in GitHub Desktop.
Save einaros/48bf9fbcdb6993605fee to your computer and use it in GitHub Desktop.
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
/**
* Packet types.
*/
var packets = exports.packets = {
'disconnect': 0
, 'connect': 1
, 'heartbeat': 2
, 'message': 3
, 'json': 4
, 'event': 5
, 'ack': 6
, 'error': 7
, 'noop': 8
}
, packetslist = Object.keys(packets);
/**
* Errors reasons.
*/
var reasons = exports.reasons = {
'transport not supported': 0
, 'client not handshaken': 1
, 'unauthorized': 2
}
, reasonslist = Object.keys(reasons);
/**
* Errors advice.
*/
var advice = exports.advice = {
'reconnect': 0
}
, advicelist = Object.keys(advice);
/**
* Encodes a packet.
*
* @api private
*/
var encoder = {
'message': function(data, packet) {
if (packet.data !== '')
data = packet.data;
return data;
},
'event': function(data, packet) {
var ev = { name: packet.name };
if (packet.args && packet.args.length) {
ev.args = packet.args;
}
data = JSON.stringify(ev);
return data;
},
'json': function(data, packet) {
data = JSON.stringify(packet.data);
return data;
},
'ack': function(data, packet) {
data = packet.ackId
+ (packet.args && packet.args.length
? '+' + JSON.stringify(packet.args) : '');
return data;
},
'connect': function(data, packet) {
if (packet.qs)
data = packet.qs;
return data;
},
'error': function(data, packet) {
var reason = packet.reason ? reasons[packet.reason] : ''
, adv = packet.advice ? advice[packet.advice] : ''
if (reason !== '' || adv !== '')
data = reason + (adv !== '' ? ('+' + adv) : '')
return data;
}
}
exports.encodePacket = function (packet) {
var type = packets[packet.type]
, id = packet.id || ''
, endpoint = packet.endpoint || ''
, ack = packet.ack
, data = null;
data = encoder[packet.type](data, packet);
// construct packet with required fragments
var encoded = [
type
, id + (ack == 'data' ? '+' : '')
, endpoint
];
// data fragment is optional
if (data !== null && data !== undefined)
encoded.push(data);
return encoded.join(':');
};
/**
* Encodes multiple messages (payload).
*
* @param {Array} messages
* @api private
*/
exports.encodePayload = function (packets) {
var decoded = '';
if (packets.length == 1)
return packets[0];
for (var i = 0, l = packets.length; i < l; i++) {
var packet = packets[i];
decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
}
return decoded;
};
/**
* Decodes a packet
*
* @api private
*/
var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
var parse = JSON.parse;
var decoder = {
'message': function(data, packet) {
packet.data = data || '';
},
'event': function(data, packet) {
try {
var pieces = parse(data);
packet.name = pieces.name;
packet.args = pieces.args;
} catch (e) { }
packet.args = packet.args || [];
},
'json': function(data, packet) {
try {
packet.data = parse(data);
} catch (e) { }
},
'connect': function(data, packet) {
packet.qs = data || '';
},
'ack': function(data, packet) {
var pieces = data.match(/^([0-9]+)(\+)?(.*)/);
if (pieces) {
packet.ackId = pieces[1];
packet.args = [];
if (pieces[3]) {
try {
packet.args = pieces[3] ? parse(pieces[3]) : [];
} catch (e) { }
}
}
},
'error': function(data, packet) {
var pieces = data.split('+');
packet.reason = reasonslist[pieces[0]] || '';
packet.advice = advicelist[pieces[1]] || '';
}
}
exports.decodePacket = function (data) {
var pieces = data.match(regexp);
if (!pieces) return {};
var id = pieces[2] || ''
, data = pieces[5] || ''
, packet = {
type: packetslist[pieces[1]]
, endpoint: pieces[4] || ''
};
// whether we need to acknowledge the packet
if (id) {
packet.id = id;
if (pieces[3])
packet.ack = 'data';
else
packet.ack = true;
}
// handle different packet types
decoder[packet.type](data, packet);
return packet;
};
/**
* Decodes data payload. Detects multiple messages
*
* @return {Array} messages
* @api public
*/
exports.decodePayload = function (data) {
if (undefined == data || null == data) {
return [];
}
if (data[0] == '\ufffd') {
var ret = [];
for (var i = 1, length = ''; i < data.length; i++) {
if (data[i] == '\ufffd') {
ret.push(exports.decodePacket(data.substr(i + 1).substr(0, length)));
i += Number(length) + 1;
length = '';
} else {
length += data[i];
}
}
return ret;
} else {
return [exports.decodePacket(data)];
}
};
Executed benchmark encoding (string)
Count (80769), Cycles (95), Elapsed (5.036), Hz (1503795.6932021)
Executed benchmark encoding (event+ack)
Count (37727), Cycles (96), Elapsed (5.029), Hz (714417.3243181611)
Executed benchmark encoding (event+data)
Count (16332), Cycles (100), Elapsed (5.051), Hz (319930.5813885676)
Executed benchmark encoding (payload)
Count (9851), Cycles (100), Elapsed (5.051), Hz (194113.86759713356)
Executed benchmark decoding (string)
Count (106126), Cycles (100), Elapsed (5.001), Hz (2101277.3588654296)
Executed benchmark decoding (event)
Count (53514), Cycles (100), Elapsed (5.02), Hz (1058395.1330354088)
Executed benchmark decoding (event+ack)
Count (47672), Cycles (100), Elapsed (5.018), Hz (938549.735871924)
Executed benchmark decoding (event+data)
Count (27802), Cycles (100), Elapsed (5.032), Hz (548953.1866758841)
Executed benchmark decoding (payload)
Count (7937), Cycles (100), Elapsed (5.006), Hz (157456.94950931493)
Executed benchmark encoding (string)
Count (69519), Cycles (100), Elapsed (5.038), Hz (1372022.3509649534)
Executed benchmark encoding (event+ack)
Count (36560), Cycles (99), Elapsed (5.01), Hz (716103.8763114816)
Executed benchmark encoding (event+data)
Count (17507), Cycles (100), Elapsed (5.03), Hz (345261.3699044089)
Executed benchmark encoding (payload)
Count (10575), Cycles (100), Elapsed (5.024), Hz (209442.11976789756)
Executed benchmark decoding (string)
Count (93225), Cycles (101), Elapsed (5.05), Hz (1842997.7012547196)
Executed benchmark decoding (event)
Count (51114), Cycles (95), Elapsed (5.039), Hz (956307.723505352)
Executed benchmark decoding (event+ack)
Count (45895), Cycles (100), Elapsed (5.02), Hz (906246.2343380426)
Executed benchmark decoding (event+data)
Count (25581), Cycles (100), Elapsed (5.022), Hz (505888.965932063)
Executed benchmark decoding (payload)
Count (8067), Cycles (101), Elapsed (5.039), Hz (160269.65544290532)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment