UNPKG

@cloudamqp/amqp-client

Version:

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

112 lines 4.12 kB
import { serializeAndEncode, decodeMessage } from "./amqp-codec-registry.js"; const DIRECT_REPLY_TO = "amq.rabbitmq.reply-to"; export class AMQPRPCClient { constructor(session) { this.ch = null; this.correlationId = 0; this.pending = new Map(); this.closed = false; this.session = session; } async start() { if (this.closed) throw new Error("RPC client is closed"); if (this.ch && !this.ch.closed) return this; const ch = await this.session.openChannel(); try { const parsers = this.session.parsers; const coders = this.session.coders; await ch.basicConsume(DIRECT_REPLY_TO, { noAck: true }, async (msg) => { const id = msg.properties.correlationId; if (id === undefined) return; const entry = this.pending.get(id); if (!entry) return; this.pending.delete(id); if (entry.timer) clearTimeout(entry.timer); try { if (parsers || coders) await decodeMessage(msg, parsers ?? {}, coders ?? {}); entry.resolve(msg); } catch (err) { entry.reject(err instanceof Error ? err : new Error(String(err))); } }); this.ch = ch; return this; } catch (err) { ch.close().catch(() => { }); throw err; } } async call(queue, body, { timeout, ...properties } = {}) { if (this.closed) throw new Error("RPC client is closed"); if (!this.ch || this.ch.closed) throw new Error("RPC client not started, call start() first"); const ch = this.ch; const correlationId = (++this.correlationId).toString(36); const defaults = {}; if (this.session.defaultContentType) defaults.contentType = this.session.defaultContentType; if (this.session.defaultContentEncoding) defaults.contentEncoding = this.session.defaultContentEncoding; const encoded = await serializeAndEncode(this.session.parsers ?? {}, this.session.coders ?? {}, body, properties, defaults); return new Promise((resolve, reject) => { let timer; if (timeout !== undefined && timeout > 0) { timer = setTimeout(() => { this.pending.delete(correlationId); reject(new Error(`No response received in ${timeout}ms`)); }, timeout); } this.pending.set(correlationId, { resolve, reject, timer }); ch.basicPublish("", queue, encoded.body, { ...encoded.properties, replyTo: DIRECT_REPLY_TO, correlationId, }).catch((err) => { const entry = this.pending.get(correlationId); if (!entry) return; this.pending.delete(correlationId); if (entry.timer) clearTimeout(entry.timer); entry.reject(err); }); }); } async recover() { if (this.closed) return; this.rejectAllPending(new Error("RPC client reconnecting")); this.ch = null; await this.start(); } async close() { if (this.closed) return; this.closed = true; this.session.untrackRPCClient(this); this.rejectAllPending(new Error("RPC client closed")); const ch = this.ch; this.ch = null; if (ch && !ch.closed) { await ch.close(); } } rejectAllPending(err) { for (const [id, entry] of this.pending) { if (entry.timer) clearTimeout(entry.timer); entry.reject(err); this.pending.delete(id); } } } //# sourceMappingURL=amqp-rpc-client.js.map