123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- /*!
- * 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
- */
- exports.encodePacket = function (packet) {
- var type = packets[packet.type]
- , id = packet.id || ''
- , endpoint = packet.endpoint || ''
- , ack = packet.ack
- , data = null;
- switch (packet.type) {
- case 'message':
- if (packet.data !== '')
- data = packet.data;
- break;
- case 'event':
- var ev = { name: packet.name };
- if (packet.args && packet.args.length) {
- ev.args = packet.args;
- }
- data = JSON.stringify(ev);
- break;
- case 'json':
- data = JSON.stringify(packet.data);
- break;
- case 'ack':
- data = packet.ackId
- + (packet.args && packet.args.length
- ? '+' + JSON.stringify(packet.args) : '');
- break;
- case 'connect':
- if (packet.qs)
- data = packet.qs;
- break;
- case 'error':
- var reason = packet.reason ? reasons[packet.reason] : ''
- , adv = packet.advice ? advice[packet.advice] : ''
- if (reason !== '' || adv !== '')
- data = reason + (adv !== '' ? ('+' + adv) : '')
- break;
- }
- // construct packet with required fragments
- var encoded = type + ':' + id + (ack == 'data' ? '+' : '') + ':' + endpoint;
- // data fragment is optional
- if (data !== null && data !== undefined)
- encoded += ':' + data;
- return encoded;
- };
- /**
- * 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]*)?/;
- /**
- * Wrap the JSON.parse in a seperate function the crankshaft optimizer will
- * only punish this function for the usage for try catch
- *
- * @api private
- */
- function parse (data) {
- try { return JSON.parse(data) }
- catch (e) { return false }
- }
- 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
- switch (packet.type) {
- case 'message':
- packet.data = data || '';
- break;
- case 'event':
- pieces = parse(data);
- if (pieces) {
- packet.name = pieces.name;
- packet.args = pieces.args;
- }
- packet.args = packet.args || [];
- break;
- case 'json':
- packet.data = parse(data);
- break;
- case 'connect':
- packet.qs = data || '';
- break;
- case 'ack':
- pieces = data.match(/^([0-9]+)(\+)?(.*)/);
- if (pieces) {
- packet.ackId = pieces[1];
- packet.args = [];
- if (pieces[3]) {
- packet.args = parse(pieces[3]) || [];
- }
- }
- break;
- case 'error':
- pieces = data.split('+');
- packet.reason = reasonslist[pieces[0]] || '';
- packet.advice = advicelist[pieces[1]] || '';
- }
- 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, length)));
- i += Number(length) + 1;
- length = '';
- } else {
- length += data[i];
- }
- }
- return ret;
- } else {
- return [exports.decodePacket(data)];
- }
- };
|