primer cambio

This commit is contained in:
beseira13
2026-01-19 12:12:38 -03:00
parent 5f59dba52d
commit 44990f015a
4759 changed files with 588702 additions and 0 deletions

314
node_modules/amqplib/lib/api_args.js generated vendored Normal file
View File

@@ -0,0 +1,314 @@
//
//
//
'use strict';
/*
The channel (promise) and callback APIs have similar signatures, and
in particular, both need AMQP fields prepared from the same arguments
and options. The arguments marshalling is done here. Each of the
procedures below takes arguments and options (the latter in an object)
particular to the operation it represents, and returns an object with
fields for handing to the encoder.
*/
// A number of AMQP methods have a table-typed field called
// `arguments`, that is intended to carry extension-specific
// values. RabbitMQ uses this in a number of places; e.g., to specify
// an 'alternate exchange'.
//
// Many of the methods in this API have an `options` argument, from
// which I take both values that have a default in AMQP (e.g.,
// autoDelete in QueueDeclare) *and* values that are specific to
// RabbitMQ (e.g., 'alternate-exchange'), which would normally be
// supplied in `arguments`. So that extensions I don't support yet can
// be used, I include `arguments` itself among the options.
//
// The upshot of this is that I often need to prepare an `arguments`
// value that has any values passed in `options.arguments` as well as
// any I've promoted to being options themselves. Since I don't want
// to mutate anything passed in, the general pattern is to create a
// fresh object with the `arguments` value given as its prototype; all
// fields in the supplied value will be serialised, as well as any I
// set on the fresh object. What I don't want to do, however, is set a
// field to undefined by copying possibly missing field values,
// because that will mask a value in the prototype.
//
// NB the `arguments` field already has a default value of `{}`, so
// there's no need to explicitly default it unless I'm setting values.
function setIfDefined(obj, prop, value) {
if (value != undefined) obj[prop] = value;
}
var EMPTY_OPTIONS = Object.freeze({});
var Args = {};
Args.assertQueue = function(queue, options) {
queue = queue || '';
options = options || EMPTY_OPTIONS;
var argt = Object.create(options.arguments || null);
setIfDefined(argt, 'x-expires', options.expires);
setIfDefined(argt, 'x-message-ttl', options.messageTtl);
setIfDefined(argt, 'x-dead-letter-exchange',
options.deadLetterExchange);
setIfDefined(argt, 'x-dead-letter-routing-key',
options.deadLetterRoutingKey);
setIfDefined(argt, 'x-max-length', options.maxLength);
setIfDefined(argt, 'x-max-priority', options.maxPriority);
setIfDefined(argt, 'x-overflow', options.overflow);
setIfDefined(argt, 'x-queue-mode', options.queueMode);
return {
queue: queue,
exclusive: !!options.exclusive,
durable: (options.durable === undefined) ? true : options.durable,
autoDelete: !!options.autoDelete,
arguments: argt,
passive: false,
// deprecated but we have to include it
ticket: 0,
nowait: false
};
};
Args.checkQueue = function(queue) {
return {
queue: queue,
passive: true, // switch to "completely different" mode
nowait: false,
durable: true, autoDelete: false, exclusive: false, // ignored
ticket: 0,
};
};
Args.deleteQueue = function(queue, options) {
options = options || EMPTY_OPTIONS;
return {
queue: queue,
ifUnused: !!options.ifUnused,
ifEmpty: !!options.ifEmpty,
ticket: 0, nowait: false
};
};
Args.purgeQueue = function(queue) {
return {
queue: queue,
ticket: 0, nowait: false
};
};
Args.bindQueue = function(queue, source, pattern, argt) {
return {
queue: queue,
exchange: source,
routingKey: pattern,
arguments: argt,
ticket: 0, nowait: false
};
};
Args.unbindQueue = function(queue, source, pattern, argt) {
return {
queue: queue,
exchange: source,
routingKey: pattern,
arguments: argt,
ticket: 0, nowait: false
};
};
Args.assertExchange = function(exchange, type, options) {
options = options || EMPTY_OPTIONS;
var argt = Object.create(options.arguments || null);
setIfDefined(argt, 'alternate-exchange', options.alternateExchange);
return {
exchange: exchange,
ticket: 0,
type: type,
passive: false,
durable: (options.durable === undefined) ? true : options.durable,
autoDelete: !!options.autoDelete,
internal: !!options.internal,
nowait: false,
arguments: argt
};
};
Args.checkExchange = function(exchange) {
return {
exchange: exchange,
passive: true, // switch to 'may as well be another method' mode
nowait: false,
// ff are ignored
durable: true, internal: false, type: '', autoDelete: false,
ticket: 0
};
};
Args.deleteExchange = function(exchange, options) {
options = options || EMPTY_OPTIONS;
return {
exchange: exchange,
ifUnused: !!options.ifUnused,
ticket: 0, nowait: false
};
};
Args.bindExchange = function(dest, source, pattern, argt) {
return {
source: source,
destination: dest,
routingKey: pattern,
arguments: argt,
ticket: 0, nowait: false
};
};
Args.unbindExchange = function(dest, source, pattern, argt) {
return {
source: source,
destination: dest,
routingKey: pattern,
arguments: argt,
ticket: 0, nowait: false
};
};
// It's convenient to construct the properties and the method fields
// at the same time, since in the APIs, values for both can appear in
// `options`. Since the property or mthod field names don't overlap, I
// just return one big object that can be used for both purposes, and
// the encoder will pick out what it wants.
Args.publish = function(exchange, routingKey, options) {
options = options || EMPTY_OPTIONS;
// The CC and BCC fields expect an array of "longstr", which would
// normally be buffer values in JavaScript; however, since a field
// array (or table) cannot have shortstr values, the codec will
// encode all strings as longstrs anyway.
function convertCC(cc) {
if (cc === undefined) {
return undefined;
}
else if (Array.isArray(cc)) {
return cc.map(String);
}
else return [String(cc)];
}
var headers = Object.create(options.headers || null);
setIfDefined(headers, 'CC', convertCC(options.CC));
setIfDefined(headers, 'BCC', convertCC(options.BCC));
var deliveryMode; // undefined will default to 1 (non-persistent)
// Previously I overloaded deliveryMode be a boolean meaning
// 'persistent or not'; better is to name this option for what it
// is, but I need to have backwards compatibility for applications
// that either supply a numeric or boolean value.
if (options.persistent !== undefined)
deliveryMode = (options.persistent) ? 2 : 1;
else if (typeof options.deliveryMode === 'number')
deliveryMode = options.deliveryMode;
else if (options.deliveryMode) // is supplied and truthy
deliveryMode = 2;
var expiration = options.expiration;
if (expiration !== undefined) expiration = expiration.toString();
return {
// method fields
exchange: exchange,
routingKey: routingKey,
mandatory: !!options.mandatory,
immediate: false, // RabbitMQ doesn't implement this any more
ticket: undefined,
// properties
contentType: options.contentType,
contentEncoding: options.contentEncoding,
headers: headers,
deliveryMode: deliveryMode,
priority: options.priority,
correlationId: options.correlationId,
replyTo: options.replyTo,
expiration: expiration,
messageId: options.messageId,
timestamp: options.timestamp,
type: options.type,
userId: options.userId,
appId: options.appId,
clusterId: undefined
};
};
Args.consume = function(queue, options) {
options = options || EMPTY_OPTIONS;
var argt = Object.create(options.arguments || null);
setIfDefined(argt, 'x-priority', options.priority);
return {
ticket: 0,
queue: queue,
consumerTag: options.consumerTag || '',
noLocal: !!options.noLocal,
noAck: !!options.noAck,
exclusive: !!options.exclusive,
nowait: false,
arguments: argt
};
};
Args.cancel = function(consumerTag) {
return {
consumerTag: consumerTag,
nowait: false
};
};
Args.get = function(queue, options) {
options = options || EMPTY_OPTIONS;
return {
ticket: 0,
queue: queue,
noAck: !!options.noAck
};
};
Args.ack = function(tag, allUpTo) {
return {
deliveryTag: tag,
multiple: !!allUpTo
};
};
Args.nack = function(tag, allUpTo, requeue) {
return {
deliveryTag: tag,
multiple: !!allUpTo,
requeue: (requeue === undefined) ? true : requeue
};
};
Args.reject = function(tag, requeue) {
return {
deliveryTag: tag,
requeue: (requeue === undefined) ? true : requeue
};
};
Args.prefetch = function(count, global) {
return {
prefetchCount: count || 0,
prefetchSize: 0,
global: !!global
};
};
Args.recover = function() {
return {requeue: true};
};
module.exports = Object.freeze(Args);

130
node_modules/amqplib/lib/bitset.js generated vendored Normal file
View File

@@ -0,0 +1,130 @@
//
//
//
'use strict';
/**
* A bitset implementation, after that in java.util. Yes there
* already exist such things, but none implement next{Clear|Set}Bit or
* equivalent, and none involved me tooling about for an evening.
*/
class BitSet {
/**
* @param {number} [size]
*/
constructor(size) {
if (size) {
const numWords = Math.ceil(size / 32);
this.words = new Array(numWords);
}
else {
this.words = [];
}
this.wordsInUse = 0; // = number, not index
}
/**
* @param {number} numWords
*/
ensureSize(numWords) {
const wordsPresent = this.words.length;
if (wordsPresent < numWords) {
this.words = this.words.concat(new Array(numWords - wordsPresent));
}
}
/**
* @param {number} bitIndex
*/
set(bitIndex) {
const w = wordIndex(bitIndex);
if (w >= this.wordsInUse) {
this.ensureSize(w + 1);
this.wordsInUse = w + 1;
}
const bit = 1 << bitIndex;
this.words[w] |= bit;
}
/**
* @param {number} bitIndex
*/
clear(bitIndex) {
const w = wordIndex(bitIndex);
if (w >= this.wordsInUse) return;
const mask = ~(1 << bitIndex);
this.words[w] &= mask;
}
/**
* @param {number} bitIndex
*/
get(bitIndex) {
const w = wordIndex(bitIndex);
if (w >= this.wordsInUse) return false; // >= since index vs size
const bit = 1 << bitIndex;
return !!(this.words[w] & bit);
}
/**
* Give the next bit that is set on or after fromIndex, or -1 if no such bit
*
* @param {number} fromIndex
*/
nextSetBit(fromIndex) {
let w = wordIndex(fromIndex);
if (w >= this.wordsInUse) return -1;
// the right-hand side is shifted to only test the bits of the first
// word that are > fromIndex
let word = this.words[w] & (0xffffffff << fromIndex);
while (true) {
if (word) return (w * 32) + trailingZeros(word);
w++;
if (w === this.wordsInUse) return -1;
word = this.words[w];
}
}
/**
* @param {number} fromIndex
*/
nextClearBit(fromIndex) {
let w = wordIndex(fromIndex);
if (w >= this.wordsInUse) return fromIndex;
let word = ~(this.words[w]) & (0xffffffff << fromIndex);
while (true) {
if (word) return (w * 32) + trailingZeros(word);
w++;
if (w == this.wordsInUse) return w * 32;
word = ~(this.words[w]);
}
}
}
/**
* @param {number} bitIndex
*/
function wordIndex(bitIndex) {
return Math.floor(bitIndex / 32);
}
/**
* @param {number} i
*/
function trailingZeros(i) {
// From Hacker's Delight, via JDK. Probably far less effective here,
// since bit ops are not necessarily the quick way to do things in
// JS.
if (i === 0) return 32;
let y, n = 31;
y = i << 16; if (y != 0) { n = n -16; i = y; }
y = i << 8; if (y != 0) { n = n - 8; i = y; }
y = i << 4; if (y != 0) { n = n - 4; i = y; }
y = i << 2; if (y != 0) { n = n - 2; i = y; }
return n - ((i << 1) >>> 31);
}
module.exports.BitSet = BitSet;

342
node_modules/amqplib/lib/callback_model.js generated vendored Normal file
View File

@@ -0,0 +1,342 @@
//
//
//
'use strict';
var defs = require('./defs');
var EventEmitter = require('events');
var BaseChannel = require('./channel').BaseChannel;
var acceptMessage = require('./channel').acceptMessage;
var Args = require('./api_args');
class CallbackModel extends EventEmitter {
constructor (connection) {
super();
this.connection = connection;
var self = this;
['error', 'close', 'blocked', 'unblocked'].forEach(function (ev) {
connection.on(ev, self.emit.bind(self, ev));
});
}
close (cb) {
this.connection.close(cb);
}
updateSecret(newSecret, reason, cb) {
this.connection._updateSecret(newSecret, reason, cb);
}
createChannel (options, cb) {
if (arguments.length === 1) {
cb = options;
options = undefined;
}
var ch = new Channel(this.connection);
ch.setOptions(options);
ch.open(function (err, ok) {
if (err === null)
cb && cb(null, ch);
else
cb && cb(err);
});
return ch;
}
createConfirmChannel (options, cb) {
if (arguments.length === 1) {
cb = options;
options = undefined;
}
var ch = new ConfirmChannel(this.connection);
ch.setOptions(options);
ch.open(function (err) {
if (err !== null)
return cb && cb(err);
else {
ch.rpc(defs.ConfirmSelect, { nowait: false },
defs.ConfirmSelectOk, function (err, _ok) {
if (err !== null)
return cb && cb(err);
else
cb && cb(null, ch);
});
}
});
return ch;
}
}
class Channel extends BaseChannel {
constructor (connection) {
super(connection);
this.on('delivery', this.handleDelivery.bind(this));
this.on('cancel', this.handleCancel.bind(this));
}
// This encodes straight-forward RPC: no side-effects and return the
// fields from the server response. It wraps the callback given it, so
// the calling method argument can be passed as-is. For anything that
// needs to have side-effects, or needs to change the server response,
// use `#_rpc(...)` and remember to dereference `.fields` of the
// server response.
rpc (method, fields, expect, cb0) {
var cb = callbackWrapper(this, cb0);
this._rpc(method, fields, expect, function (err, ok) {
cb(err, ok && ok.fields); // in case of an error, ok will be
// undefined
});
return this;
}
// === Public API ===
open (cb) {
try { this.allocate(); }
catch (e) { return cb(e); }
return this.rpc(defs.ChannelOpen, { outOfBand: "" },
defs.ChannelOpenOk, cb);
}
close (cb) {
return this.closeBecause("Goodbye", defs.constants.REPLY_SUCCESS,
function () { cb && cb(null); });
}
assertQueue (queue, options, cb) {
return this.rpc(defs.QueueDeclare,
Args.assertQueue(queue, options),
defs.QueueDeclareOk, cb);
}
checkQueue (queue, cb) {
return this.rpc(defs.QueueDeclare,
Args.checkQueue(queue),
defs.QueueDeclareOk, cb);
}
deleteQueue (queue, options, cb) {
return this.rpc(defs.QueueDelete,
Args.deleteQueue(queue, options),
defs.QueueDeleteOk, cb);
}
purgeQueue (queue, cb) {
return this.rpc(defs.QueuePurge,
Args.purgeQueue(queue),
defs.QueuePurgeOk, cb);
}
bindQueue (queue, source, pattern, argt, cb) {
return this.rpc(defs.QueueBind,
Args.bindQueue(queue, source, pattern, argt),
defs.QueueBindOk, cb);
}
unbindQueue (queue, source, pattern, argt, cb) {
return this.rpc(defs.QueueUnbind,
Args.unbindQueue(queue, source, pattern, argt),
defs.QueueUnbindOk, cb);
}
assertExchange (ex, type, options, cb0) {
var cb = callbackWrapper(this, cb0);
this._rpc(defs.ExchangeDeclare,
Args.assertExchange(ex, type, options),
defs.ExchangeDeclareOk,
function (e, _) { cb(e, { exchange: ex }); });
return this;
}
checkExchange (exchange, cb) {
return this.rpc(defs.ExchangeDeclare,
Args.checkExchange(exchange),
defs.ExchangeDeclareOk, cb);
}
deleteExchange (exchange, options, cb) {
return this.rpc(defs.ExchangeDelete,
Args.deleteExchange(exchange, options),
defs.ExchangeDeleteOk, cb);
}
bindExchange (dest, source, pattern, argt, cb) {
return this.rpc(defs.ExchangeBind,
Args.bindExchange(dest, source, pattern, argt),
defs.ExchangeBindOk, cb);
}
unbindExchange (dest, source, pattern, argt, cb) {
return this.rpc(defs.ExchangeUnbind,
Args.unbindExchange(dest, source, pattern, argt),
defs.ExchangeUnbindOk, cb);
}
publish (exchange, routingKey, content, options) {
var fieldsAndProps = Args.publish(exchange, routingKey, options);
return this.sendMessage(fieldsAndProps, fieldsAndProps, content);
}
sendToQueue (queue, content, options) {
return this.publish('', queue, content, options);
}
consume (queue, callback, options, cb0) {
var cb = callbackWrapper(this, cb0);
var fields = Args.consume(queue, options);
var self = this;
this._rpc(
defs.BasicConsume, fields, defs.BasicConsumeOk,
function (err, ok) {
if (err === null) {
self.registerConsumer(ok.fields.consumerTag, callback);
cb(null, ok.fields);
}
else
cb(err);
});
return this;
}
cancel (consumerTag, cb0) {
var cb = callbackWrapper(this, cb0);
var self = this;
this._rpc(
defs.BasicCancel, Args.cancel(consumerTag), defs.BasicCancelOk,
function (err, ok) {
if (err === null) {
self.unregisterConsumer(consumerTag);
cb(null, ok.fields);
}
else
cb(err);
});
return this;
}
get (queue, options, cb0) {
var self = this;
var fields = Args.get(queue, options);
var cb = callbackWrapper(this, cb0);
this.sendOrEnqueue(defs.BasicGet, fields, function (err, f) {
if (err === null) {
if (f.id === defs.BasicGetEmpty) {
cb(null, false);
}
else if (f.id === defs.BasicGetOk) {
self.handleMessage = acceptMessage(function (m) {
m.fields = f.fields;
cb(null, m);
});
}
else {
cb(new Error("Unexpected response to BasicGet: " +
inspect(f)));
}
}
});
return this;
}
ack (message, allUpTo) {
this.sendImmediately(
defs.BasicAck, Args.ack(message.fields.deliveryTag, allUpTo));
return this;
}
ackAll () {
this.sendImmediately(defs.BasicAck, Args.ack(0, true));
return this;
}
nack (message, allUpTo, requeue) {
this.sendImmediately(
defs.BasicNack,
Args.nack(message.fields.deliveryTag, allUpTo, requeue));
return this;
}
nackAll (requeue) {
this.sendImmediately(
defs.BasicNack, Args.nack(0, true, requeue));
return this;
}
reject (message, requeue) {
this.sendImmediately(
defs.BasicReject,
Args.reject(message.fields.deliveryTag, requeue));
return this;
}
prefetch (count, global, cb) {
return this.rpc(defs.BasicQos,
Args.prefetch(count, global),
defs.BasicQosOk, cb);
}
recover (cb) {
return this.rpc(defs.BasicRecover,
Args.recover(),
defs.BasicRecoverOk, cb);
}
}
// Wrap an RPC callback to make sure the callback is invoked with
// either `(null, value)` or `(error)`, i.e., never two non-null
// values. Also substitutes a stub if the callback is `undefined` or
// otherwise falsey, for convenience in methods for which the callback
// is optional (that is, most of them).
function callbackWrapper(ch, cb) {
return (cb) ? function(err, ok) {
if (err === null) {
cb(null, ok);
}
else cb(err);
} : function() {};
}
class ConfirmChannel extends Channel {
publish (exchange, routingKey,
content, options, cb) {
this.pushConfirmCallback(cb);
return Channel.prototype.publish.call(
this, exchange, routingKey, content, options);
}
sendToQueue (queue, content,
options, cb) {
return this.publish('', queue, content, options, cb);
}
waitForConfirms (k) {
var awaiting = [];
var unconfirmed = this.unconfirmed;
unconfirmed.forEach(function (val, index) {
if (val === null)
; // already confirmed
else {
var confirmed = new Promise(function (resolve, reject) {
unconfirmed[index] = function (err) {
if (val)
val(err);
if (err === null)
resolve();
else
reject(err);
};
});
awaiting.push(confirmed);
}
});
return Promise.all(awaiting).then(function () { k(); },
function (err) { k(err); });
}
}
module.exports.CallbackModel = CallbackModel;
module.exports.Channel = Channel;
module.exports.ConfirmChannel = ConfirmChannel;

510
node_modules/amqplib/lib/channel.js generated vendored Normal file
View File

@@ -0,0 +1,510 @@
//
//
//
// Channel machinery.
'use strict';
var defs = require('./defs');
var closeMsg = require('./format').closeMessage;
var inspect = require('./format').inspect;
var methodName = require('./format').methodName;
var assert = require('assert');
var EventEmitter = require('events');
var fmt = require('util').format;
var IllegalOperationError = require('./error').IllegalOperationError;
var stackCapture = require('./error').stackCapture;
class Channel extends EventEmitter {
constructor (connection) {
super();
this.connection = connection;
// for the presently outstanding RPC
this.reply = null;
// for the RPCs awaiting action
this.pending = [];
// for unconfirmed messages
this.lwm = 1; // the least, unconfirmed deliveryTag
this.unconfirmed = []; // rolling window of delivery callbacks
this.on('ack', this.handleConfirm.bind(this, function (cb) {
if (cb)
cb(null);
}));
this.on('nack', this.handleConfirm.bind(this, function (cb) {
if (cb)
cb(new Error('message nacked'));
}));
this.on('close', function () {
var cb;
while (cb = this.unconfirmed.shift()) {
if (cb)
cb(new Error('channel closed'));
}
});
// message frame state machine
this.handleMessage = acceptDeliveryOrReturn;
}
setOptions(options) {
this.options = options;
}
allocate () {
this.ch = this.connection.freshChannel(this, this.options);
return this;
}
// Incoming frames are either notifications of e.g., message delivery,
// or replies to something we've sent. In general I deal with the
// former by emitting an event, and with the latter by keeping a track
// of what's expecting a reply.
//
// The AMQP specification implies that RPCs can't be pipelined; that
// is, you can have only one outstanding RPC on a channel at a
// time. Certainly that's what RabbitMQ and its clients assume. For
// this reason, I buffer RPCs if the channel is already waiting for a
// reply.
// Just send the damn frame.
sendImmediately (method, fields) {
return this.connection.sendMethod(this.ch, method, fields);
}
// Invariant: !this.reply -> pending.length == 0. That is, whenever we
// clear a reply, we must send another RPC (and thereby fill
// this.reply) if there is one waiting. The invariant relevant here
// and in `accept`.
sendOrEnqueue (method, fields, reply) {
if (!this.reply) { // if no reply waiting, we can go
assert(this.pending.length === 0);
this.reply = reply;
this.sendImmediately(method, fields);
}
else {
this.pending.push({
method: method,
fields: fields,
reply: reply
});
}
}
sendMessage (fields, properties, content) {
return this.connection.sendMessage(
this.ch,
defs.BasicPublish, fields,
defs.BasicProperties, properties,
content);
}
// Internal, synchronously resolved RPC; the return value is resolved
// with the whole frame.
_rpc (method, fields, expect, cb) {
var self = this;
function reply (err, f) {
if (err === null) {
if (f.id === expect) {
return cb(null, f);
}
else {
// We have detected a problem, so it's up to us to close the
// channel
var expectedName = methodName(expect);
var e = new Error(fmt("Expected %s; got %s",
expectedName, inspect(f, false)));
self.closeWithError(f.id, fmt('Expected %s; got %s',
expectedName, methodName(f.id)),
defs.constants.UNEXPECTED_FRAME, e);
return cb(e);
}
}
// An error will be given if, for example, this is waiting to be
// sent and the connection closes
else if (err instanceof Error)
return cb(err);
// A close frame will be given if this is the RPC awaiting reply
// and the channel is closed by the server
else {
// otherwise, it's a close frame
var closeReason = (err.fields.classId << 16) + err.fields.methodId;
var e = (method === closeReason)
? fmt("Operation failed: %s; %s",
methodName(method), closeMsg(err))
: fmt("Channel closed by server: %s", closeMsg(err));
var closeFrameError = new Error(e);
closeFrameError.code = err.fields.replyCode;
closeFrameError.classId = err.fields.classId;
closeFrameError.methodId = err.fields.methodId;
return cb(closeFrameError);
}
}
this.sendOrEnqueue(method, fields, reply);
}
// Move to entirely closed state.
toClosed (capturedStack) {
this._rejectPending();
invalidateSend(this, 'Channel closed', capturedStack);
this.accept = invalidOp('Channel closed', capturedStack);
this.connection.releaseChannel(this.ch);
this.emit('close');
}
// Stop being able to send and receive methods and content. Used when
// we close the channel. Invokes the continuation once the server has
// acknowledged the close, but before the channel is moved to the
// closed state.
toClosing (capturedStack, k) {
var send = this.sendImmediately.bind(this);
invalidateSend(this, 'Channel closing', capturedStack);
this.accept = function (f) {
if (f.id === defs.ChannelCloseOk) {
if (k)
k();
var s = stackCapture('ChannelCloseOk frame received');
this.toClosed(s);
}
else if (f.id === defs.ChannelClose) {
send(defs.ChannelCloseOk, {});
}
// else ignore frame
};
}
_rejectPending () {
function rej (r) {
r(new Error("Channel ended, no reply will be forthcoming"));
}
if (this.reply !== null)
rej(this.reply);
this.reply = null;
var discard;
while (discard = this.pending.shift())
rej(discard.reply);
this.pending = null; // so pushes will break
}
closeBecause (reason, code, k) {
this.sendImmediately(defs.ChannelClose, {
replyText: reason,
replyCode: code,
methodId: 0, classId: 0
});
var s = stackCapture('closeBecause called: ' + reason);
this.toClosing(s, k);
}
// If we close because there's been an error, we need to distinguish
// between what we tell the server (`reason`) and what we report as
// the cause in the client (`error`).
closeWithError (id, reason, code, error) {
var self = this;
this.closeBecause(reason, code, function () {
error.code = code;
// content frames and consumer errors do not provide a method a class/method ID
if (id) {
error.classId = defs.info(id).classId;
error.methodId = defs.info(id).methodId;
}
self.emit('error', error);
});
}
// A trampolining state machine for message frames on a channel. A
// message arrives in at least two frames: first, a method announcing
// the message (either a BasicDeliver or BasicGetOk); then, a message
// header with the message properties; then, zero or more content
// frames.
// Keep the try/catch localised, in an attempt to avoid disabling
// optimisation
acceptMessageFrame (f) {
try {
this.handleMessage = this.handleMessage(f);
}
catch (msg) {
if (typeof msg === 'string') {
this.closeWithError(f.id, msg, defs.constants.UNEXPECTED_FRAME,
new Error(msg));
}
else if (msg instanceof Error) {
this.closeWithError(f.id, 'Error while processing message',
defs.constants.INTERNAL_ERROR, msg);
}
else {
this.closeWithError(f.id, 'Internal error while processing message',
defs.constants.INTERNAL_ERROR,
new Error(msg.toString()));
}
}
}
handleConfirm (handle, f) {
var tag = f.deliveryTag;
var multi = f.multiple;
if (multi) {
var confirmed = this.unconfirmed.splice(0, tag - this.lwm + 1);
this.lwm = tag + 1;
confirmed.forEach(handle);
}
else {
var c;
if (tag === this.lwm) {
c = this.unconfirmed.shift();
this.lwm++;
// Advance the LWM and the window to the next non-gap, or
// possibly to the end
while (this.unconfirmed[0] === null) {
this.unconfirmed.shift();
this.lwm++;
}
}
else {
c = this.unconfirmed[tag - this.lwm];
this.unconfirmed[tag - this.lwm] = null;
}
// Technically, in the single-deliveryTag case, I should report a
// protocol breach if it's already been confirmed.
handle(c);
}
}
pushConfirmCallback (cb) {
// `null` is used specifically for marking already confirmed slots,
// so I coerce `undefined` and `null` to false; functions are never
// falsey.
this.unconfirmed.push(cb || false);
}
onBufferDrain () {
this.emit('drain');
}
accept(f) {
switch (f.id) {
// Message frames
case undefined: // content frame!
case defs.BasicDeliver:
case defs.BasicReturn:
case defs.BasicProperties:
return this.acceptMessageFrame(f);
// confirmations, need to do confirm.select first
case defs.BasicAck:
return this.emit('ack', f.fields);
case defs.BasicNack:
return this.emit('nack', f.fields);
case defs.BasicCancel:
// The broker can send this if e.g., the queue is deleted.
return this.emit('cancel', f.fields);
case defs.ChannelClose:
// Any remote closure is an error to us. Reject the pending reply
// with the close frame, so it can see whether it was that
// operation that caused it to close.
if (this.reply) {
var reply = this.reply; this.reply = null;
reply(f);
}
var emsg = "Channel closed by server: " + closeMsg(f);
this.sendImmediately(defs.ChannelCloseOk, {});
var error = new Error(emsg);
error.code = f.fields.replyCode;
error.classId = f.fields.classId;
error.methodId = f.fields.methodId;
this.emit('error', error);
var s = stackCapture(emsg);
this.toClosed(s);
return;
case defs.BasicFlow:
// RabbitMQ doesn't send this, it just blocks the TCP socket
return this.closeWithError(f.id, "Flow not implemented",
defs.constants.NOT_IMPLEMENTED,
new Error('Flow not implemented'));
default: // assume all other things are replies
// Resolving the reply may lead to another RPC; to make sure we
// don't hold that up, clear this.reply
var reply = this.reply; this.reply = null;
// however, maybe there's an RPC waiting to go? If so, that'll
// fill this.reply again, restoring the invariant. This does rely
// on any response being recv'ed after resolving the promise,
// below; hence, I use synchronous defer.
if (this.pending.length > 0) {
var send = this.pending.shift();
this.reply = send.reply;
this.sendImmediately(send.method, send.fields);
}
return reply(null, f);
}
}
}
// Shutdown protocol. There's three scenarios:
//
// 1. The application decides to shut the channel
// 2. The server decides to shut the channel, possibly because of
// something the application did
// 3. The connection is closing, so there won't be any more frames
// going back and forth.
//
// 1 and 2 involve an exchange of method frames (Close and CloseOk),
// while 3 doesn't; the connection simply says "shutdown" to the
// channel, which then acts as if it's closing, without going through
// the exchange.
function invalidOp(msg, stack) {
return function() {
throw new IllegalOperationError(msg, stack);
};
}
function invalidateSend(ch, msg, stack) {
ch.sendImmediately = ch.sendOrEnqueue = ch.sendMessage =
invalidOp(msg, stack);
}
// Kick off a message delivery given a BasicDeliver or BasicReturn
// frame (BasicGet uses the RPC mechanism)
function acceptDeliveryOrReturn(f) {
var event;
if (f.id === defs.BasicDeliver) event = 'delivery';
else if (f.id === defs.BasicReturn) event = 'return';
else throw fmt("Expected BasicDeliver or BasicReturn; got %s",
inspect(f));
var self = this;
var fields = f.fields;
return acceptMessage(function(message) {
message.fields = fields;
self.emit(event, message);
});
}
// Move to the state of waiting for message frames (headers, then
// one or more content frames)
function acceptMessage(continuation) {
var totalSize = 0, remaining = 0;
var buffers = null;
var message = {
fields: null,
properties: null,
content: null
};
return headers;
// expect a headers frame
function headers(f) {
if (f.id === defs.BasicProperties) {
message.properties = f.fields;
totalSize = remaining = f.size;
// for zero-length messages, content frames aren't required.
if (totalSize === 0) {
message.content = Buffer.alloc(0);
continuation(message);
return acceptDeliveryOrReturn;
}
else {
return content;
}
}
else {
throw "Expected headers frame after delivery";
}
}
// expect a content frame
// %%% TODO cancelled messages (sent as zero-length content frame)
function content(f) {
if (f.content) {
var size = f.content.length;
remaining -= size;
if (remaining === 0) {
if (buffers !== null) {
buffers.push(f.content);
message.content = Buffer.concat(buffers);
}
else {
message.content = f.content;
}
continuation(message);
return acceptDeliveryOrReturn;
}
else if (remaining < 0) {
throw fmt("Too much content sent! Expected %d bytes",
totalSize);
}
else {
if (buffers !== null)
buffers.push(f.content);
else
buffers = [f.content];
return content;
}
}
else throw "Expected content frame after headers"
}
}
// This adds just a bit more stuff useful for the APIs, but not
// low-level machinery.
class BaseChannel extends Channel {
constructor (connection) {
super(connection);
this.consumers = new Map();
}
// Not sure I like the ff, it's going to be changing hidden classes
// all over the place. On the other hand, whaddya do.
registerConsumer (tag, callback) {
this.consumers.set(tag, callback);
}
unregisterConsumer (tag) {
this.consumers.delete(tag);
}
dispatchMessage (fields, message) {
var consumerTag = fields.consumerTag;
var consumer = this.consumers.get(consumerTag);
if (consumer) {
return consumer(message);
}
else {
// %%% Surely a race here
throw new Error("Unknown consumer: " + consumerTag);
}
}
handleDelivery (message) {
return this.dispatchMessage(message.fields, message);
}
handleCancel (fields) {
var result = this.dispatchMessage(fields, null);
this.unregisterConsumer(fields.consumerTag);
return result;
}
}
module.exports.acceptMessage = acceptMessage;
module.exports.BaseChannel = BaseChannel;
module.exports.Channel = Channel;

308
node_modules/amqplib/lib/channel_model.js generated vendored Normal file
View File

@@ -0,0 +1,308 @@
//
//
//
'use strict';
const EventEmitter = require('events');
const promisify = require('util').promisify;
const defs = require('./defs');
const {BaseChannel} = require('./channel');
const {acceptMessage} = require('./channel');
const Args = require('./api_args');
const {inspect} = require('./format');
class ChannelModel extends EventEmitter {
constructor(connection) {
super();
this.connection = connection;
['error', 'close', 'blocked', 'unblocked'].forEach(ev => {
connection.on(ev, this.emit.bind(this, ev));
});
}
close() {
return promisify(this.connection.close.bind(this.connection))();
}
updateSecret(newSecret, reason) {
return promisify(this.connection._updateSecret.bind(this.connection))(newSecret, reason);
}
async createChannel(options) {
const channel = new Channel(this.connection);
channel.setOptions(options);
await channel.open();
return channel;
}
async createConfirmChannel(options) {
const channel = new ConfirmChannel(this.connection);
channel.setOptions(options);
await channel.open();
await channel.rpc(defs.ConfirmSelect, {nowait: false}, defs.ConfirmSelectOk);
return channel;
}
}
// Channels
class Channel extends BaseChannel {
constructor(connection) {
super(connection);
this.on('delivery', this.handleDelivery.bind(this));
this.on('cancel', this.handleCancel.bind(this));
}
// An RPC that returns a 'proper' promise, which resolves to just the
// response's fields; this is intended to be suitable for implementing
// API procedures.
async rpc(method, fields, expect) {
const f = await promisify(cb => {
return this._rpc(method, fields, expect, cb);
})();
return f.fields;
}
// Do the remarkably simple channel open handshake
async open() {
const ch = await this.allocate.bind(this)();
return ch.rpc(defs.ChannelOpen, {outOfBand: ""},
defs.ChannelOpenOk);
}
close() {
return promisify(cb => {
return this.closeBecause("Goodbye", defs.constants.REPLY_SUCCESS,
cb);
})();
}
// === Public API, declaring queues and stuff ===
assertQueue(queue, options) {
return this.rpc(defs.QueueDeclare,
Args.assertQueue(queue, options),
defs.QueueDeclareOk);
}
checkQueue(queue) {
return this.rpc(defs.QueueDeclare,
Args.checkQueue(queue),
defs.QueueDeclareOk);
}
deleteQueue(queue, options) {
return this.rpc(defs.QueueDelete,
Args.deleteQueue(queue, options),
defs.QueueDeleteOk);
}
purgeQueue(queue) {
return this.rpc(defs.QueuePurge,
Args.purgeQueue(queue),
defs.QueuePurgeOk);
}
bindQueue(queue, source, pattern, argt) {
return this.rpc(defs.QueueBind,
Args.bindQueue(queue, source, pattern, argt),
defs.QueueBindOk);
}
unbindQueue(queue, source, pattern, argt) {
return this.rpc(defs.QueueUnbind,
Args.unbindQueue(queue, source, pattern, argt),
defs.QueueUnbindOk);
}
assertExchange(exchange, type, options) {
// The server reply is an empty set of fields, but it's convenient
// to have the exchange name handed to the continuation.
return this.rpc(defs.ExchangeDeclare,
Args.assertExchange(exchange, type, options),
defs.ExchangeDeclareOk)
.then(_ok => { return { exchange }; });
}
checkExchange(exchange) {
return this.rpc(defs.ExchangeDeclare,
Args.checkExchange(exchange),
defs.ExchangeDeclareOk);
}
deleteExchange(name, options) {
return this.rpc(defs.ExchangeDelete,
Args.deleteExchange(name, options),
defs.ExchangeDeleteOk);
}
bindExchange(dest, source, pattern, argt) {
return this.rpc(defs.ExchangeBind,
Args.bindExchange(dest, source, pattern, argt),
defs.ExchangeBindOk);
}
unbindExchange(dest, source, pattern, argt) {
return this.rpc(defs.ExchangeUnbind,
Args.unbindExchange(dest, source, pattern, argt),
defs.ExchangeUnbindOk);
}
// Working with messages
publish(exchange, routingKey, content, options) {
const fieldsAndProps = Args.publish(exchange, routingKey, options);
return this.sendMessage(fieldsAndProps, fieldsAndProps, content);
}
sendToQueue(queue, content, options) {
return this.publish('', queue, content, options);
}
consume(queue, callback, options) {
// NB we want the callback to be run synchronously, so that we've
// registered the consumerTag before any messages can arrive.
const fields = Args.consume(queue, options);
return new Promise((resolve, reject) => {
this._rpc(defs.BasicConsume, fields, defs.BasicConsumeOk, (err, ok) => {
if (err) return reject(err);
this.registerConsumer(ok.fields.consumerTag, callback);
resolve(ok.fields);
});
});
}
async cancel(consumerTag) {
const ok = await promisify(cb => {
this._rpc(defs.BasicCancel, Args.cancel(consumerTag),
defs.BasicCancelOk,
cb);
})()
.then(ok => {
this.unregisterConsumer(consumerTag);
return ok.fields;
});
}
get(queue, options) {
const fields = Args.get(queue, options);
return new Promise((resolve, reject) => {
this.sendOrEnqueue(defs.BasicGet, fields, (err, f) => {
if (err) return reject(err);
if (f.id === defs.BasicGetEmpty) {
return resolve(false);
}
else if (f.id === defs.BasicGetOk) {
const fields = f.fields;
this.handleMessage = acceptMessage(m => {
m.fields = fields;
resolve(m);
});
}
else {
reject(new Error(`Unexpected response to BasicGet: ${inspect(f)}`));
}
});
});
}
ack(message, allUpTo) {
this.sendImmediately(
defs.BasicAck,
Args.ack(message.fields.deliveryTag, allUpTo));
}
ackAll() {
this.sendImmediately(defs.BasicAck, Args.ack(0, true));
}
nack(message, allUpTo, requeue) {
this.sendImmediately(
defs.BasicNack,
Args.nack(message.fields.deliveryTag, allUpTo, requeue));
}
nackAll(requeue) {
this.sendImmediately(defs.BasicNack,
Args.nack(0, true, requeue));
}
// `Basic.Nack` is not available in older RabbitMQ versions (or in the
// AMQP specification), so you have to use the one-at-a-time
// `Basic.Reject`. This is otherwise synonymous with
// `#nack(message, false, requeue)`.
reject(message, requeue) {
this.sendImmediately(
defs.BasicReject,
Args.reject(message.fields.deliveryTag, requeue));
}
recover() {
return this.rpc(defs.BasicRecover,
Args.recover(),
defs.BasicRecoverOk);
}
qos(count, global) {
return this.rpc(defs.BasicQos,
Args.prefetch(count, global),
defs.BasicQosOk);
}
}
// There are more options in AMQP than exposed here; RabbitMQ only
// implements prefetch based on message count, and only for individual
// channels or consumers. RabbitMQ v3.3.0 and after treat prefetch
// (without `global` set) as per-consumer (for consumers following),
// and prefetch with `global` set as per-channel.
Channel.prototype.prefetch = Channel.prototype.qos
// Confirm channel. This is a channel with confirms 'switched on',
// meaning sent messages will provoke a responding 'ack' or 'nack'
// from the server. The upshot of this is that `publish` and
// `sendToQueue` both take a callback, which will be called either
// with `null` as its argument to signify 'ack', or an exception as
// its argument to signify 'nack'.
class ConfirmChannel extends Channel {
publish(exchange, routingKey, content, options, cb) {
this.pushConfirmCallback(cb);
return super.publish(exchange, routingKey, content, options);
}
sendToQueue(queue, content, options, cb) {
return this.publish('', queue, content, options, cb);
}
waitForConfirms() {
const awaiting = [];
const unconfirmed = this.unconfirmed;
unconfirmed.forEach((val, index) => {
if (val !== null) {
const confirmed = new Promise((resolve, reject) => {
unconfirmed[index] = err => {
if (val) val(err);
if (err === null) resolve();
else reject(err);
};
});
awaiting.push(confirmed);
}
});
// Channel closed
if (!this.pending) {
var cb;
while (cb = this.unconfirmed.shift()) {
if (cb) cb(new Error('channel closed'));
}
}
return Promise.all(awaiting);
}
}
module.exports.ConfirmChannel = ConfirmChannel;
module.exports.Channel = Channel;
module.exports.ChannelModel = ChannelModel;

345
node_modules/amqplib/lib/codec.js generated vendored Normal file
View File

@@ -0,0 +1,345 @@
//
//
//
/*
The AMQP 0-9-1 is a mess when it comes to the types that can be
encoded on the wire.
There are four encoding schemes, and three overlapping sets of types:
frames, methods, (field-)tables, and properties.
Each *frame type* has a set layout in which values of given types are
concatenated along with sections of "raw binary" data.
In frames there are `shortstr`s, that is length-prefixed strings of
UTF8 chars, 8 bit unsigned integers (called `octet`), unsigned 16 bit
integers (called `short` or `short-uint`), unsigned 32 bit integers
(called `long` or `long-uint`), unsigned 64 bit integers (called
`longlong` or `longlong-uint`), and flags (called `bit`).
Methods are encoded as a frame giving a method ID and a sequence of
arguments of known types. The encoded method argument values are
concatenated (with some fun complications around "packing" consecutive
bit values into bytes).
Along with the types given in frames, method arguments may be long
byte strings (`longstr`, not required to be UTF8) or 64 bit unsigned
integers to be interpreted as timestamps (yeah I don't know why
either), or arbitrary sets of key-value pairs (called `field-table`).
Inside a field table the keys are `shortstr` and the values are
prefixed with a byte tag giving the type. The types are any of the
above except for bits (which are replaced by byte-wide `bool`), along
with a NULL value `void`, a special fixed-precision number encoding
(`decimal`), IEEE754 `float`s and `double`s, signed integers,
`field-array` (a sequence of tagged values), and nested field-tables.
RabbitMQ and QPid use a subset of the field-table types, and different
value tags, established before the AMQP 0-9-1 specification was
published. So far as I know, no-one uses the types and tags as
published. http://www.rabbitmq.com/amqp-0-9-1-errata.html gives the
list of field-table types.
Lastly, there are (sets of) properties, only one of which is given in
AMQP 0-9-1: `BasicProperties`. These are almost the same as methods,
except that they appear in content header frames, which include a
content size, and they carry a set of flags indicating which
properties are present. This scheme can save ones of bytes per message
(messages which take a minimum of three frames each to send).
*/
'use strict';
var ints = require('buffer-more-ints');
// JavaScript uses only doubles so what I'm testing for is whether
// it's *better* to encode a number as a float or double. This really
// just amounts to testing whether there's a fractional part to the
// number, except that see below. NB I don't use bitwise operations to
// do this 'efficiently' -- it would mask the number to 32 bits.
//
// At 2^50, doubles don't have sufficient precision to distinguish
// between floating point and integer numbers (`Math.pow(2, 50) + 0.1
// === Math.pow(2, 50)` (and, above 2^53, doubles cannot represent all
// integers (`Math.pow(2, 53) + 1 === Math.pow(2, 53)`)). Hence
// anything with a magnitude at or above 2^50 may as well be encoded
// as a 64-bit integer. Except that only signed integers are supported
// by RabbitMQ, so anything above 2^63 - 1 must be a double.
function isFloatingPoint(n) {
return n >= 0x8000000000000000 ||
(Math.abs(n) < 0x4000000000000
&& Math.floor(n) !== n);
}
function encodeTable(buffer, val, offset) {
var start = offset;
offset += 4; // leave room for the table length
for (var key in val) {
if (val[key] !== undefined) {
var len = Buffer.byteLength(key);
buffer.writeUInt8(len, offset); offset++;
buffer.write(key, offset, 'utf8'); offset += len;
offset += encodeFieldValue(buffer, val[key], offset);
}
}
var size = offset - start;
buffer.writeUInt32BE(size - 4, start);
return size;
}
function encodeArray(buffer, val, offset) {
var start = offset;
offset += 4;
for (var i=0, num=val.length; i < num; i++) {
offset += encodeFieldValue(buffer, val[i], offset);
}
var size = offset - start;
buffer.writeUInt32BE(size - 4, start);
return size;
}
function encodeFieldValue(buffer, value, offset) {
var start = offset;
var type = typeof value, val = value;
// A trapdoor for specifying a type, e.g., timestamp
if (value && type === 'object' && value.hasOwnProperty('!')) {
val = value.value;
type = value['!'];
}
// If it's a JS number, we'll have to guess what type to encode it
// as.
if (type == 'number') {
// Making assumptions about the kind of number (floating point
// v integer, signed, unsigned, size) desired is dangerous in
// general; however, in practice RabbitMQ uses only
// longstrings and unsigned integers in its arguments, and
// other clients generally conflate number types anyway. So
// the only distinction we care about is floating point vs
// integers, preferring integers since those can be promoted
// if necessary. If floating point is required, we may as well
// use double precision.
if (isFloatingPoint(val)) {
type = 'double';
}
else { // only signed values are used in tables by
// RabbitMQ. It *used* to (< v3.3.0) treat the byte 'b'
// type as unsigned, but most clients (and the spec)
// think it's signed, and now RabbitMQ does too.
if (val < 128 && val >= -128) {
type = 'byte';
}
else if (val >= -0x8000 && val < 0x8000) {
type = 'short'
}
else if (val >= -0x80000000 && val < 0x80000000) {
type = 'int';
}
else {
type = 'long';
}
}
}
function tag(t) { buffer.write(t, offset); offset++; }
switch (type) {
case 'string': // no shortstr in field tables
var len = Buffer.byteLength(val, 'utf8');
tag('S');
buffer.writeUInt32BE(len, offset); offset += 4;
buffer.write(val, offset, 'utf8'); offset += len;
break;
case 'object':
if (val === null) {
tag('V');
}
else if (Array.isArray(val)) {
tag('A');
offset += encodeArray(buffer, val, offset);
}
else if (Buffer.isBuffer(val)) {
tag('x');
buffer.writeUInt32BE(val.length, offset); offset += 4;
val.copy(buffer, offset); offset += val.length;
}
else {
tag('F');
offset += encodeTable(buffer, val, offset);
}
break;
case 'boolean':
tag('t');
buffer.writeUInt8((val) ? 1 : 0, offset); offset++;
break;
// These are the types that are either guessed above, or
// explicitly given using the {'!': type} notation.
case 'double':
case 'float64':
tag('d');
buffer.writeDoubleBE(val, offset);
offset += 8;
break;
case 'byte':
case 'int8':
tag('b');
buffer.writeInt8(val, offset); offset++;
break;
case 'unsignedbyte':
case 'uint8':
tag('B');
buffer.writeUInt8(val, offset); offset++;
break;
case 'short':
case 'int16':
tag('s');
buffer.writeInt16BE(val, offset); offset += 2;
break;
case 'unsignedshort':
case 'uint16':
tag('u');
buffer.writeUInt16BE(val, offset); offset += 2;
break;
case 'int':
case 'int32':
tag('I');
buffer.writeInt32BE(val, offset); offset += 4;
break;
case 'unsignedint':
case 'uint32':
tag('i');
buffer.writeUInt32BE(val, offset); offset += 4;
break;
case 'long':
case 'int64':
tag('l');
ints.writeInt64BE(buffer, val, offset); offset += 8;
break;
// Now for exotic types, those can _only_ be denoted by using
// `{'!': type, value: val}
case 'timestamp':
tag('T');
ints.writeUInt64BE(buffer, val, offset); offset += 8;
break;
case 'float':
tag('f');
buffer.writeFloatBE(val, offset); offset += 4;
break;
case 'decimal':
tag('D');
if (val.hasOwnProperty('places') && val.hasOwnProperty('digits')
&& val.places >= 0 && val.places < 256) {
buffer[offset] = val.places; offset++;
buffer.writeUInt32BE(val.digits, offset); offset += 4;
}
else throw new TypeError(
"Decimal value must be {'places': 0..255, 'digits': uint32}, " +
"got " + JSON.stringify(val));
break;
default:
throw new TypeError('Unknown type to encode: ' + type);
}
return offset - start;
}
// Assume we're given a slice of the buffer that contains just the
// fields.
function decodeFields(slice) {
var fields = {}, offset = 0, size = slice.length;
var len, key, val;
function decodeFieldValue() {
var tag = String.fromCharCode(slice[offset]); offset++;
switch (tag) {
case 'b':
val = slice.readInt8(offset); offset++;
break;
case 'B':
val = slice.readUInt8(offset); offset++;
break;
case 'S':
len = slice.readUInt32BE(offset); offset += 4;
val = slice.toString('utf8', offset, offset + len);
offset += len;
break;
case 'I':
val = slice.readInt32BE(offset); offset += 4;
break;
case 'i':
val = slice.readUInt32BE(offset); offset += 4;
break;
case 'D': // only positive decimals, apparently.
var places = slice[offset]; offset++;
var digits = slice.readUInt32BE(offset); offset += 4;
val = {'!': 'decimal', value: {places: places, digits: digits}};
break;
case 'T':
val = ints.readUInt64BE(slice, offset); offset += 8;
val = {'!': 'timestamp', value: val};
break;
case 'F':
len = slice.readUInt32BE(offset); offset += 4;
val = decodeFields(slice.subarray(offset, offset + len));
offset += len;
break;
case 'A':
len = slice.readUInt32BE(offset); offset += 4;
decodeArray(offset + len);
// NB decodeArray will itself update offset and val
break;
case 'd':
val = slice.readDoubleBE(offset); offset += 8;
break;
case 'f':
val = slice.readFloatBE(offset); offset += 4;
break;
case 'l':
val = ints.readInt64BE(slice, offset); offset += 8;
break;
case 's':
val = slice.readInt16BE(offset); offset += 2;
break;
case 'u':
val = slice.readUInt16BE(offset); offset += 2;
break;
case 't':
val = slice[offset] != 0; offset++;
break;
case 'V':
val = null;
break;
case 'x':
len = slice.readUInt32BE(offset); offset += 4;
val = slice.subarray(offset, offset + len);
offset += len;
break;
default:
throw new TypeError('Unexpected type tag "' + tag +'"');
}
}
function decodeArray(until) {
var vals = [];
while (offset < until) {
decodeFieldValue();
vals.push(val);
}
val = vals;
}
while (offset < size) {
len = slice.readUInt8(offset); offset++;
key = slice.toString('utf8', offset, offset + len);
offset += len;
decodeFieldValue();
fields[key] = val;
}
return fields;
}
module.exports.encodeTable = encodeTable;
module.exports.decodeFields = decodeFields;

189
node_modules/amqplib/lib/connect.js generated vendored Normal file
View File

@@ -0,0 +1,189 @@
//
//
//
// General-purpose API for glueing everything together.
'use strict';
var URL = require('url-parse');
var QS = require('querystring');
var Connection = require('./connection').Connection;
var fmt = require('util').format;
var credentials = require('./credentials');
function copyInto(obj, target) {
var keys = Object.keys(obj);
var i = keys.length;
while (i--) {
var k = keys[i];
target[k] = obj[k];
}
return target;
}
// Adapted from util._extend, which is too fringe to use.
function clone(obj) {
return copyInto(obj, {});
}
var CLIENT_PROPERTIES = {
"product": "amqplib",
"version": require('../package.json').version,
"platform": fmt('Node.JS %s', process.version),
"information": "https://amqp-node.github.io/amqplib/",
"capabilities": {
"publisher_confirms": true,
"exchange_exchange_bindings": true,
"basic.nack": true,
"consumer_cancel_notify": true,
"connection.blocked": true,
"authentication_failure_close": true
}
};
// Construct the main frames used in the opening handshake
function openFrames(vhost, query, credentials, extraClientProperties) {
if (!vhost)
vhost = '/';
else
vhost = QS.unescape(vhost);
var query = query || {};
function intOrDefault(val, def) {
return (val === undefined) ? def : parseInt(val);
}
var clientProperties = Object.create(CLIENT_PROPERTIES);
return {
// start-ok
'clientProperties': copyInto(extraClientProperties, clientProperties),
'mechanism': credentials.mechanism,
'response': credentials.response(),
'locale': query.locale || 'en_US',
// tune-ok
'channelMax': intOrDefault(query.channelMax, 0),
'frameMax': intOrDefault(query.frameMax, 131072),
'heartbeat': intOrDefault(query.heartbeat, 0),
// open
'virtualHost': vhost,
'capabilities': '',
'insist': 0
};
}
// Decide on credentials based on what we're supplied.
function credentialsFromUrl(parts) {
var user = 'guest', passwd = 'guest';
if (parts.username != '' || parts.password != '') {
user = (parts.username) ? unescape(parts.username) : '';
passwd = (parts.password) ? unescape(parts.password) : '';
}
return credentials.plain(user, passwd);
}
function connect(url, socketOptions, openCallback) {
// tls.connect uses `util._extend()` on the options given it, which
// copies only properties mentioned in `Object.keys()`, when
// processing the options. So I have to make copies too, rather
// than using `Object.create()`.
var sockopts = clone(socketOptions || {});
url = url || 'amqp://localhost';
var noDelay = !!sockopts.noDelay;
var timeout = sockopts.timeout;
var keepAlive = !!sockopts.keepAlive;
// 0 is default for node
var keepAliveDelay = sockopts.keepAliveDelay || 0;
var extraClientProperties = sockopts.clientProperties || {};
var protocol, fields;
if (typeof url === 'object') {
protocol = (url.protocol || 'amqp') + ':';
sockopts.host = url.hostname;
sockopts.servername = sockopts.servername || url.hostname;
sockopts.port = url.port || ((protocol === 'amqp:') ? 5672 : 5671);
var user, pass;
// Only default if both are missing, to have the same behaviour as
// the stringly URL.
if (url.username == undefined && url.password == undefined) {
user = 'guest'; pass = 'guest';
} else {
user = url.username || '';
pass = url.password || '';
}
var config = {
locale: url.locale,
channelMax: url.channelMax,
frameMax: url.frameMax,
heartbeat: url.heartbeat,
};
fields = openFrames(url.vhost, config, sockopts.credentials || credentials.plain(user, pass), extraClientProperties);
} else {
var parts = URL(url, true); // yes, parse the query string
protocol = parts.protocol;
sockopts.host = parts.hostname;
sockopts.servername = sockopts.servername || parts.hostname;
sockopts.port = parseInt(parts.port) || ((protocol === 'amqp:') ? 5672 : 5671);
var vhost = parts.pathname ? parts.pathname.substr(1) : null;
fields = openFrames(vhost, parts.query, sockopts.credentials || credentialsFromUrl(parts), extraClientProperties);
}
var sockok = false;
var sock;
function onConnect() {
sockok = true;
sock.setNoDelay(noDelay);
if (keepAlive) sock.setKeepAlive(keepAlive, keepAliveDelay);
var c = new Connection(sock);
c.open(fields, function(err, ok) {
// disable timeout once the connection is open, we don't want
// it fouling things
if (timeout) sock.setTimeout(0);
if (err === null) {
openCallback(null, c);
} else {
// The connection isn't closed by the server on e.g. wrong password
sock.end();
sock.destroy();
openCallback(err);
}
});
}
if (protocol === 'amqp:') {
sock = require('net').connect(sockopts, onConnect);
}
else if (protocol === 'amqps:') {
sock = require('tls').connect(sockopts, onConnect);
}
else {
throw new Error("Expected amqp: or amqps: as the protocol; got " + protocol);
}
if (timeout) {
sock.setTimeout(timeout, function() {
sock.end();
sock.destroy();
openCallback(new Error('connect ETIMEDOUT'));
});
}
sock.once('error', function(err) {
if (!sockok) openCallback(err);
});
}
module.exports.connect = connect;
module.exports.credentialsFromUrl = credentialsFromUrl;

675
node_modules/amqplib/lib/connection.js generated vendored Normal file
View File

@@ -0,0 +1,675 @@
//
//
//
'use strict';
var defs = require('./defs');
var constants = defs.constants;
var frame = require('./frame');
var HEARTBEAT = frame.HEARTBEAT;
var Mux = require('./mux').Mux;
var Duplex = require('stream').Duplex;
var EventEmitter = require('events');
var Heart = require('./heartbeat').Heart;
var methodName = require('./format').methodName;
var closeMsg = require('./format').closeMessage;
var inspect = require('./format').inspect;
var BitSet = require('./bitset').BitSet;
var fmt = require('util').format;
var PassThrough = require('stream').PassThrough;
var IllegalOperationError = require('./error').IllegalOperationError;
var stackCapture = require('./error').stackCapture;
// High-water mark for channel write buffers, in 'objects' (which are
// encoded frames as buffers).
var DEFAULT_WRITE_HWM = 1024;
// If all the frames of a message (method, properties, content) total
// to less than this, copy them into a single buffer and write it all
// at once. Note that this is less than the minimum frame size: if it
// was greater, we might have to fragment the content.
var SINGLE_CHUNK_THRESHOLD = 2048;
class Connection extends EventEmitter {
constructor (underlying) {
super();
var stream = this.stream = wrapStream(underlying);
this.muxer = new Mux(stream);
// frames
this.rest = Buffer.alloc(0);
this.frameMax = constants.FRAME_MIN_SIZE;
this.sentSinceLastCheck = false;
this.recvSinceLastCheck = false;
this.expectSocketClose = false;
this.freeChannels = new BitSet();
this.channels = [{
channel: { accept: channel0(this) },
buffer: underlying
}];
}
// This changed between versions, as did the codec, methods, etc. AMQP
// 0-9-1 is fairly similar to 0.8, but better, and nothing implements
// 0.8 that doesn't implement 0-9-1. In other words, it doesn't make
// much sense to generalise here.
sendProtocolHeader () {
this.sendBytes(frame.PROTOCOL_HEADER);
}
/*
The frighteningly complicated opening protocol (spec section 2.2.4):
Client -> Server
protocol header ->
<- start
start-ok ->
.. next two zero or more times ..
<- secure
secure-ok ->
<- tune
tune-ok ->
open ->
<- open-ok
If I'm only supporting SASL's PLAIN mechanism (which I am for the time
being), it gets a bit easier since the server won't in general send
back a `secure`, it'll just send `tune` after the `start-ok`.
(SASL PLAIN: http://tools.ietf.org/html/rfc4616)
*/
open (allFields, openCallback0) {
var self = this;
var openCallback = openCallback0 || function () { };
// This is where we'll put our negotiated values
var tunedOptions = Object.create(allFields);
function wait (k) {
self.step(function (err, frame) {
if (err !== null)
bail(err);
else if (frame.channel !== 0) {
bail(new Error(
fmt("Frame on channel != 0 during handshake: %s",
inspect(frame, false))));
}
else
k(frame);
});
}
function expect (Method, k) {
wait(function (frame) {
if (frame.id === Method)
k(frame);
else {
bail(new Error(
fmt("Expected %s; got %s",
methodName(Method), inspect(frame, false))));
}
});
}
function bail (err) {
openCallback(err);
}
function send (Method) {
// This can throw an exception if there's some problem with the
// options; e.g., something is a string instead of a number.
self.sendMethod(0, Method, tunedOptions);
}
function negotiate (server, desired) {
// We get sent values for channelMax, frameMax and heartbeat,
// which we may accept or lower (subject to a minimum for
// frameMax, but we'll leave that to the server to enforce). In
// all cases, `0` really means "no limit", or rather the highest
// value in the encoding, e.g., unsigned short for channelMax.
if (server === 0 || desired === 0) {
// i.e., whichever places a limit, if either
return Math.max(server, desired);
}
else {
return Math.min(server, desired);
}
}
function onStart (start) {
var mechanisms = start.fields.mechanisms.toString().split(' ');
if (mechanisms.indexOf(allFields.mechanism) < 0) {
bail(new Error(fmt('SASL mechanism %s is not provided by the server',
allFields.mechanism)));
return;
}
self.serverProperties = start.fields.serverProperties;
try {
send(defs.ConnectionStartOk);
} catch (err) {
bail(err);
return;
}
wait(afterStartOk);
}
function afterStartOk (reply) {
switch (reply.id) {
case defs.ConnectionSecure:
bail(new Error(
"Wasn't expecting to have to go through secure"));
break;
case defs.ConnectionClose:
bail(new Error(fmt("Handshake terminated by server: %s",
closeMsg(reply))));
break;
case defs.ConnectionTune:
var fields = reply.fields;
tunedOptions.frameMax =
negotiate(fields.frameMax, allFields.frameMax);
tunedOptions.channelMax =
negotiate(fields.channelMax, allFields.channelMax);
tunedOptions.heartbeat =
negotiate(fields.heartbeat, allFields.heartbeat);
try {
send(defs.ConnectionTuneOk);
send(defs.ConnectionOpen);
} catch (err) {
bail(err);
return;
}
expect(defs.ConnectionOpenOk, onOpenOk);
break;
default:
bail(new Error(
fmt("Expected connection.secure, connection.close, " +
"or connection.tune during handshake; got %s",
inspect(reply, false))));
break;
}
}
function onOpenOk (openOk) {
// Impose the maximum of the encoded value, if the negotiated
// value is zero, meaning "no, no limits"
self.channelMax = tunedOptions.channelMax || 0xffff;
self.frameMax = tunedOptions.frameMax || 0xffffffff;
// 0 means "no heartbeat", rather than "maximum period of
// heartbeating"
self.heartbeat = tunedOptions.heartbeat;
self.heartbeater = self.startHeartbeater();
self.accept = mainAccept;
succeed(openOk);
}
// If the server closes the connection, it's probably because of
// something we did
function endWhileOpening (err) {
bail(err || new Error('Socket closed abruptly ' +
'during opening handshake'));
}
this.stream.on('end', endWhileOpening);
this.stream.on('error', endWhileOpening);
function succeed (ok) {
self.stream.removeListener('end', endWhileOpening);
self.stream.removeListener('error', endWhileOpening);
self.stream.on('error', self.onSocketError.bind(self));
self.stream.on('end', self.onSocketError.bind(
self, new Error('Unexpected close')));
self.on('frameError', self.onSocketError.bind(self));
self.acceptLoop();
openCallback(null, ok);
}
// Now kick off the handshake by prompting the server
this.sendProtocolHeader();
expect(defs.ConnectionStart, onStart);
}
// Closing things: AMQP has a closing handshake that applies to
// closing both connects and channels. As the initiating party, I send
// Close, then ignore all frames until I see either CloseOK --
// which signifies that the other party has seen the Close and shut
// the connection or channel down, so it's fine to free resources; or
// Close, which means the other party also wanted to close the
// whatever, and I should send CloseOk so it can free resources,
// then go back to waiting for the CloseOk. If I receive a Close
// out of the blue, I should throw away any unsent frames (they will
// be ignored anyway) and send CloseOk, then clean up resources. In
// general, Close out of the blue signals an error (or a forced
// closure, which may as well be an error).
//
// RUNNING [1] --- send Close ---> Closing [2] ---> recv Close --+
// | | [3]
// | +------ send CloseOk ------+
// recv Close recv CloseOk
// | |
// V V
// Ended [4] ---- send CloseOk ---> Closed [5]
//
// [1] All frames accepted; getting a Close frame from the server
// moves to Ended; client may initiate a close by sending Close
// itself.
// [2] Client has initiated a close; only CloseOk or (simulataneously
// sent) Close is accepted.
// [3] Simultaneous close
// [4] Server won't send any more frames; accept no more frames, send
// CloseOk.
// [5] Fully closed, client will send no more, server will send no
// more. Signal 'close' or 'error'.
//
// There are two signalling mechanisms used in the API. The first is
// that calling `close` will return a promise, that will either
// resolve once the connection or channel is cleanly shut down, or
// will reject if the shutdown times out.
//
// The second is the 'close' and 'error' events. These are
// emitted as above. The events will fire *before* promises are
// resolved.
// Close the connection without even giving a reason. Typical.
close (closeCallback) {
var k = closeCallback && function () { closeCallback(null); };
this.closeBecause("Cheers, thanks", constants.REPLY_SUCCESS, k);
}
// Close with a reason and a 'code'. I'm pretty sure RabbitMQ totally
// ignores these; maybe it logs them. The continuation will be invoked
// when the CloseOk has been received, and before the 'close' event.
closeBecause (reason, code, k) {
this.sendMethod(0, defs.ConnectionClose, {
replyText: reason,
replyCode: code,
methodId: 0, classId: 0
});
var s = stackCapture('closeBecause called: ' + reason);
this.toClosing(s, k);
}
closeWithError (reason, code, error) {
this.emit('error', error);
this.closeBecause(reason, code);
}
onSocketError (err) {
if (!this.expectSocketClose) {
// forestall any more calls to onSocketError, since we're signed
// up for `'error'` *and* `'end'`
this.expectSocketClose = true;
this.emit('error', err);
var s = stackCapture('Socket error');
this.toClosed(s, err);
}
}
// A close has been initiated. Repeat: a close has been initiated.
// This means we should not send more frames, anyway they will be
// ignored. We also have to shut down all the channels.
toClosing (capturedStack, k) {
var send = this.sendMethod.bind(this);
this.accept = function (f) {
if (f.id === defs.ConnectionCloseOk) {
if (k)
k();
var s = stackCapture('ConnectionCloseOk received');
this.toClosed(s, undefined);
}
else if (f.id === defs.ConnectionClose) {
send(0, defs.ConnectionCloseOk, {});
}
// else ignore frame
};
invalidateSend(this, 'Connection closing', capturedStack);
}
_closeChannels (capturedStack) {
for (var i = 1; i < this.channels.length; i++) {
var ch = this.channels[i];
if (ch !== null) {
ch.channel.toClosed(capturedStack); // %%% or with an error? not clear
}
}
}
// A close has been confirmed. Cease all communication.
toClosed (capturedStack, maybeErr) {
this._closeChannels(capturedStack);
var info = fmt('Connection closed (%s)',
(maybeErr) ? maybeErr.toString() : 'by client');
// Tidy up, invalidate enverything, dynamite the bridges.
invalidateSend(this, info, capturedStack);
this.accept = invalidOp(info, capturedStack);
this.close = function (cb) {
cb && cb(new IllegalOperationError(info, capturedStack));
};
if (this.heartbeater)
this.heartbeater.clear();
// This is certainly true now, if it wasn't before
this.expectSocketClose = true;
this.stream.end();
this.emit('close', maybeErr);
}
_updateSecret(newSecret, reason, cb) {
this.sendMethod(0, defs.ConnectionUpdateSecret, {
newSecret,
reason
});
this.once('update-secret-ok', cb);
}
// ===
startHeartbeater () {
if (this.heartbeat === 0)
return null;
else {
var self = this;
var hb = new Heart(this.heartbeat,
this.checkSend.bind(this),
this.checkRecv.bind(this));
hb.on('timeout', function () {
var hberr = new Error("Heartbeat timeout");
self.emit('error', hberr);
var s = stackCapture('Heartbeat timeout');
self.toClosed(s, hberr);
});
hb.on('beat', function () {
self.sendHeartbeat();
});
return hb;
}
}
// I use an array to keep track of the channels, rather than an
// object. The channel identifiers are numbers, and allocated by the
// connection. If I try to allocate low numbers when they are
// available (which I do, by looking from the start of the bitset),
// this ought to keep the array small, and out of 'sparse array
// storage'. I also set entries to null, rather than deleting them, in
// the expectation that the next channel allocation will fill the slot
// again rather than growing the array. See
// http://www.html5rocks.com/en/tutorials/speed/v8/
freshChannel (channel, options) {
var next = this.freeChannels.nextClearBit(1);
if (next < 0 || next > this.channelMax)
throw new Error("No channels left to allocate");
this.freeChannels.set(next);
var hwm = (options && options.highWaterMark) || DEFAULT_WRITE_HWM;
var writeBuffer = new PassThrough({
objectMode: true, highWaterMark: hwm
});
this.channels[next] = { channel: channel, buffer: writeBuffer };
writeBuffer.on('drain', function () {
channel.onBufferDrain();
});
this.muxer.pipeFrom(writeBuffer);
return next;
}
releaseChannel (channel) {
this.freeChannels.clear(channel);
var buffer = this.channels[channel].buffer;
buffer.end(); // will also cause it to be unpiped
this.channels[channel] = null;
}
acceptLoop () {
var self = this;
function go () {
try {
var f; while (f = self.recvFrame())
self.accept(f);
}
catch (e) {
self.emit('frameError', e);
}
}
self.stream.on('readable', go);
go();
}
step (cb) {
var self = this;
function recv () {
var f;
try {
f = self.recvFrame();
}
catch (e) {
cb(e, null);
return;
}
if (f)
cb(null, f);
else
self.stream.once('readable', recv);
}
recv();
}
checkSend () {
var check = this.sentSinceLastCheck;
this.sentSinceLastCheck = false;
return check;
}
checkRecv () {
var check = this.recvSinceLastCheck;
this.recvSinceLastCheck = false;
return check;
}
sendBytes (bytes) {
this.sentSinceLastCheck = true;
this.stream.write(bytes);
}
sendHeartbeat () {
return this.sendBytes(frame.HEARTBEAT_BUF);
}
sendMethod (channel, Method, fields) {
var frame = encodeMethod(Method, channel, fields);
this.sentSinceLastCheck = true;
var buffer = this.channels[channel].buffer;
return buffer.write(frame);
}
sendMessage (channel, Method, fields, Properties, props, content) {
if (!Buffer.isBuffer(content))
throw new TypeError('content is not a buffer');
var mframe = encodeMethod(Method, channel, fields);
var pframe = encodeProperties(Properties, channel,
content.length, props);
var buffer = this.channels[channel].buffer;
this.sentSinceLastCheck = true;
var methodHeaderLen = mframe.length + pframe.length;
var bodyLen = (content.length > 0) ?
content.length + FRAME_OVERHEAD : 0;
var allLen = methodHeaderLen + bodyLen;
if (allLen < SINGLE_CHUNK_THRESHOLD) {
// Use `allocUnsafe` to avoid excessive allocations and CPU usage
// from zeroing. The returned Buffer is not zeroed and so must be
// completely filled to be used safely.
// See https://github.com/amqp-node/amqplib/pull/695
var all = Buffer.allocUnsafe(allLen);
var offset = mframe.copy(all, 0);
offset += pframe.copy(all, offset);
if (bodyLen > 0)
makeBodyFrame(channel, content).copy(all, offset);
return buffer.write(all);
}
else {
if (methodHeaderLen < SINGLE_CHUNK_THRESHOLD) {
// Use `allocUnsafe` to avoid excessive allocations and CPU usage
// from zeroing. The returned Buffer is not zeroed and so must be
// completely filled to be used safely.
// See https://github.com/amqp-node/amqplib/pull/695
var both = Buffer.allocUnsafe(methodHeaderLen);
var offset = mframe.copy(both, 0);
pframe.copy(both, offset);
buffer.write(both);
}
else {
buffer.write(mframe);
buffer.write(pframe);
}
return this.sendContent(channel, content);
}
}
sendContent (channel, body) {
if (!Buffer.isBuffer(body)) {
throw new TypeError(fmt("Expected buffer; got %s", body));
}
var writeResult = true;
var buffer = this.channels[channel].buffer;
var maxBody = this.frameMax - FRAME_OVERHEAD;
for (var offset = 0; offset < body.length; offset += maxBody) {
var end = offset + maxBody;
var slice = (end > body.length) ? body.subarray(offset) : body.subarray(offset, end);
var bodyFrame = makeBodyFrame(channel, slice);
writeResult = buffer.write(bodyFrame);
}
this.sentSinceLastCheck = true;
return writeResult;
}
recvFrame () {
// %%% identifying invariants might help here?
var frame = parseFrame(this.rest);
if (!frame) {
var incoming = this.stream.read();
if (incoming === null) {
return false;
}
else {
this.recvSinceLastCheck = true;
this.rest = Buffer.concat([this.rest, incoming]);
return this.recvFrame();
}
}
else {
this.rest = frame.rest;
return decodeFrame(frame);
}
}
}
// Usual frame accept mode
function mainAccept(frame) {
var rec = this.channels[frame.channel];
if (rec) { return rec.channel.accept(frame); }
// NB CHANNEL_ERROR may not be right, but I don't know what is ..
else
this.closeWithError(
fmt('Frame on unknown channel %d', frame.channel),
constants.CHANNEL_ERROR,
new Error(fmt("Frame on unknown channel: %s",
inspect(frame, false))));
}
// Handle anything that comes through on channel 0, that's the
// connection control channel. This is only used once mainAccept is
// installed as the frame handler, after the opening handshake.
function channel0(connection) {
return function(f) {
// Once we get a 'close', we know 1. we'll get no more frames, and
// 2. anything we send except close, or close-ok, will be
// ignored. If we already sent 'close', this won't be invoked since
// we're already in closing mode; if we didn't well we're not going
// to send it now are we.
if (f === HEARTBEAT); // ignore; it's already counted as activity
// on the socket, which is its purpose
else if (f.id === defs.ConnectionClose) {
// Oh. OK. I guess we're done here then.
connection.sendMethod(0, defs.ConnectionCloseOk, {});
var emsg = fmt('Connection closed: %s', closeMsg(f));
var s = stackCapture(emsg);
var e = new Error(emsg);
e.code = f.fields.replyCode;
if (isFatalError(e)) {
connection.emit('error', e);
}
connection.toClosed(s, e);
}
else if (f.id === defs.ConnectionBlocked) {
connection.emit('blocked', f.fields.reason);
}
else if (f.id === defs.ConnectionUnblocked) {
connection.emit('unblocked');
}
else if (f.id === defs.ConnectionUpdateSecretOk) {
connection.emit('update-secret-ok');
}
else {
connection.closeWithError(
fmt("Unexpected frame on channel 0"),
constants.UNEXPECTED_FRAME,
new Error(fmt("Unexpected frame on channel 0: %s",
inspect(f, false))));
}
};
}
function invalidOp(msg, stack) {
return function() {
throw new IllegalOperationError(msg, stack);
};
}
function invalidateSend(conn, msg, stack) {
conn.sendMethod = conn.sendContent = conn.sendMessage =
invalidOp(msg, stack);
}
var encodeMethod = defs.encodeMethod;
var encodeProperties = defs.encodeProperties;
var FRAME_OVERHEAD = defs.FRAME_OVERHEAD;
var makeBodyFrame = frame.makeBodyFrame;
var parseFrame = frame.parseFrame;
var decodeFrame = frame.decodeFrame;
function wrapStream(s) {
if (s instanceof Duplex) return s;
else {
var ws = new Duplex();
ws.wrap(s); //wraps the readable side of things
ws._write = function(chunk, encoding, callback) {
return s.write(chunk, encoding, callback);
};
return ws;
}
}
function isFatalError(error) {
switch (error && error.code) {
case defs.constants.CONNECTION_FORCED:
case defs.constants.REPLY_SUCCESS:
return false;
default:
return true;
}
}
module.exports.Connection = Connection;
module.exports.isFatalError = isFatalError;

42
node_modules/amqplib/lib/credentials.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
//
//
//
// Different kind of credentials that can be supplied when opening a
// connection, corresponding to SASL mechanisms There's only two
// useful mechanisms that RabbitMQ implements:
// * PLAIN (send username and password in the plain)
// * EXTERNAL (assume the server will figure out who you are from
// context, i.e., your SSL certificate)
var codec = require('./codec')
module.exports.plain = function(user, passwd) {
return {
mechanism: 'PLAIN',
response: function() {
return Buffer.from(['', user, passwd].join(String.fromCharCode(0)))
},
username: user,
password: passwd
}
}
module.exports.amqplain = function(user, passwd) {
return {
mechanism: 'AMQPLAIN',
response: function() {
const buffer = Buffer.alloc(16384);
const size = codec.encodeTable(buffer, { LOGIN: user, PASSWORD: passwd}, 0);
return buffer.subarray(4, size);
},
username: user,
password: passwd
}
}
module.exports.external = function() {
return {
mechanism: 'EXTERNAL',
response: function() { return Buffer.from(''); }
}
}

5077
node_modules/amqplib/lib/defs.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

24
node_modules/amqplib/lib/error.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
var inherits = require('util').inherits;
function trimStack(stack, num) {
return stack && stack.split('\n').slice(num).join('\n');
}
function IllegalOperationError(msg, stack) {
var tmp = new Error();
this.message = msg;
this.stack = this.toString() + '\n' + trimStack(tmp.stack, 2);
this.stackAtStateChange = stack;
}
inherits(IllegalOperationError, Error);
IllegalOperationError.prototype.name = 'IllegalOperationError';
function stackCapture(reason) {
var e = new Error();
return 'Stack capture: ' + reason + '\n' +
trimStack(e.stack, 2);
}
module.exports.IllegalOperationError = IllegalOperationError;
module.exports.stackCapture = stackCapture;

39
node_modules/amqplib/lib/format.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
//
//
//
// Stringifying various things
'use strict';
var defs = require('./defs');
var format = require('util').format;
var HEARTBEAT = require('./frame').HEARTBEAT;
module.exports.closeMessage = function(close) {
var code = close.fields.replyCode;
return format('%d (%s) with message "%s"',
code, defs.constant_strs[code],
close.fields.replyText);
}
module.exports.methodName = function(id) {
return defs.info(id).name;
};
module.exports.inspect = function(frame, showFields) {
if (frame === HEARTBEAT) {
return '<Heartbeat>';
}
else if (!frame.id) {
return format('<Content channel:%d size:%d>',
frame.channel, frame.size);
}
else {
var info = defs.info(frame.id);
return format('<%s channel:%d%s>', info.name, frame.channel,
(showFields)
? ' ' + JSON.stringify(frame.fields, undefined, 2)
: '');
}
}

175
node_modules/amqplib/lib/frame.js generated vendored Normal file
View File

@@ -0,0 +1,175 @@
// The river sweeps through
// Silt and twigs, gravel and leaves
// Driving the wheel on
'use strict';
const ints = require('buffer-more-ints')
var defs = require('./defs');
var constants = defs.constants;
var decode = defs.decode;
module.exports.PROTOCOL_HEADER = "AMQP" + String.fromCharCode(0, 0, 9, 1);
/*
Frame format:
0 1 3 7 size+7 size+8
+------+---------+-------------+ +------------+ +-----------+
| type | channel | size | | payload | | frame-end |
+------+---------+-------------+ +------------+ +-----------+
octet short long size octets octet
In general I want to know those first three things straight away, so I
can discard frames early.
*/
// framing constants
var FRAME_METHOD = constants.FRAME_METHOD,
FRAME_HEARTBEAT = constants.FRAME_HEARTBEAT,
FRAME_HEADER = constants.FRAME_HEADER,
FRAME_BODY = constants.FRAME_BODY,
FRAME_END = constants.FRAME_END;
// expected byte sizes for frame parts
const TYPE_BYTES = 1
const CHANNEL_BYTES = 2
const SIZE_BYTES = 4
const FRAME_HEADER_BYTES = TYPE_BYTES + CHANNEL_BYTES + SIZE_BYTES
const FRAME_END_BYTES = 1
/**
* @typedef {{
* type: number,
* channel: number,
* size: number,
* payload: Buffer,
* rest: Buffer
* }} FrameStructure
*/
/**
* This is a polyfill which will read a big int 64 bit as a number.
* @arg { Buffer } buffer
* @arg { number } offset
* @returns { number }
*/
function readInt64BE(buffer, offset) {
/**
* We try to use native implementation if available here because
* buffer-more-ints does not
*/
if (typeof Buffer.prototype.readBigInt64BE === 'function') {
return Number(buffer.readBigInt64BE(offset))
}
return ints.readInt64BE(buffer, offset)
}
// %%% TESTME possibly better to cons the first bit and write the
// second directly, in the absence of IO lists
/**
* Make a frame header
* @arg { number } channel
* @arg { Buffer } payload
*/
module.exports.makeBodyFrame = function (channel, payload) {
const frameSize = FRAME_HEADER_BYTES + payload.length + FRAME_END_BYTES
const frame = Buffer.alloc(frameSize)
let offset = 0
offset = frame.writeUInt8(FRAME_BODY, offset)
offset = frame.writeUInt16BE(channel, offset)
offset = frame.writeInt32BE(payload.length, offset)
payload.copy(frame, offset)
offset += payload.length
frame.writeUInt8(FRAME_END, offset)
return frame
};
/**
* Parse an AMQP frame
* @arg { Buffer } bin
* @arg { number } max
* @returns { FrameStructure | boolean }
*/
function parseFrame(bin) {
if (bin.length < FRAME_HEADER_BYTES) {
return false
}
const type = bin.readUInt8(0)
const channel = bin.readUInt16BE(1)
const size = bin.readUInt32BE(3)
const totalSize = FRAME_HEADER_BYTES + size + FRAME_END_BYTES
if (bin.length < totalSize) {
return false
}
const frameEnd = bin.readUInt8(FRAME_HEADER_BYTES + size)
if (frameEnd !== FRAME_END) {
throw new Error('Invalid frame')
}
return {
type,
channel,
size,
payload: bin.subarray(FRAME_HEADER_BYTES, FRAME_HEADER_BYTES + size),
rest: bin.subarray(totalSize)
}
}
module.exports.parseFrame = parseFrame;
var HEARTBEAT = {channel: 0};
/**
* Decode AMQP frame into JS object
* @param { FrameStructure } frame
* @returns
*/
module.exports.decodeFrame = (frame) => {
const payload = frame.payload
const channel = frame.channel
switch (frame.type) {
case FRAME_METHOD: {
const id = payload.readUInt32BE(0)
const args = payload.subarray(4)
const fields = decode(id, args)
return { id, channel, fields }
}
case FRAME_HEADER: {
const id = payload.readUInt16BE(0)
// const weight = payload.readUInt16BE(2)
const size = readInt64BE(payload, 4)
const flagsAndfields = payload.subarray(12)
const fields = decode(id, flagsAndfields)
return { id, channel, size, fields }
}
case FRAME_BODY:
return { channel, content: payload }
case FRAME_HEARTBEAT:
return HEARTBEAT
default:
throw new Error('Unknown frame type ' + frame.type)
}
}
// encoded heartbeat
module.exports.HEARTBEAT_BUF = Buffer.from([constants.FRAME_HEARTBEAT,
0, 0, 0, 0, // size = 0
0, 0, // channel = 0
constants.FRAME_END]);
module.exports.HEARTBEAT = HEARTBEAT;

92
node_modules/amqplib/lib/heartbeat.js generated vendored Normal file
View File

@@ -0,0 +1,92 @@
//
//
//
// Heartbeats. In AMQP both clients and servers may expect a heartbeat
// frame if there is no activity on the connection for a negotiated
// period of time. If there's no activity for two such intervals, the
// server or client is allowed to close the connection on the
// presumption that the other party is dead.
//
// The client has two jobs here: the first is to send a heartbeat
// frame if it's not sent any frames for a while, so that the server
// doesn't think it's dead; the second is to check periodically that
// it's seen activity from the server, and to advise if there doesn't
// appear to have been any for over two intervals.
//
// Node.JS timers are a bit unreliable, in that they endeavour only to
// fire at some indeterminate point *after* the given time (rather
// gives the lie to 'realtime', dunnit). Because the scheduler is just
// an event loop, it's quite easy to delay timers indefinitely by
// reacting to some I/O with a lot of computation.
//
// To mitigate this I need a bit of creative interpretation:
//
// - I'll schedule a server activity check for every `interval`, and
// check just how much time has passed. It will overshoot by at
// least a small margin; modulo missing timer deadlines, it'll
// notice between two and three intervals after activity actually
// stops (otherwise, at some point after two intervals).
//
// - Every `interval / 2` I'll check that we've sent something since
// the last check, and if not, send a heartbeat frame. If we're
// really too busy to even run the check for two whole heartbeat
// intervals, there must be a lot of I (but not O, at least not on
// the connection), or computation, in which case perhaps it's best
// the server cuts us off anyway. Why `interval / 2`? Because the
// edge case is that the client sent a frame just after a
// heartbeat, which would mean I only send one after almost two
// intervals. (NB a heartbeat counts as a send, so it'll be checked
// at least twice before sending another)
//
// This design is based largely on RabbitMQ's heartbeating:
// https://github.com/rabbitmq/rabbitmq-common/blob/master/src/rabbit_heartbeat.erl
// %% Yes, I could apply the same 'actually passage of time' thing to
// %% send as well as to recv.
'use strict';
var EventEmitter = require('events');
// Exported so that we can mess with it in tests
module.exports.UNITS_TO_MS = 1000;
class Heart extends EventEmitter {
constructor (interval, checkSend, checkRecv) {
super();
this.interval = interval;
var intervalMs = interval * module.exports.UNITS_TO_MS;
// Function#bind is my new best friend
var beat = this.emit.bind(this, 'beat');
var timeout = this.emit.bind(this, 'timeout');
this.sendTimer = setInterval(
this.runHeartbeat.bind(this, checkSend, beat), intervalMs / 2);
// A timeout occurs if I see nothing for *two consecutive* intervals
var recvMissed = 0;
function missedTwo () {
if (!checkRecv())
return (++recvMissed < 2);
else { recvMissed = 0; return true; }
}
this.recvTimer = setInterval(
this.runHeartbeat.bind(this, missedTwo, timeout), intervalMs);
}
clear () {
clearInterval(this.sendTimer);
clearInterval(this.recvTimer);
}
runHeartbeat (check, fail) {
// Have we seen activity?
if (!check())
fail();
}
}
module.exports.Heart = Heart;

126
node_modules/amqplib/lib/mux.js generated vendored Normal file
View File

@@ -0,0 +1,126 @@
//
//
//
'use strict';
// A Mux is an object into which other readable streams may be piped;
// it then writes 'packets' from the upstreams to the given
// downstream.
var assert = require('assert');
var schedule = (typeof setImmediate === 'function') ?
setImmediate : process.nextTick;
class Mux {
constructor (downstream) {
this.newStreams = [];
this.oldStreams = [];
this.blocked = false;
this.scheduledRead = false;
this.out = downstream;
var self = this;
downstream.on('drain', function () {
self.blocked = false;
self._readIncoming();
});
}
// There are 2 states we can be in:
// - waiting for outbound capacity, which will be signalled by a
// - 'drain' event on the downstream; or,
// - no packets to send, waiting for an inbound buffer to have
// packets, which will be signalled by a 'readable' event
// If we write all packets available whenever there is outbound
// capacity, we will either run out of outbound capacity (`#write`
// returns false), or run out of packets (all calls to an
// `inbound.read()` have returned null).
_readIncoming () {
// We may be sent here speculatively, if an incoming stream has
// become readable
if (this.blocked) return;
var accepting = true;
var out = this.out;
// Try to read a chunk from each stream in turn, until all streams
// are empty, or we exhaust our ability to accept chunks.
function roundrobin (streams) {
var s;
while (accepting && (s = streams.shift())) {
var chunk = s.read();
if (chunk !== null) {
accepting = out.write(chunk);
streams.push(s);
}
}
}
roundrobin(this.newStreams);
// Either we exhausted the new queues, or we ran out of capacity. If
// we ran out of capacity, all the remaining new streams (i.e.,
// those with packets left) become old streams. This effectively
// prioritises streams that keep their buffers close to empty over
// those that are constantly near full.
if (accepting) { // all new queues are exhausted, write as many as
// we can from the old streams
assert.equal(0, this.newStreams.length);
roundrobin(this.oldStreams);
}
else { // ran out of room
assert(this.newStreams.length > 0, "Expect some new streams to remain");
Array.prototype.push.apply(this.oldStreams, this.newStreams);
this.newStreams = [];
}
// We may have exhausted all the old queues, or run out of room;
// either way, all we need to do is record whether we have capacity
// or not, so any speculative reads will know
this.blocked = !accepting;
}
_scheduleRead () {
var self = this;
if (!self.scheduledRead) {
schedule(function () {
self.scheduledRead = false;
self._readIncoming();
});
self.scheduledRead = true;
}
}
pipeFrom (readable) {
var self = this;
function enqueue () {
self.newStreams.push(readable);
self._scheduleRead();
}
function cleanup () {
readable.removeListener('readable', enqueue);
readable.removeListener('error', cleanup);
readable.removeListener('end', cleanup);
readable.removeListener('unpipeFrom', cleanupIfMe);
}
function cleanupIfMe (dest) {
if (dest === self) cleanup();
}
readable.on('unpipeFrom', cleanupIfMe);
readable.on('end', cleanup);
readable.on('error', cleanup);
readable.on('readable', enqueue);
}
unpipeFrom (readable) {
readable.emit('unpipeFrom', this);
}
}
module.exports.Mux = Mux;