UNPKG

diffusion

Version:

Diffusion JavaScript client

194 lines (164 loc) 5.18 kB
/*eslint valid-jsdoc: "off"*/ var inherits = require('inherits'); var BufferOutputStream = require('io/buffer-output-stream'); var BufferInputStream = require('io/buffer-input-stream'); var MessageEncoding = require('util/message-encoding'); var EncodingType = require('util/message-encoding').EncodingType; var logger = require('util/logger').create('Message'); var ClientCapabilities = require('protocol/consts').CAPABILITIES; var Zlib; if (ClientCapabilities === 10) { Zlib = require('util/zlib-decompression'); } else { logger.warn("Per message compression is disabled because 'zlib' bundle is not included"); Zlib = null; } var systemHeaders = { 0: [], 1: [], 2: [], 4: [], 5: [], 28: [], 29: [], 34: ['topic'], }; var types = { SERVICE_REQUEST: 0, SERVICE_RESPONSE: 1, SERVICE_ERROR: 2, TOPIC_VALUE: 4, TOPIC_DELTA: 5, ABORT_NOTIFICATION: 28, CLOSE_REQUEST: 29, FETCH_REPLY: 34, }; var encoding = { NONE: 0, ENCRYPTION_REQUESTED: 1, COMPRESSION_REQUESTED: 2, BASE64_REQUESTED: 3, ENCRYPTED: 17, COMPRESSED: 18, BASE64: 19 }; var parse = function (buffer, callback) { var bis = new BufferInputStream(buffer); var typeAndEncoding = bis.read(); var type = MessageEncoding.extractMessageType(typeAndEncoding); var encodingType = MessageEncoding.extractMessageEncoding(typeAndEncoding); if (systemHeaders[type] === undefined) { callback(new Error('Invalid message type: ' + type), null); } if (type === types.SERVICE_REQUEST || type === types.SERVICE_RESPONSE || type === types.SERVICE_ERROR) { callback(null, parseServiceMessage(type, bis)); } else if (type === types.TOPIC_VALUE || type === types.TOPIC_DELTA) { parseClientTopicMessage(type, encodingType, bis, callback); } else { var headers = bis.readUntil(0x01).toString().split('\u0002'); var body = bis.readMany(bis.count); var fields = {}; if (systemHeaders[type]) { systemHeaders[type].forEach(function (key) { fields[key] = headers.shift(); }); } callback(null, new Message(type, encoding.NONE, fields, body, headers)); } }; function parseServiceMessage(type, bis) { var headers = []; var body = bis.readMany(bis.count); var fields = {}; return new Message(type, encoding.NONE, fields, body, headers); } function parseClientTopicMessage(type, encodingType, bis, callback) { var headers = []; var fields = { 'id': bis.readInt32() }; if (encodingType === EncodingType.ZLIB && Zlib !== null) { try { var bytes = Zlib.decompressSync(bis.readMany(bis.count)); callback(null, new Message(type, encoding.COMPRESSED, fields, bytes, headers)); } catch(error) { callback(error, null); } } else { callback(null, new Message(type, encoding.NONE, fields, bis.readMany(bis.count), headers)); } } /** * Create a writeable Message. * * The returned value inherits functionality from BufferOutputStream. * * @param {Number|Object} - Provide a number to specify a message type; use an object to provide fields * @returns {Message} The created message */ var create = function (type) { var fields; if (type === undefined || (typeof type === "number" && systemHeaders[type] === undefined)) { throw "Invalid message type: " + type; } else if (type instanceof Object) { fields = type; } else { fields = {type: type}; } fields.encoding = fields.encoding || 0; fields.headers = fields.headers || []; fields.buffer = fields.buffer || new Buffer(0); return new WriteableMessage(fields); }; var getHeaderString = function (message) { var sh = []; var headers = ''; systemHeaders[message.type].forEach(function (h) { sh.push(message[h]); }); message.headers.forEach(function (h) { sh.push(h); }); // CLOSE_REQUEST has no header or body if (systemHeaders[message.type].length === 0) { return headers; } if (sh.length > 0) { headers = sh.join('\u0002'); headers += '\u0001'; } return headers; }; function writeToBuffer(message, bos) { bos.write(message.type); bos.writeString(getHeaderString(message)); bos.writeMany(message.getBuffer()); } function WriteableMessage(fields) { Message.call(this, fields.type, fields.encoding, fields, fields.buffer, fields.headers); BufferOutputStream.call(this, fields.buffer); } inherits(WriteableMessage, BufferOutputStream); function Message(type, encoding, fields, data, headers) { this.type = type; this.encoding = encoding; for (var f in fields) { this[f] = fields[f]; } this.data = data; this.headers = headers; } Message.prototype.getInputStream = function () { return new BufferInputStream(this.data); }; module.exports = { types: types, parse: parse, create: create, encoding: encoding, getHeaderString: getHeaderString, writeToBuffer: writeToBuffer };