backendless-rt-client
Version:
Backendless RT Client for connect to Backendless RT Server
180 lines (159 loc) • 3.79 kB
JavaScript
;
/* eslint-disable */
/**
* Since JS Clients don't use binary data through sockets
* we do not need to use socket.io-parser module inside the socket.io-client
*
* The custom SocketIO Parser is based on both modules:
* - socket.io-json-parser
* - socket.io-parser
*/
var Emitter = require('component-emitter');
exports.protocol = 4;
exports.types = ['CONNECT', 'DISCONNECT', 'EVENT', 'ACK', 'ERROR', 'BINARY_EVENT', 'BINARY_ACK'];
exports.CONNECT = 0;
exports.DISCONNECT = 1;
exports.EVENT = 2;
exports.ACK = 3;
exports.ERROR = 4;
exports.BINARY_EVENT = 5;
exports.BINARY_ACK = 6;
exports.Encoder = Encoder;
exports.Decoder = Decoder;
function Encoder() {}
/**
* Encode a packet as a single string if non-binary, or as a
* buffer sequence, depending on packet type.
*
* @param {Object} obj - packet object
* @param {Function} callback - function to handle encodings (likely engine.write)
* @return Calls callback with Array of encodings
* @api public
*/
Encoder.prototype.encode = function (obj, callback) {
callback([encodeAsString(obj)]);
};
/**
* Encode packet as string.
*
* @param {Object} packet
* @return {String} encoded
* @api private
*/
function encodeAsString(obj) {
// first is type
var str = '' + obj.type;
// attachments if we have them
if (exports.BINARY_EVENT === obj.type || exports.BINARY_ACK === obj.type) {
str += obj.attachments + '-';
}
// if we have a namespace other than `/`
// we append it followed by a comma `,`
if (obj.nsp && '/' !== obj.nsp) {
str += obj.nsp + ',';
}
// immediately followed by the id
if (null != obj.id) {
str += obj.id;
}
// json data
if (null != obj.data) {
str += JSON.stringify(obj.data);
}
return str;
}
function Decoder() {}
Emitter(Decoder.prototype);
/**
* Decodes an ecoded packet string into packet JSON.
*
* @param {String} obj - encoded packet
* @return {Object} packet
* @api public
*/
Decoder.prototype.add = function (obj) {
if (typeof obj === 'string') {
this.emit('decoded', decodeString(obj));
} else {
throw new Error('Unknown type: ' + obj);
}
};
/**
* Decode a packet String (JSON data)
*
* @param {String} str
* @return {Object} packet
* @api private
*/
function decodeString(str) {
var i = 0;
// look up type
var p = {
type: Number(str.charAt(0))
};
if (null == exports.types[p.type]) return error();
// look up attachments if type binary
if (exports.BINARY_EVENT === p.type || exports.BINARY_ACK === p.type) {
var buf = '';
while (str.charAt(++i) !== '-') {
buf += str.charAt(i);
if (i == str.length) break;
}
if (buf != Number(buf) || str.charAt(i) !== '-') {
throw new Error('Illegal attachments');
}
p.attachments = Number(buf);
}
// look up namespace (if any)
if ('/' === str.charAt(i + 1)) {
p.nsp = '';
while (++i) {
var c = str.charAt(i);
if (',' === c) break;
p.nsp += c;
if (i === str.length) break;
}
} else {
p.nsp = '/';
}
// look up id
var next = str.charAt(i + 1);
if ('' !== next && Number(next) == next) {
p.id = '';
while (++i) {
var c = str.charAt(i);
if (null == c || Number(c) != c) {
--i;
break;
}
p.id += str.charAt(i);
if (i === str.length) break;
}
p.id = Number(p.id);
}
// look up json data
if (str.charAt(++i)) {
p = tryParse(p, str.substr(i));
}
return p;
}
function tryParse(p, str) {
try {
p.data = JSON.parse(str);
} catch (e) {
return error();
}
return p;
}
/**
* Deallocates a parser's resources
*
* @api public
*/
Decoder.prototype.destroy = function () {};
function error() {
return {
type: exports.ERROR,
data: 'parser error'
};
}