@cloudamqp/amqp-client
Version:
AMQP 0-9-1 client, both for browsers (WebSocket) and node (TCP Socket)
112 lines • 4.12 kB
JavaScript
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