UNPKG

diffusion

Version:

Diffusion JavaScript client

248 lines (247 loc) 9.21 kB
"use strict"; /** * @module V4Stack */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.writeToBuffer = exports.create = exports.parse = exports.WriteableMessage = exports.Message = exports.encoding = exports.types = void 0; var errors_1 = require("./../../errors/errors"); var buffer_input_stream_1 = require("./../io/buffer-input-stream"); var buffer_output_stream_1 = require("./../io/buffer-output-stream"); var consts_1 = require("./../protocol/consts"); var Logger = require("./../util/logger"); var message_encoding_1 = require("./../util/message-encoding"); var object_1 = require("./../util/object"); var logger = Logger.create('Message'); var zlib; if (consts_1.PROTOCOL.CAPABILITIES === 10) { /* tslint:disable-next-line:no-var-requires */ zlib = require('../util/zlib-decompression'); } else { logger.warn('Per message compression is disabled because \'zlib\' bundle is not included'); zlib = null; } /** * Message types */ // eslint-disable-next-line @typescript-eslint/naming-convention var types; (function (types) { types[types["SERVICE_REQUEST"] = 0] = "SERVICE_REQUEST"; types[types["SERVICE_RESPONSE"] = 6] = "SERVICE_RESPONSE"; types[types["SERVICE_ERROR"] = 7] = "SERVICE_ERROR"; types[types["TOPIC_VALUE"] = 4] = "TOPIC_VALUE"; types[types["TOPIC_DELTA"] = 5] = "TOPIC_DELTA"; types[types["ABORT_NOTIFICATION"] = 28] = "ABORT_NOTIFICATION"; types[types["CLOSE_REQUEST"] = 29] = "CLOSE_REQUEST"; types[types["FETCH_REPLY"] = 34] = "FETCH_REPLY"; })(types = exports.types || (exports.types = {})); /** * Message encodings */ // eslint-disable-next-line @typescript-eslint/naming-convention var encoding; (function (encoding) { encoding[encoding["NONE"] = 0] = "NONE"; encoding[encoding["ENCRYPTION_REQUESTED"] = 1] = "ENCRYPTION_REQUESTED"; encoding[encoding["COMPRESSION_REQUESTED"] = 2] = "COMPRESSION_REQUESTED"; encoding[encoding["BASE64_REQUESTED"] = 3] = "BASE64_REQUESTED"; encoding[encoding["ENCRYPTED"] = 17] = "ENCRYPTED"; encoding[encoding["COMPRESSED"] = 18] = "COMPRESSED"; encoding[encoding["BASE64"] = 19] = "BASE64"; })(encoding = exports.encoding || (exports.encoding = {})); /** * Basic message type */ var Message = /** @class */ (function () { /** * Create a new message * * @param type the message type * @param encoding the message encoding * @param fields optional message fields * @param data the message's data * @param headers additional message headers */ function Message(type, msgEncoding, fields, data, headers) { this.type = type; this.encoding = msgEncoding; this.id = fields.id; this.topic = fields.topic; this.data = data; this.headers = headers; } /** * Create an input stream from the message's data * * @return an input stream that can be deserialised */ Message.prototype.getInputStream = function () { return new buffer_input_stream_1.BufferInputStream(this.data); }; return Message; }()); exports.Message = Message; /** * A writable message that can be serialised into a {@link BufferOutputStream} */ var WriteableMessage = /** @class */ (function (_super) { __extends(WriteableMessage, _super); /** * Create a writeable message * * @param the message fields in an object */ function WriteableMessage(fields) { var _this = _super.call(this, fields.type, fields.encoding, fields, fields.buffer, fields.headers) || this; _this.stream = new buffer_output_stream_1.BufferOutputStream(fields.buffer); return _this; } /** * Get the output stream * * @return the output stream that writes into the message's data buffer */ WriteableMessage.prototype.getStream = function () { return this.stream; }; /** * Get the buffer * * @return the buffer that the output has been written into */ WriteableMessage.prototype.getBuffer = function () { return this.stream.getBuffer(); }; return WriteableMessage; }(Message)); exports.WriteableMessage = WriteableMessage; /** * Parse a message from a buffer * * @param buffer the buffer to parse * @param callback a callback that is called when the message has been parsed * or an error has occurred. */ function parse(buffer, callback) { var bis = new buffer_input_stream_1.BufferInputStream(buffer); var typeAndEncoding = bis.read(); var type = message_encoding_1.MessageEncoding.extractMessageType(typeAndEncoding); var encodingType = message_encoding_1.MessageEncoding.extractMessageEncoding(typeAndEncoding); /* tslint:disable-next-line:strict-type-predicates */ if (types[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 topic = (type === types.FETCH_REPLY) ? headers.shift() : undefined; callback(null, new Message(type, encoding.NONE, { topic: topic }, body, headers)); } } exports.parse = parse; /** * Helper function to create a service message * * @param type the message type to create * @param bis the buffer that is passed into the {@link Message.data} property * of the message * @return the newly constructed message */ function parseServiceMessage(type, bis) { var body = bis.readMany(bis.count); return new Message(type, encoding.NONE, {}, body, []); } /** * Helper function to create a client topic message * * @param type the message type to create * @param encodingType the message encoding * @param bis the buffer that is passed into the {@link Message.data} property * @param callback a callback that is called when the message has been parsed * or an error has occurred. */ function parseClientTopicMessage(type, encodingType, bis, callback) { var headers = []; var fields = { id: bis.readInt32() }; if (encodingType === message_encoding_1.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. * * @param type provide a number to specify a message type; use an object to provide fields * @return the created message */ function create(type) { var fields; /* tslint:disable-next-line:strict-type-predicates */ if (type === undefined || (typeof type === 'number' && types[type] === undefined)) { throw new errors_1.InternalError("Invalid message type: " + type); } else if (object_1.isObjectAs(type)) { fields = type; } else { fields = { type: type }; } fields.encoding = fields.encoding || 0; fields.headers = fields.headers || []; fields.buffer = fields.buffer || new Uint8Array(0); return new WriteableMessage(fields); } exports.create = create; /** * Construct a header string * * @param message the message from which to construct the header string * @return the string to be serialised in the header */ function getHeaderString(message) { if (message.type !== types.FETCH_REPLY) { return ''; } var sh = [message.topic].concat(message.headers); return sh.join('\u0002') + '\u0001'; } /** * Serialise a message into a buffer * * @param message the message to write * @param bos the buffer to write into */ function writeToBuffer(message, bos) { bos.write(message.type); bos.writeString(getHeaderString(message)); bos.writeMany(message.getBuffer()); } exports.writeToBuffer = writeToBuffer;