@jonaskello-forks/amqp-client
Version:
AMQP 0-9-1 client, both for browsers (WebSocket) and node (TCP Socket)
107 lines • 4.78 kB
JavaScript
import { AMQPBaseClient } from './amqp-base-client.js';
import { AMQPError } from './amqp-error.js';
import { AMQPView } from './amqp-view.js';
import { Buffer } from 'buffer';
import * as net from 'net';
import * as tls from 'tls';
export class AMQPClient extends AMQPBaseClient {
constructor(url) {
const u = new URL(url);
const vhost = decodeURIComponent(u.pathname.slice(1)) || "/";
const username = u.username || "guest";
const password = u.password || "guest";
const name = u.searchParams.get("name") || "";
const frameMax = parseInt(u.searchParams.get("frameMax") || "4096");
const heartbeat = parseInt(u.searchParams.get("heartbeat") || "0");
const platform = `${process.release.name} ${process.version} ${process.platform} ${process.arch}`;
super(vhost, username, password, name, platform, frameMax, heartbeat);
this.tls = u.protocol === "amqps:";
this.host = u.hostname || "localhost";
this.port = parseInt(u.port) || (this.tls ? 5671 : 5672);
this.insecure = u.searchParams.get("insecure") !== undefined;
this.framePos = 0;
this.frameSize = 0;
this.frameBuffer = Buffer.allocUnsafe(frameMax);
}
connect() {
const socket = this.connectSocket();
Object.defineProperty(this, 'socket', {
value: socket,
enumerable: false
});
return new Promise((resolve, reject) => {
socket.on('error', (err) => reject(new AMQPError(err.message, this)));
this.connectPromise = [resolve, reject];
});
}
connectSocket() {
const options = {
host: this.host,
port: this.port,
servername: this.host,
rejectUnauthorized: !this.insecure
};
const sendStart = () => this.send(new Uint8Array([65, 77, 81, 80, 0, 0, 9, 1]));
const conn = this.tls ? tls.connect(options, sendStart) : net.connect(options, sendStart);
conn.on('data', this.onRead.bind(this));
return conn;
}
onRead(buf) {
const bufLen = buf.length;
let bufPos = 0;
while (bufPos < bufLen) {
if (this.frameSize === 0) {
if (this.framePos !== 0) {
const copied = buf.copy(this.frameBuffer, this.framePos, bufPos, bufPos + 7 - this.framePos);
if (copied === 0)
throw `Copied 0 bytes framePos=${this.framePos} bufPos=${bufPos} bytesWritten=${bufLen}`;
this.frameSize = this.frameBuffer.readInt32BE(bufPos + 3) + 8;
this.framePos += copied;
bufPos += copied;
continue;
}
if (bufPos + 3 + 4 > bufLen) {
const copied = buf.copy(this.frameBuffer, this.framePos, bufPos, bufLen);
if (copied === 0)
throw `Copied 0 bytes framePos=${this.framePos} bufPos=${bufPos} bytesWritten=${bufLen}`;
this.framePos += copied;
break;
}
this.frameSize = buf.readInt32BE(bufPos + 3) + 8;
if (bufLen - bufPos >= this.frameSize) {
const view = new AMQPView(buf.buffer, buf.byteOffset + bufPos, this.frameSize);
this.parseFrames(view);
bufPos += this.frameSize;
this.frameSize = 0;
continue;
}
}
const leftOfFrame = this.frameSize - this.framePos;
const copyBytes = Math.min(leftOfFrame, bufLen - bufPos);
const copied = buf.copy(this.frameBuffer, this.framePos, bufPos, bufPos + copyBytes);
if (copied === 0)
throw `Copied 0 bytes, please report this bug, frameSize=${this.frameSize} framePos=${this.framePos} bufPos=${bufPos} copyBytes=${copyBytes} bytesWritten=${bufLen}`;
this.framePos += copied;
bufPos += copied;
if (this.framePos === this.frameSize) {
const view = new AMQPView(this.frameBuffer.buffer, 0, this.frameSize);
this.parseFrames(view);
this.frameSize = this.framePos = 0;
}
}
return true;
}
send(bytes) {
return new Promise((resolve, reject) => {
if (this.socket)
this.socket.write(bytes, undefined, (err) => err ? reject(err) : resolve());
else
reject(new AMQPError("Socket not connected", this));
});
}
closeSocket() {
if (this.socket)
this.socket.end();
}
}
//# sourceMappingURL=amqp-socket-client.js.map