UNPKG

@cloudamqp/amqp-client

Version:

AMQP 0-9-1 client, both for browsers (WebSocket) and node (TCP Socket)

825 lines 26.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AMQPChannel = void 0; const amqp_error_js_1 = require("./amqp-error.js"); const amqp_view_js_1 = require("./amqp-view.js"); const amqp_queue_js_1 = require("./amqp-queue.js"); const amqp_consumer_js_1 = require("./amqp-consumer.js"); class AMQPChannel { constructor(connection, id) { this.consumers = new Map(); this.rpcQueue = Promise.resolve(true); this.unconfirmedPublishes = []; this.closed = false; this.confirmId = 0; this.connection = connection; this.id = id; this.onerror = (reason) => this.logger?.error(`channel ${this.id} closed: ${reason}`); } get logger() { return this.connection.logger; } open() { let j = 0; const channelOpen = new amqp_view_js_1.AMQPView(new ArrayBuffer(13)); channelOpen.setUint8(j, 1); j += 1; channelOpen.setUint16(j, this.id); j += 2; channelOpen.setUint32(j, 5); j += 4; channelOpen.setUint16(j, 20); j += 2; channelOpen.setUint16(j, 10); j += 2; channelOpen.setUint8(j, 0); j += 1; channelOpen.setUint8(j, 206); j += 1; return this.sendRpc(channelOpen, j); } queue(name = "", { passive = false, durable = name !== "", autoDelete = name === "", exclusive = name === "" } = {}, args = {}) { return new Promise((resolve, reject) => { this.queueDeclare(name, { passive, durable, autoDelete, exclusive }, args) .then(({ name }) => resolve(new amqp_queue_js_1.AMQPQueue(this, name))) .catch(reject); }); } prefetch(prefetchCount) { return this.basicQos(prefetchCount); } onReturn(message) { this.logger?.error("Message returned from server", message); } close(reason = "", code = 200) { if (this.closed) return this.rejectClosed(); this.closed = true; let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(512)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 0); j += 4; frame.setUint16(j, 20); j += 2; frame.setUint16(j, 40); j += 2; frame.setUint16(j, code); j += 2; j += frame.setShortString(j, reason); frame.setUint16(j, 0); j += 2; frame.setUint16(j, 0); j += 2; frame.setUint8(j, 206); j += 1; frame.setUint32(3, j - 8); return this.sendRpc(frame, j); } basicGet(queue, { noAck = true } = {}) { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(512)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 11); j += 4; frame.setUint16(j, 60); j += 2; frame.setUint16(j, 70); j += 2; frame.setUint16(j, 0); j += 2; j += frame.setShortString(j, queue); frame.setUint8(j, noAck ? 1 : 0); j += 1; frame.setUint8(j, 206); j += 1; frame.setUint32(3, j - 8); return this.sendRpc(frame, j); } basicConsume(queue, { tag = "", noAck = true, exclusive = false, args = {} } = {}, callback) { if (this.closed) return this.rejectClosed(); let j = 0; const noWait = false; const noLocal = false; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(4096)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 0); j += 4; frame.setUint16(j, 60); j += 2; frame.setUint16(j, 20); j += 2; frame.setUint16(j, 0); j += 2; j += frame.setShortString(j, queue); j += frame.setShortString(j, tag); let bits = 0; if (noLocal) bits = bits | (1 << 0); if (noAck) bits = bits | (1 << 1); if (exclusive) bits = bits | (1 << 2); if (noWait) bits = bits | (1 << 3); frame.setUint8(j, bits); j += 1; j += frame.setTable(j, args); frame.setUint8(j, 206); j += 1; frame.setUint32(3, j - 8); return new Promise((resolve, reject) => { this.sendRpc(frame, j).then((consumerTag) => { const consumer = new amqp_consumer_js_1.AMQPConsumer(this, consumerTag, callback); this.consumers.set(consumerTag, consumer); resolve(consumer); }).catch(reject); }); } basicCancel(tag) { if (this.closed) return this.rejectClosed(); const noWait = false; let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(512)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 0); j += 4; frame.setUint16(j, 60); j += 2; frame.setUint16(j, 30); j += 2; j += frame.setShortString(j, tag); frame.setUint8(j, noWait ? 1 : 0); j += 1; frame.setUint8(j, 206); j += 1; frame.setUint32(3, j - 8); return new Promise((resolve, reject) => { this.sendRpc(frame, j).then((consumerTag) => { const consumer = this.consumers.get(consumerTag); if (consumer) { consumer.setClosed(); this.consumers.delete(consumerTag); } resolve(this); }).catch(reject); }); } basicAck(deliveryTag, multiple = false) { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(21)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 13); j += 4; frame.setUint16(j, 60); j += 2; frame.setUint16(j, 80); j += 2; frame.setUint64(j, deliveryTag); j += 8; frame.setUint8(j, multiple ? 1 : 0); j += 1; frame.setUint8(j, 206); j += 1; return this.connection.send(new Uint8Array(frame.buffer, 0, 21)); } basicNack(deliveryTag, requeue = false, multiple = false) { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(21)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 13); j += 4; frame.setUint16(j, 60); j += 2; frame.setUint16(j, 120); j += 2; frame.setUint64(j, deliveryTag); j += 8; let bits = 0; if (multiple) bits = bits | (1 << 0); if (requeue) bits = bits | (1 << 1); frame.setUint8(j, bits); j += 1; frame.setUint8(j, 206); j += 1; return this.connection.send(new Uint8Array(frame.buffer, 0, 21)); } basicReject(deliveryTag, requeue = false) { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(21)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 13); j += 4; frame.setUint16(j, 60); j += 2; frame.setUint16(j, 90); j += 2; frame.setUint64(j, deliveryTag); j += 8; frame.setUint8(j, requeue ? 1 : 0); j += 1; frame.setUint8(j, 206); j += 1; return this.connection.send(new Uint8Array(frame.buffer, 0, 21)); } basicRecover(requeue = false) { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(13)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 5); j += 4; frame.setUint16(j, 60); j += 2; frame.setUint16(j, 110); j += 2; frame.setUint8(j, requeue ? 1 : 0); j += 1; frame.setUint8(j, 206); j += 1; return this.sendRpc(frame, j); } async basicPublish(exchange, routingKey, data, properties = {}, mandatory = false, immediate = false) { if (this.closed) return this.rejectClosed(); if (this.connection.blocked) return Promise.reject(new amqp_error_js_1.AMQPError(`Connection blocked by server: ${this.connection.blocked}`, this.connection)); let body; if (typeof Buffer !== "undefined" && data instanceof Buffer) { body = data; } else if (data instanceof Uint8Array) { body = data; } else if (data instanceof ArrayBuffer) { body = new Uint8Array(data); } else if (data === null) { body = new Uint8Array(0); } else if (typeof data === "string") { body = this.connection.textEncoder.encode(data); } else { throw new TypeError(`Invalid type ${typeof data} for parameter data`); } let j = 0; let buffer = this.connection.bufferPool.pop() || new amqp_view_js_1.AMQPView(new ArrayBuffer(this.connection.frameMax)); buffer.setUint8(j, 1); j += 1; buffer.setUint16(j, this.id); j += 2; j += 4; buffer.setUint16(j, 60); j += 2; buffer.setUint16(j, 40); j += 2; buffer.setUint16(j, 0); j += 2; j += buffer.setShortString(j, exchange); j += buffer.setShortString(j, routingKey); let bits = 0; if (mandatory) bits = bits | (1 << 0); if (immediate) bits = bits | (1 << 1); buffer.setUint8(j, bits); j += 1; buffer.setUint8(j, 206); j += 1; buffer.setUint32(3, j - 8); const headerStart = j; buffer.setUint8(j, 2); j += 1; buffer.setUint16(j, this.id); j += 2; j += 4; buffer.setUint16(j, 60); j += 2; buffer.setUint16(j, 0); j += 2; buffer.setUint32(j, 0); j += 4; buffer.setUint32(j, body.byteLength); j += 4; j += buffer.setProperties(j, properties); buffer.setUint8(j, 206); j += 1; buffer.setUint32(headerStart + 3, j - headerStart - 8); let bufferView = new Uint8Array(buffer.buffer); const bodyFrameCount = Math.ceil(body.byteLength / (this.connection.frameMax - 8)); const bufferSize = j + body.byteLength + 8 * bodyFrameCount; if (buffer.byteLength < bufferSize) { const newBuffer = new ArrayBuffer(bufferSize); const newBufferView = new Uint8Array(newBuffer); newBufferView.set(bufferView.subarray(0, j)); buffer = new amqp_view_js_1.AMQPView(newBuffer); bufferView = newBufferView; } for (let bodyPos = 0; bodyPos < body.byteLength;) { const frameSize = Math.min(body.byteLength - bodyPos, this.connection.frameMax - 8); const dataSlice = body.subarray(bodyPos, bodyPos + frameSize); buffer.setUint8(j, 3); j += 1; buffer.setUint16(j, this.id); j += 2; buffer.setUint32(j, frameSize); j += 4; bufferView.set(dataSlice, j); j += frameSize; buffer.setUint8(j, 206); j += 1; bodyPos += frameSize; } const sendFrames = this.connection.send(bufferView.subarray(0, j)); this.connection.bufferPool.push(buffer); if (this.confirmId) { const wait4Confirm = new Promise((resolve, reject) => this.unconfirmedPublishes.push([this.confirmId++, resolve, reject])); return sendFrames.then(() => wait4Confirm); } else { return sendFrames.then(() => 0); } } basicQos(prefetchCount, prefetchSize = 0, global = false) { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(19)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 11); j += 4; frame.setUint16(j, 60); j += 2; frame.setUint16(j, 10); j += 2; frame.setUint32(j, prefetchSize); j += 4; frame.setUint16(j, prefetchCount); j += 2; frame.setUint8(j, global ? 1 : 0); j += 1; frame.setUint8(j, 206); j += 1; return this.sendRpc(frame, j); } basicFlow(active = true) { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(13)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 5); j += 4; frame.setUint16(j, 20); j += 2; frame.setUint16(j, 20); j += 2; frame.setUint8(j, active ? 1 : 0); j += 1; frame.setUint8(j, 206); j += 1; return this.sendRpc(frame, j); } confirmSelect() { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(13)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 5); j += 4; frame.setUint16(j, 85); j += 2; frame.setUint16(j, 10); j += 2; frame.setUint8(j, 0); j += 1; frame.setUint8(j, 206); j += 1; return this.sendRpc(frame, j); } queueDeclare(name = "", { passive = false, durable = name !== "", autoDelete = name === "", exclusive = name === "" } = {}, args = {}) { if (this.closed) return this.rejectClosed(); const noWait = false; let j = 0; const declare = new amqp_view_js_1.AMQPView(new ArrayBuffer(4096)); declare.setUint8(j, 1); j += 1; declare.setUint16(j, this.id); j += 2; declare.setUint32(j, 0); j += 4; declare.setUint16(j, 50); j += 2; declare.setUint16(j, 10); j += 2; declare.setUint16(j, 0); j += 2; j += declare.setShortString(j, name); let bits = 0; if (passive) bits = bits | (1 << 0); if (durable) bits = bits | (1 << 1); if (exclusive) bits = bits | (1 << 2); if (autoDelete) bits = bits | (1 << 3); if (noWait) bits = bits | (1 << 4); declare.setUint8(j, bits); j += 1; j += declare.setTable(j, args); declare.setUint8(j, 206); j += 1; declare.setUint32(3, j - 8); return this.sendRpc(declare, j); } queueDelete(name = "", { ifUnused = false, ifEmpty = false } = {}) { if (this.closed) return this.rejectClosed(); const noWait = false; let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(512)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 0); j += 4; frame.setUint16(j, 50); j += 2; frame.setUint16(j, 40); j += 2; frame.setUint16(j, 0); j += 2; j += frame.setShortString(j, name); let bits = 0; if (ifUnused) bits = bits | (1 << 0); if (ifEmpty) bits = bits | (1 << 1); if (noWait) bits = bits | (1 << 2); frame.setUint8(j, bits); j += 1; frame.setUint8(j, 206); j += 1; frame.setUint32(3, j - 8); return this.sendRpc(frame, j); } queueBind(queue, exchange, routingKey, args = {}) { if (this.closed) return this.rejectClosed(); const noWait = false; let j = 0; const bind = new amqp_view_js_1.AMQPView(new ArrayBuffer(4096)); bind.setUint8(j, 1); j += 1; bind.setUint16(j, this.id); j += 2; bind.setUint32(j, 0); j += 4; bind.setUint16(j, 50); j += 2; bind.setUint16(j, 20); j += 2; bind.setUint16(j, 0); j += 2; j += bind.setShortString(j, queue); j += bind.setShortString(j, exchange); j += bind.setShortString(j, routingKey); bind.setUint8(j, noWait ? 1 : 0); j += 1; j += bind.setTable(j, args); bind.setUint8(j, 206); j += 1; bind.setUint32(3, j - 8); return this.sendRpc(bind, j); } queueUnbind(queue, exchange, routingKey, args = {}) { if (this.closed) return this.rejectClosed(); let j = 0; const unbind = new amqp_view_js_1.AMQPView(new ArrayBuffer(4096)); unbind.setUint8(j, 1); j += 1; unbind.setUint16(j, this.id); j += 2; unbind.setUint32(j, 0); j += 4; unbind.setUint16(j, 50); j += 2; unbind.setUint16(j, 50); j += 2; unbind.setUint16(j, 0); j += 2; j += unbind.setShortString(j, queue); j += unbind.setShortString(j, exchange); j += unbind.setShortString(j, routingKey); j += unbind.setTable(j, args); unbind.setUint8(j, 206); j += 1; unbind.setUint32(3, j - 8); return this.sendRpc(unbind, j); } queuePurge(queue) { if (this.closed) return this.rejectClosed(); const noWait = false; let j = 0; const purge = new amqp_view_js_1.AMQPView(new ArrayBuffer(512)); purge.setUint8(j, 1); j += 1; purge.setUint16(j, this.id); j += 2; purge.setUint32(j, 0); j += 4; purge.setUint16(j, 50); j += 2; purge.setUint16(j, 30); j += 2; purge.setUint16(j, 0); j += 2; j += purge.setShortString(j, queue); purge.setUint8(j, noWait ? 1 : 0); j += 1; purge.setUint8(j, 206); j += 1; purge.setUint32(3, j - 8); return this.sendRpc(purge, j); } exchangeDeclare(name, type, { passive = false, durable = true, autoDelete = false, internal = false } = {}, args = {}) { const noWait = false; let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(4096)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 0); j += 4; frame.setUint16(j, 40); j += 2; frame.setUint16(j, 10); j += 2; frame.setUint16(j, 0); j += 2; j += frame.setShortString(j, name); j += frame.setShortString(j, type); let bits = 0; if (passive) bits = bits | (1 << 0); if (durable) bits = bits | (1 << 1); if (autoDelete) bits = bits | (1 << 2); if (internal) bits = bits | (1 << 3); if (noWait) bits = bits | (1 << 4); frame.setUint8(j, bits); j += 1; j += frame.setTable(j, args); frame.setUint8(j, 206); j += 1; frame.setUint32(3, j - 8); return this.sendRpc(frame, j); } exchangeDelete(name, { ifUnused = false } = {}) { const noWait = false; let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(512)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 0); j += 4; frame.setUint16(j, 40); j += 2; frame.setUint16(j, 20); j += 2; frame.setUint16(j, 0); j += 2; j += frame.setShortString(j, name); let bits = 0; if (ifUnused) bits = bits | (1 << 0); if (noWait) bits = bits | (1 << 1); frame.setUint8(j, bits); j += 1; frame.setUint8(j, 206); j += 1; frame.setUint32(3, j - 8); return this.sendRpc(frame, j); } exchangeBind(destination, source, routingKey = "", args = {}) { if (this.closed) return this.rejectClosed(); let j = 0; const bind = new amqp_view_js_1.AMQPView(new ArrayBuffer(4096)); bind.setUint8(j, 1); j += 1; bind.setUint16(j, this.id); j += 2; bind.setUint32(j, 0); j += 4; bind.setUint16(j, 40); j += 2; bind.setUint16(j, 30); j += 2; bind.setUint16(j, 0); j += 2; j += bind.setShortString(j, destination); j += bind.setShortString(j, source); j += bind.setShortString(j, routingKey); bind.setUint8(j, 0); j += 1; j += bind.setTable(j, args); bind.setUint8(j, 206); j += 1; bind.setUint32(3, j - 8); return this.sendRpc(bind, j); } exchangeUnbind(destination, source, routingKey = "", args = {}) { if (this.closed) return this.rejectClosed(); let j = 0; const unbind = new amqp_view_js_1.AMQPView(new ArrayBuffer(4096)); unbind.setUint8(j, 1); j += 1; unbind.setUint16(j, this.id); j += 2; unbind.setUint32(j, 0); j += 4; unbind.setUint16(j, 40); j += 2; unbind.setUint16(j, 40); j += 2; unbind.setUint16(j, 0); j += 2; j += unbind.setShortString(j, destination); j += unbind.setShortString(j, source); j += unbind.setShortString(j, routingKey); unbind.setUint8(j, 0); j += 1; j += unbind.setTable(j, args); unbind.setUint8(j, 206); j += 1; unbind.setUint32(3, j - 8); return this.sendRpc(unbind, j); } txSelect() { return this.txMethod(10); } txCommit() { return this.txMethod(20); } txRollback() { return this.txMethod(30); } txMethod(methodId) { if (this.closed) return this.rejectClosed(); let j = 0; const frame = new amqp_view_js_1.AMQPView(new ArrayBuffer(12)); frame.setUint8(j, 1); j += 1; frame.setUint16(j, this.id); j += 2; frame.setUint32(j, 4); j += 4; frame.setUint16(j, 90); j += 2; frame.setUint16(j, methodId); j += 2; frame.setUint8(j, 206); j += 1; return this.sendRpc(frame, j); } sendRpc(frame, frameSize) { return new Promise((resolve, reject) => { this.rpcQueue = this.rpcQueue.then(() => { this.connection.send(new Uint8Array(frame.buffer, 0, frameSize)) .then(() => { this.resolveRPC = resolve; this.rejectRPC = reject; }) .catch(reject); }); }); } setClosed(err) { const closedByServer = err !== undefined; err || (err = new Error("Connection closed by client")); if (!this.closed) { this.closed = true; this.consumers.forEach((consumer) => consumer.setClosed(err)); this.consumers.clear(); this.rejectRPC(err); this.unconfirmedPublishes.forEach(([, , reject]) => reject(err)); this.unconfirmedPublishes.length = 0; if (closedByServer) this.onerror(err.message); } } rejectClosed() { return Promise.reject(new amqp_error_js_1.AMQPError("Channel is closed", this.connection)); } publishConfirmed(deliveryTag, multiple, nack) { const idx = this.unconfirmedPublishes.findIndex(([tag,]) => tag === deliveryTag); if (idx !== -1) { const confirmed = multiple ? this.unconfirmedPublishes.splice(0, idx + 1) : this.unconfirmedPublishes.splice(idx, 1); confirmed.forEach(([tag, resolve, reject]) => { if (nack) reject(new Error("Message rejected")); else resolve(tag); }); } else { this.logger?.warn("Cant find unconfirmed deliveryTag", deliveryTag, "multiple:", multiple, "nack:", nack); } } onMessageReady(message) { if (this.delivery) { delete this.delivery; this.deliver(message); } else if (this.getMessage) { delete this.getMessage; this.resolveRPC(message); } else { delete this.returned; this.onReturn(message); } } resolveRPC(value) { return value; } rejectRPC(err) { return err; } deliver(message) { queueMicrotask(() => { const consumer = this.consumers.get(message.consumerTag); if (consumer) { consumer.onMessage(message); } else { this.logger?.warn("Consumer", message.consumerTag, "not available on channel", this.id); } }); } } exports.AMQPChannel = AMQPChannel; //# sourceMappingURL=amqp-channel.js.map