@jonaskello-forks/amqp-client
Version:
AMQP 0-9-1 client, both for browsers (WebSocket) and node (TCP Socket)
470 lines • 16.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AMQPView = void 0;
class AMQPView extends DataView {
getUint64(byteOffset, littleEndian) {
const left = this.getUint32(byteOffset, littleEndian);
const right = this.getUint32(byteOffset + 4, littleEndian);
const combined = littleEndian ? left + 2 ** 32 * right : 2 ** 32 * left + right;
if (!Number.isSafeInteger(combined))
console.warn(combined, 'exceeds MAX_SAFE_INTEGER. Precision may be lost');
return combined;
}
setUint64(byteOffset, value, littleEndian) {
this.setBigUint64(byteOffset, BigInt(value), littleEndian);
}
getInt64(byteOffset, littleEndian) {
return Number(this.getBigInt64(byteOffset, littleEndian));
}
setInt64(byteOffset, value, littleEndian) {
this.setBigInt64(byteOffset, BigInt(value), littleEndian);
}
getShortString(byteOffset) {
const len = this.getUint8(byteOffset);
byteOffset += 1;
if (typeof Buffer !== "undefined") {
const text = Buffer.from(this.buffer, this.byteOffset + byteOffset, len).toString();
return [text, len + 1];
}
else {
const view = new Uint8Array(this.buffer, this.byteOffset + byteOffset, len);
const text = AMQPView.decoder.decode(view);
return [text, len + 1];
}
}
setShortString(byteOffset, string) {
if (typeof Buffer !== "undefined") {
const len = Buffer.byteLength(string);
if (len > 255)
throw new Error(`Short string too long, ${len} bytes: ${string.substring(0, 255)}...`);
this.setUint8(byteOffset, len);
byteOffset += 1;
Buffer.from(this.buffer, this.byteOffset + byteOffset, len).write(string);
return len + 1;
}
else {
const utf8 = AMQPView.encoder.encode(string);
const len = utf8.byteLength;
if (len > 255)
throw new Error(`Short string too long, ${len} bytes: ${string.substring(0, 255)}...`);
this.setUint8(byteOffset, len);
byteOffset += 1;
const view = new Uint8Array(this.buffer, this.byteOffset + byteOffset);
view.set(utf8);
return len + 1;
}
}
getLongString(byteOffset, littleEndian) {
const len = this.getUint32(byteOffset, littleEndian);
byteOffset += 4;
if (typeof Buffer !== "undefined") {
const text = Buffer.from(this.buffer, this.byteOffset + byteOffset, len).toString();
return [text, len + 4];
}
else {
const view = new Uint8Array(this.buffer, this.byteOffset + byteOffset, len);
const text = AMQPView.decoder.decode(view);
return [text, len + 4];
}
}
setLongString(byteOffset, string, littleEndian) {
if (typeof Buffer !== "undefined") {
const len = Buffer.byteLength(string);
this.setUint32(byteOffset, len, littleEndian);
byteOffset += 4;
Buffer.from(this.buffer, this.byteOffset + byteOffset, len).write(string);
return len + 4;
}
else {
const utf8 = AMQPView.encoder.encode(string);
const len = utf8.byteLength;
this.setUint32(byteOffset, len, littleEndian);
byteOffset += 4;
const view = new Uint8Array(this.buffer, this.byteOffset + byteOffset);
view.set(utf8);
return len + 4;
}
}
getProperties(byteOffset, littleEndian) {
let j = byteOffset;
const flags = this.getUint16(j, littleEndian);
j += 2;
const props = {};
if ((flags & 0x8000) > 0) {
const [contentType, len] = this.getShortString(j);
j += len;
props.contentType = contentType;
}
if ((flags & 0x4000) > 0) {
const [contentEncoding, len] = this.getShortString(j);
j += len;
props.contentEncoding = contentEncoding;
}
if ((flags & 0x2000) > 0) {
const [headers, len] = this.getTable(j, littleEndian);
j += len;
props.headers = headers;
}
if ((flags & 0x1000) > 0) {
props.deliveryMode = this.getUint8(j);
j += 1;
}
if ((flags & 0x0800) > 0) {
props.priority = this.getUint8(j);
j += 1;
}
if ((flags & 0x0400) > 0) {
const [correlationId, len] = this.getShortString(j);
j += len;
props.correlationId = correlationId;
}
if ((flags & 0x0200) > 0) {
const [replyTo, len] = this.getShortString(j);
j += len;
props.replyTo = replyTo;
}
if ((flags & 0x0100) > 0) {
const [expiration, len] = this.getShortString(j);
j += len;
props.expiration = expiration;
}
if ((flags & 0x0080) > 0) {
const [messageId, len] = this.getShortString(j);
j += len;
props.messageId = messageId;
}
if ((flags & 0x0040) > 0) {
props.timestamp = new Date(this.getInt64(j, littleEndian) * 1000);
j += 8;
}
if ((flags & 0x0020) > 0) {
const [type, len] = this.getShortString(j);
j += len;
props.type = type;
}
if ((flags & 0x0010) > 0) {
const [userId, len] = this.getShortString(j);
j += len;
props.userId = userId;
}
if ((flags & 0x0008) > 0) {
const [appId, len] = this.getShortString(j);
j += len;
props.appId = appId;
}
const len = j - byteOffset;
return [props, len];
}
setProperties(byteOffset, properties, littleEndian) {
let j = byteOffset;
let flags = 0;
if (properties.contentType)
flags = flags | 0x8000;
if (properties.contentEncoding)
flags = flags | 0x4000;
if (properties.headers)
flags = flags | 0x2000;
if (properties.deliveryMode)
flags = flags | 0x1000;
if (properties.priority)
flags = flags | 0x0800;
if (properties.correlationId)
flags = flags | 0x0400;
if (properties.replyTo)
flags = flags | 0x0200;
if (properties.expiration)
flags = flags | 0x0100;
if (properties.messageId)
flags = flags | 0x0080;
if (properties.timestamp)
flags = flags | 0x0040;
if (properties.type)
flags = flags | 0x0020;
if (properties.userId)
flags = flags | 0x0010;
if (properties.appId)
flags = flags | 0x0008;
this.setUint16(j, flags, littleEndian);
j += 2;
if (properties.contentType) {
j += this.setShortString(j, properties.contentType);
}
if (properties.contentEncoding) {
j += this.setShortString(j, properties.contentEncoding);
}
if (properties.headers) {
j += this.setTable(j, properties.headers);
}
if (properties.deliveryMode) {
this.setUint8(j, properties.deliveryMode);
j += 1;
}
if (properties.priority) {
this.setUint8(j, properties.priority);
j += 1;
}
if (properties.correlationId) {
j += this.setShortString(j, properties.correlationId);
}
if (properties.replyTo) {
j += this.setShortString(j, properties.replyTo);
}
if (properties.expiration) {
j += this.setShortString(j, properties.expiration);
}
if (properties.messageId) {
j += this.setShortString(j, properties.messageId);
}
if (properties.timestamp) {
const unixEpoch = Math.floor(Number(properties.timestamp) / 1000);
this.setInt64(j, unixEpoch, littleEndian);
j += 8;
}
if (properties.type) {
j += this.setShortString(j, properties.type);
}
if (properties.userId) {
j += this.setShortString(j, properties.userId);
}
if (properties.appId) {
j += this.setShortString(j, properties.appId);
}
const len = j - byteOffset;
return len;
}
getTable(byteOffset, littleEndian) {
const table = {};
let i = byteOffset;
const len = this.getUint32(byteOffset, littleEndian);
i += 4;
for (; i < byteOffset + 4 + len;) {
const [k, strLen] = this.getShortString(i);
i += strLen;
const [v, vLen] = this.getField(i, littleEndian);
i += vLen;
table[k] = v;
}
return [table, len + 4];
}
setTable(byteOffset, table, littleEndian) {
let i = byteOffset + 4;
for (const [key, value] of Object.entries(table)) {
if (value === undefined)
continue;
i += this.setShortString(i, key);
i += this.setField(i, value, littleEndian);
}
this.setUint32(byteOffset, i - byteOffset - 4, littleEndian);
return i - byteOffset;
}
getField(byteOffset, littleEndian) {
let i = byteOffset;
const k = this.getUint8(i);
i += 1;
const type = String.fromCharCode(k);
let v;
let len;
switch (type) {
case 't':
v = this.getUint8(i) === 1;
i += 1;
break;
case 'b':
v = this.getInt8(i);
i += 1;
break;
case 'B':
v = this.getUint8(i);
i += 1;
break;
case 's':
v = this.getInt16(i, littleEndian);
i += 2;
break;
case 'u':
v = this.getUint16(i, littleEndian);
i += 2;
break;
case 'I':
v = this.getInt32(i, littleEndian);
i += 4;
break;
case 'i':
v = this.getUint32(i, littleEndian);
i += 4;
break;
case 'l':
v = this.getInt64(i, littleEndian);
i += 8;
break;
case 'f':
v = this.getFloat32(i, littleEndian);
i += 4;
break;
case 'd':
v = this.getFloat64(i, littleEndian);
i += 8;
break;
case 'S':
[v, len] = this.getLongString(i, littleEndian);
i += len;
break;
case 'F':
[v, len] = this.getTable(i, littleEndian);
i += len;
break;
case 'A':
[v, len] = this.getArray(i, littleEndian);
i += len;
break;
case 'x':
[v, len] = this.getByteArray(i, littleEndian);
i += len;
break;
case 'T':
v = new Date(this.getInt64(i, littleEndian) * 1000);
i += 8;
break;
case 'V':
v = null;
break;
case 'D': {
const scale = this.getUint8(i);
i += 1;
const value = this.getUint32(i, littleEndian);
i += 4;
v = value / 10 ** scale;
break;
}
default:
throw `Field type '${k}' not supported`;
}
return [v, i - byteOffset];
}
setField(byteOffset, field, littleEndian) {
let i = byteOffset;
switch (typeof field) {
case "string":
this.setUint8(i, 'S'.charCodeAt(0));
i += 1;
i += this.setLongString(i, field, littleEndian);
break;
case "boolean":
this.setUint8(i, 't'.charCodeAt(0));
i += 1;
this.setUint8(i, field ? 1 : 0);
i += 1;
break;
case "bigint":
this.setUint8(i, 'l'.charCodeAt(0));
i += 1;
this.setBigInt64(i, field, littleEndian);
i += 8;
break;
case "number":
if (Number.isInteger(field)) {
if (-(2 ** 32) < field && field < 2 ** 32) {
this.setUint8(i, 'I'.charCodeAt(0));
i += 1;
this.setInt32(i, field, littleEndian);
i += 4;
}
else {
this.setUint8(i, 'l'.charCodeAt(0));
i += 1;
this.setInt64(i, field, littleEndian);
i += 8;
}
}
else {
if (-(2 ** 32) < field && field < 2 ** 32) {
this.setUint8(i, 'f'.charCodeAt(0));
i += 1;
this.setFloat32(i, field, littleEndian);
i += 4;
}
else {
this.setUint8(i, 'd'.charCodeAt(0));
i += 1;
this.setFloat64(i, field, littleEndian);
i += 8;
}
}
break;
case "object":
if (Array.isArray(field)) {
this.setUint8(i, 'A'.charCodeAt(0));
i += 1;
i += this.setArray(i, field, littleEndian);
}
else if (field instanceof Uint8Array) {
this.setUint8(i, 'x'.charCodeAt(0));
i += 1;
i += this.setByteArray(i, field);
}
else if (field instanceof ArrayBuffer) {
this.setUint8(i, 'x'.charCodeAt(0));
i += 1;
i += this.setByteArray(i, new Uint8Array(field));
}
else if (field instanceof Date) {
this.setUint8(i, 'T'.charCodeAt(0));
i += 1;
const unixEpoch = Math.floor(Number(field) / 1000);
this.setInt64(i, unixEpoch, littleEndian);
i += 8;
}
else if (field === null || field === undefined) {
this.setUint8(i, 'V'.charCodeAt(0));
i += 1;
}
else {
this.setUint8(i, 'F'.charCodeAt(0));
i += 1;
i += this.setTable(i, field, littleEndian);
}
break;
default:
throw `Unsupported field type '${field}'`;
}
return i - byteOffset;
}
getArray(byteOffset, littleEndian) {
const len = this.getUint32(byteOffset, littleEndian);
byteOffset += 4;
const endOffset = byteOffset + len;
const v = [];
for (; byteOffset < endOffset;) {
const [field, fieldLen] = this.getField(byteOffset, littleEndian);
byteOffset += fieldLen;
v.push(field);
}
return [v, len + 4];
}
setArray(byteOffset, array, littleEndian) {
const start = byteOffset;
byteOffset += 4;
array.forEach((e) => {
byteOffset += this.setField(byteOffset, e, littleEndian);
});
this.setUint32(start, byteOffset - start - 4, littleEndian);
return byteOffset - start;
}
getByteArray(byteOffset, littleEndian) {
const len = this.getUint32(byteOffset, littleEndian);
byteOffset += 4;
const v = new Uint8Array(this.buffer, this.byteOffset + byteOffset, len);
return [v, len + 4];
}
setByteArray(byteOffset, data, littleEndian) {
this.setUint32(byteOffset, data.byteLength, littleEndian);
byteOffset += 4;
const view = new Uint8Array(this.buffer, this.byteOffset + byteOffset, data.byteLength);
view.set(data);
return data.byteLength + 4;
}
}
exports.AMQPView = AMQPView;
AMQPView.decoder = new TextDecoder();
AMQPView.encoder = new TextEncoder();
//# sourceMappingURL=amqp-view.js.map