rhea
Version:
reactive AMQP 1.0 library
1,452 lines (1,321 loc) • 326 kB
JavaScript
require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (process,Buffer){(function (){
/*
* Copyright 2015 Red Hat Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var errors = require('./errors.js');
var frames = require('./frames.js');
var log = require('./log.js');
var sasl = require('./sasl.js');
var util = require('./util.js');
var EndpointState = require('./endpoint.js');
var Session = require('./session.js');
var Transport = require('./transport.js');
var fs = require('fs');
var os = require('os');
var path = require('path');
var net = require('net');
var tls = require('tls');
var EventEmitter = require('events').EventEmitter;
var AMQP_PROTOCOL_ID = 0x00;
function find_connect_config() {
var paths;
if (process.env.MESSAGING_CONNECT_FILE) {
paths = [process.env.MESSAGING_CONNECT_FILE];
} else {
paths = [process.cwd(), path.join(os.homedir(), '.config/messaging'),'/etc/messaging'].map(function (base) { return path.join(base, '/connect.json'); });
}
for (var i = 0; i < paths.length; i++) {
if (fs.existsSync(paths[i])) {
var obj = JSON.parse(fs.readFileSync(paths[i], 'utf8'));
log.config('using config from %s: %j', paths[i], obj);
return obj;
}
}
return {};
}
function get_default_connect_config() {
var config = find_connect_config();
var options = {};
if (config.scheme === 'amqps') options.transport = 'tls';
if (config.host) options.host = config.host;
if(config.port === 'amqp') options.port = 5672;
else if(config.port === 'amqps') options.port = 5671;
else options.port = config.port;
if (!(config.sasl && config.sasl.enabled === false)) {
if (config.user) options.username = config.user;
else options.username = 'anonymous';
if (config.password) options.password = config.password;
if (config.sasl_mechanisms) options.sasl_mechanisms = config.sasl_mechanisms;
}
if (config.tls) {
if (config.tls.key) options.key = fs.readFileSync(config.tls.key);
if (config.tls.cert) options.cert = fs.readFileSync(config.tls.cert);
if (config.tls.ca) options.ca = [ fs.readFileSync(config.tls.ca) ];
if (config.verify === false || config.tls.verify === false) options.rejectUnauthorized = false;
}
if (options.transport === 'tls') {
options.servername = options.host;
}
return options;
}
function get_socket_id(socket) {
if (socket.get_id_string) return socket.get_id_string();
return socket.localAddress + ':' + socket.localPort + ' -> ' + socket.remoteAddress + ':' + socket.remotePort;
}
function session_per_connection(conn) {
var ssn = null;
return {
'get_session' : function () {
if (!ssn) {
ssn = conn.create_session();
ssn.observers.on('session_close', function () { ssn = null; });
ssn.begin();
}
return ssn;
}
};
}
function restrict(count, f) {
if (count) {
var current = count;
var reset;
return function (successful_attempts) {
if (reset !== successful_attempts) {
current = count;
reset = successful_attempts;
}
if (current--) return f(successful_attempts);
else return -1;
};
} else {
return f;
}
}
function backoff(initial, max) {
var delay = initial;
var reset;
return function (successful_attempts) {
if (reset !== successful_attempts) {
delay = initial;
reset = successful_attempts;
}
var current = delay;
var next = delay*2;
delay = max > next ? next : max;
return current;
};
}
function get_connect_fn(options) {
if (options.transport === undefined || options.transport === 'tcp') {
return net.connect;
} else if (options.transport === 'tls' || options.transport === 'ssl') {
return tls.connect;
} else {
throw Error('Unrecognised transport: ' + options.transport);
}
}
function connection_details(options) {
var details = {};
details.connect = options.connect ? options.connect : get_connect_fn(options);
details.host = options.host ? options.host : 'localhost';
details.port = options.port ? options.port : 5672;
details.options = options;
return details;
}
var aliases = [
'container_id',
'hostname',
'max_frame_size',
'channel_max',
'idle_time_out',
'outgoing_locales',
'incoming_locales',
'offered_capabilities',
'desired_capabilities',
'properties'
];
function remote_property_shortcut(name) {
return function() { return this.remote.open ? this.remote.open[name] : undefined; };
}
function connection_fields(fields) {
var o = {};
aliases.forEach(function (name) {
if (fields[name] !== undefined) {
o[name] = fields[name];
}
});
return o;
}
function set_reconnect(reconnect, connection) {
if (typeof reconnect === 'boolean') {
if (reconnect) {
var initial = connection.get_option('initial_reconnect_delay', 100);
var max = connection.get_option('max_reconnect_delay', 60000);
connection.options.reconnect = restrict(
connection.get_option('reconnect_limit'),
backoff(initial, max)
);
} else {
connection.options.reconnect = false;
}
} else if (typeof reconnect === 'number') {
var fixed = connection.options.reconnect;
connection.options.reconnect = restrict(
connection.get_option('reconnect_limit'),
function() {
return fixed;
}
);
}
}
var conn_counter = 1;
var Connection = function (options, container) {
this.options = {};
if (options) {
for (var k in options) {
this.options[k] = options[k];
}
if ((options.transport === 'tls' || options.transport === 'ssl')
&& options.servername === undefined && options.host !== undefined) {
this.options.servername = options.host;
}
} else {
this.options = get_default_connect_config();
}
this.container = container;
if (!this.options.id) {
this.options.id = 'connection-' + conn_counter++;
}
if (!this.options.container_id) {
this.options.container_id = container ? container.id : util.generate_uuid();
}
if (!this.options.connection_details) {
var self = this;
this.options.connection_details = function() { return connection_details(self.options); };
}
var reconnect = this.get_option('reconnect', true);
set_reconnect(reconnect, this);
this.registered = false;
this.state = new EndpointState();
this.local_channel_map = {};
this.remote_channel_map = {};
this.local = {};
this.remote = {};
this.local.open = frames.open(connection_fields(this.options));
this.local.close = frames.close({});
this.session_policy = session_per_connection(this);
this.amqp_transport = new Transport(this.options.id, AMQP_PROTOCOL_ID, frames.TYPE_AMQP, this);
this.sasl_transport = undefined;
this.transport = this.amqp_transport;
this.conn_established_counter = 0;
this.heartbeat_out = undefined;
this.heartbeat_in = undefined;
this.abort_idle = false;
this.socket_ready = false;
this.scheduled_reconnect = undefined;
this.default_sender = undefined;
this.closed_with_non_fatal_error = false;
var self = this;
aliases.forEach(function (alias) { Object.defineProperty(self, alias, { get: remote_property_shortcut(alias) }); });
Object.defineProperty(this, 'error', { get: function() { return this.remote.close ? this.remote.close.error : undefined; }});
};
Connection.prototype = Object.create(EventEmitter.prototype);
Connection.prototype.constructor = Connection;
Connection.prototype.dispatch = function(name) {
log.events('[%s] Connection got event: %s', this.options.id, name);
if (this.listeners(name).length) {
EventEmitter.prototype.emit.apply(this, arguments);
return true;
} else if (this.container) {
return this.container.dispatch.apply(this.container, arguments);
} else {
return false;
}
};
Connection.prototype._disconnect = function() {
this.state.disconnected();
for (var k in this.local_channel_map) {
this.local_channel_map[k]._disconnect();
}
this.socket_ready = false;
};
Connection.prototype._reconnect = function() {
if (this.abort_idle) {
this.abort_idle = false;
this.local.close.error = undefined;
this.state = new EndpointState();
this.state.open();
}
this.state.reconnect();
this._reset_remote_state();
};
Connection.prototype._reset_remote_state = function() {
//reset transport
this.amqp_transport = new Transport(this.options.id, AMQP_PROTOCOL_ID, frames.TYPE_AMQP, this);
this.sasl_transport = undefined;
this.transport = this.amqp_transport;
//reset remote endpoint state
this.remote = {};
//reset sessions:
this.remote_channel_map = {};
var localChannelMap = this.local_channel_map;
for (var k in localChannelMap) {
localChannelMap[k]._reconnect();
}
};
Connection.prototype.connect = function () {
this.is_server = false;
this.abort_idle = false;
this._reset_remote_state();
this._connect(this.options.connection_details(this.conn_established_counter));
this.open();
return this;
};
Connection.prototype.reconnect = function () {
this.scheduled_reconnect = undefined;
log.reconnect('[%s] reconnecting...', this.options.id);
this._reconnect();
this._connect(this.options.connection_details(this.conn_established_counter));
process.nextTick(this._process.bind(this));
return this;
};
Connection.prototype.set_reconnect = function (reconnect) {
set_reconnect(reconnect, this);
};
Connection.prototype._connect = function (details) {
if (details.connect) {
this.init(details.connect(details.port, details.host, details.options, this.connected.bind(this)));
} else {
this.init(get_connect_fn(details)(details.port, details.host, details.options, this.connected.bind(this)));
}
return this;
};
Connection.prototype.accept = function (socket) {
this.is_server = true;
log.io('[%s] client accepted: %s', this.id, get_socket_id(socket));
this.socket_ready = true;
return this.init(socket);
};
Connection.prototype.abort_socket = function (socket) {
if (socket === this.socket) {
log.io('[%s] aborting socket', this.options.id);
this.socket.end();
if (this.socket.removeAllListeners) {
this.socket.removeAllListeners('data');
this.socket.removeAllListeners('error');
this.socket.removeAllListeners('end');
}
if (typeof this.socket.destroy === 'function') {
this.socket.destroy();
}
this._disconnected();
}
};
Connection.prototype.init = function (socket) {
this.socket = socket;
if (this.get_option('tcp_no_delay', false) && this.socket.setNoDelay) {
this.socket.setNoDelay(true);
}
this.socket.on('data', this.input.bind(this));
this.socket.on('error', this.on_error.bind(this));
this.socket.on('end', this.eof.bind(this));
if (this.is_server) {
var mechs;
if (this.container && Object.getOwnPropertyNames(this.container.sasl_server_mechanisms).length) {
mechs = this.container.sasl_server_mechanisms;
}
if (this.socket.encrypted && this.socket.authorized && this.get_option('enable_sasl_external', false)) {
mechs = sasl.server_add_external(mechs ? util.clone(mechs) : {});
}
if (mechs) {
if (mechs.ANONYMOUS !== undefined && !this.get_option('require_sasl', false)) {
this.sasl_transport = new sasl.Selective(this, mechs);
} else {
this.sasl_transport = new sasl.Server(this, mechs);
}
} else {
if (!this.get_option('disable_sasl', false)) {
var anon = sasl.server_mechanisms();
anon.enable_anonymous();
this.sasl_transport = new sasl.Selective(this, anon);
}
}
} else {
var mechanisms = this.get_option('sasl_mechanisms');
if (!mechanisms) {
var username = this.get_option('username');
var password = this.get_option('password');
var token = this.get_option('token');
if (username) {
mechanisms = sasl.client_mechanisms();
if (password) mechanisms.enable_plain(username, password);
else if (token) mechanisms.enable_xoauth2(username, token);
else mechanisms.enable_anonymous(username);
}
}
if (this.socket.encrypted && this.options.cert && this.get_option('enable_sasl_external', false)) {
if (!mechanisms) mechanisms = sasl.client_mechanisms();
mechanisms.enable_external();
}
if (mechanisms) {
this.sasl_transport = new sasl.Client(this, mechanisms, this.options.sasl_init_hostname || this.options.servername || this.options.host);
}
}
this.transport = this.sasl_transport ? this.sasl_transport : this.amqp_transport;
return this;
};
Connection.prototype.attach_sender = function (options) {
return this.session_policy.get_session().attach_sender(options);
};
Connection.prototype.open_sender = Connection.prototype.attach_sender;//alias
Connection.prototype.attach_receiver = function (options) {
if (this.get_option('tcp_no_delay', true) && this.socket.setNoDelay) {
this.socket.setNoDelay(true);
}
return this.session_policy.get_session().attach_receiver(options);
};
Connection.prototype.open_receiver = Connection.prototype.attach_receiver;//alias
Connection.prototype.get_option = function (name, default_value) {
if (this.options[name] !== undefined) return this.options[name];
else if (this.container) return this.container.get_option(name, default_value);
else return default_value;
};
Connection.prototype.send = function(msg) {
if (this.default_sender === undefined) {
this.default_sender = this.open_sender({target:{}});
}
return this.default_sender.send(msg);
};
Connection.prototype.connected = function () {
this.socket_ready = true;
this.conn_established_counter++;
log.io('[%s] connected %s', this.options.id, get_socket_id(this.socket));
this.output();
};
Connection.prototype.sasl_failed = function (text, condition) {
this.transport_error = new errors.ConnectionError(text, condition ? condition : 'amqp:unauthorized-access', this);
this._handle_error();
this.socket.end();
};
Connection.prototype._is_fatal = function (error_condition) {
var all_errors_non_fatal = this.get_option('all_errors_non_fatal', false);
if (all_errors_non_fatal) {
return false;
} else {
var non_fatal = this.get_option('non_fatal_errors', ['amqp:connection:forced']);
return non_fatal.indexOf(error_condition) < 0;
}
};
Connection.prototype._handle_error = function () {
var error = this.get_error();
if (error) {
var handled = this.dispatch('connection_error', this._context({error:error}));
handled = this.dispatch('connection_close', this._context({error:error})) || handled;
if (!this._is_fatal(error.condition)) {
if (this.state.local_open) {
this.closed_with_non_fatal_error = true;
}
} else if (!handled) {
this.dispatch('error', new errors.ConnectionError(error.description, error.condition, this));
}
return true;
} else {
return false;
}
};
Connection.prototype.get_error = function () {
if (this.transport_error) return this.transport_error;
if (this.remote.close && this.remote.close.error) {
return new errors.ConnectionError(this.remote.close.error.description, this.remote.close.error.condition, this);
}
return undefined;
};
Connection.prototype._get_peer_details = function () {
var s = '';
if (this.remote.open && this.remote.open.container) {
s += this.remote.open.container + ' ';
}
if (this.remote.open && this.remote.open.properties) {
s += JSON.stringify(this.remote.open.properties);
}
return s;
};
Connection.prototype.output = function () {
try {
if (this.socket && this.socket_ready) {
if (this.heartbeat_out) clearTimeout(this.heartbeat_out);
this.transport.write(this.socket);
if (((this.is_closed() && this.state.has_settled()) || this.abort_idle || this.transport_error) && !this.transport.has_writes_pending()) {
this.socket.end();
} else if (this.is_open() && this.remote.open.idle_time_out) {
this.heartbeat_out = setTimeout(this._write_frame.bind(this), this.remote.open.idle_time_out / 2);
}
if (this.local.open.idle_time_out && this.heartbeat_in === undefined) {
this.heartbeat_in = setTimeout(this.idle.bind(this), this.local.open.idle_time_out);
}
}
} catch (e) {
this.saved_error = e;
if (e.name === 'ProtocolError') {
console.error('[' + this.options.id + '] error on write: ' + e + ' ' + this._get_peer_details() + ' ' + e.name);
this.dispatch('protocol_error', e) || console.error('[' + this.options.id + '] error on write: ' + e + ' ' + this._get_peer_details());
} else {
this.dispatch('error', e);
}
this.socket.end();
}
};
function byte_to_hex(value) {
if (value < 16) return '0x0' + Number(value).toString(16);
else return '0x' + Number(value).toString(16);
}
function buffer_to_hex(buffer) {
var bytes = [];
for (var i = 0; i < buffer.length; i++) {
bytes.push(byte_to_hex(buffer[i]));
}
return bytes.join(',');
}
Connection.prototype.input = function (buff) {
var buffer;
try {
if (this.heartbeat_in) clearTimeout(this.heartbeat_in);
log.io('[%s] read %d bytes', this.options.id, buff.length);
if (this.previous_input) {
buffer = Buffer.concat([this.previous_input, buff], this.previous_input.length + buff.length);
this.previous_input = null;
} else {
buffer = buff;
}
var read = this.transport.read(buffer, this);
if (read < buffer.length) {
this.previous_input = buffer.slice(read);
}
if (this.local.open.idle_time_out) this.heartbeat_in = setTimeout(this.idle.bind(this), this.local.open.idle_time_out);
if (this.transport.has_writes_pending()) {
this.output();
} else if (this.is_closed() && this.state.has_settled()) {
this.socket.end();
} else if (this.is_open() && this.remote.open.idle_time_out && !this.heartbeat_out) {
this.heartbeat_out = setTimeout(this._write_frame.bind(this), this.remote.open.idle_time_out / 2);
}
} catch (e) {
this.saved_error = e;
if (e.name === 'ProtocolError') {
this.dispatch('protocol_error', e) ||
console.error('[' + this.options.id + '] error on read: ' + e + ' ' + this._get_peer_details() + ' (buffer:' + buffer_to_hex(buffer) + ')');
} else {
this.dispatch('error', e);
}
this.socket.end();
}
};
Connection.prototype.idle = function () {
if (!this.is_closed()) {
this.abort_idle = true;
this.closed_with_non_fatal_error = true;
this.local.close.error = {condition:'amqp:resource-limit-exceeded', description:'max idle time exceeded'};
this.close();
setTimeout(this.abort_socket.bind(this, this.socket), 1000);
}
};
Connection.prototype.on_error = function (e) {
this._disconnected(e);
};
Connection.prototype.eof = function (e) {
var error = e || this.saved_error;
this.saved_error = undefined;
this._disconnected(error);
};
Connection.prototype._disconnected = function (error) {
if (this.heartbeat_out) {
clearTimeout(this.heartbeat_out);
this.heartbeat_out = undefined;
}
if (this.heartbeat_in) {
clearTimeout(this.heartbeat_in);
this.heartbeat_in = undefined;
}
var was_closed_with_non_fatal_error = this.closed_with_non_fatal_error;
if (this.closed_with_non_fatal_error) {
this.closed_with_non_fatal_error = false;
if (this.options.reconnect) this.open();
}
if ((!this.is_closed() || was_closed_with_non_fatal_error) && this.scheduled_reconnect === undefined) {
this._disconnect();
var disconnect_ctxt = {};
if (error) {
disconnect_ctxt.error = error;
}
if (!this.is_server && !this.transport_error && this.options.reconnect) {
var delay = this.options.reconnect(this.conn_established_counter);
if (delay >= 0) {
log.reconnect('[%s] Scheduled reconnect in ' + delay + 'ms', this.options.id);
this.scheduled_reconnect = setTimeout(this.reconnect.bind(this), delay);
disconnect_ctxt.reconnecting = true;
} else {
disconnect_ctxt.reconnecting = false;
}
}
if (!this.dispatch('disconnected', this._context(disconnect_ctxt))) {
console.warn('[' + this.options.id + '] disconnected %s', disconnect_ctxt.error || '');
}
}
};
Connection.prototype.open = function () {
if (this.state.open()) {
this._register();
}
};
Connection.prototype.close = function (error) {
if (error) this.local.close.error = error;
if (this.state.close()) {
this._register();
}
};
Connection.prototype.is_open = function () {
return this.state.is_open();
};
Connection.prototype.is_remote_open = function () {
return this.state.remote_open;
};
Connection.prototype.is_closed = function () {
return this.state.is_closed();
};
Connection.prototype.create_session = function () {
var i = 0;
while (this.local_channel_map[i]) i++;
var session = new Session(this, i);
this.local_channel_map[i] = session;
return session;
};
Connection.prototype.find_sender = function (filter) {
return this.find_link(util.sender_filter(filter));
};
Connection.prototype.find_receiver = function (filter) {
return this.find_link(util.receiver_filter(filter));
};
Connection.prototype.find_link = function (filter) {
for (var channel in this.local_channel_map) {
var session = this.local_channel_map[channel];
var result = session.find_link(filter);
if (result) return result;
}
return undefined;
};
Connection.prototype.each_receiver = function (action, filter) {
this.each_link(action, util.receiver_filter(filter));
};
Connection.prototype.each_sender = function (action, filter) {
this.each_link(action, util.sender_filter(filter));
};
Connection.prototype.each_link = function (action, filter) {
for (var channel in this.local_channel_map) {
var session = this.local_channel_map[channel];
session.each_link(action, filter);
}
};
Connection.prototype.on_open = function (frame) {
if (this.state.remote_opened()) {
this.remote.open = frame.performative;
this.open();
this.dispatch('connection_open', this._context());
} else {
throw new errors.ProtocolError('Open already received');
}
};
Connection.prototype.on_close = function (frame) {
if (this.state.remote_closed()) {
this.remote.close = frame.performative;
if (this.remote.close.error) {
this._handle_error();
} else {
this.dispatch('connection_close', this._context());
}
if (this.heartbeat_out) clearTimeout(this.heartbeat_out);
var self = this;
process.nextTick(function () {
self.close();
});
} else {
throw new errors.ProtocolError('Close already received');
}
};
Connection.prototype._register = function () {
if (!this.registered) {
this.registered = true;
process.nextTick(this._process.bind(this));
}
};
Connection.prototype._process = function () {
this.registered = false;
do {
if (this.state.need_open()) {
this._write_open();
}
var localChannelMap = this.local_channel_map;
for (var k in localChannelMap) {
localChannelMap[k]._process();
}
if (this.state.need_close()) {
this._write_close();
}
} while (!this.state.has_settled());
};
Connection.prototype._write_frame = function (channel, frame, payload) {
this.amqp_transport.encode(frames.amqp_frame(channel, frame, payload));
this.output();
};
Connection.prototype._write_open = function () {
this._write_frame(0, this.local.open);
};
Connection.prototype._write_close = function () {
this._write_frame(0, this.local.close);
};
Connection.prototype.on_begin = function (frame) {
var session;
if (frame.performative.remote_channel === null || frame.performative.remote_channel === undefined) {
//peer initiated
session = this.create_session();
session.local.begin.remote_channel = frame.channel;
} else {
session = this.local_channel_map[frame.performative.remote_channel];
if (!session) throw new errors.ProtocolError('Invalid value for remote channel ' + frame.performative.remote_channel);
}
session.on_begin(frame);
this.remote_channel_map[frame.channel] = session;
};
Connection.prototype.get_peer_certificate = function() {
if (this.socket && this.socket.getPeerCertificate) {
return this.socket.getPeerCertificate();
} else {
return undefined;
}
};
Connection.prototype.get_tls_socket = function() {
if (this.socket && (this.options.transport === 'tls' || this.options.transport === 'ssl')) {
return this.socket;
} else {
return undefined;
}
};
Connection.prototype._context = function (c) {
var context = c ? c : {};
context.connection = this;
if (this.container) context.container = this.container;
return context;
};
Connection.prototype.remove_session = function (session) {
if (this.remote_channel_map[session.remote.channel] === session) {
delete this.remote_channel_map[session.remote.channel];
}
if (this.local_channel_map[session.local.channel] === session) {
delete this.local_channel_map[session.local.channel];
}
};
Connection.prototype.remove_all_sessions = function () {
clearObject(this.remote_channel_map);
clearObject(this.local_channel_map);
};
function clearObject(obj) {
for (var k in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, k)) {
continue;
}
delete obj[k];
}
}
function delegate_to_session(name) {
Connection.prototype['on_' + name] = function (frame) {
var session = this.remote_channel_map[frame.channel];
if (!session) {
throw new errors.ProtocolError(name + ' received on invalid channel ' + frame.channel);
}
session['on_' + name](frame);
};
}
delegate_to_session('end');
delegate_to_session('attach');
delegate_to_session('detach');
delegate_to_session('transfer');
delegate_to_session('disposition');
delegate_to_session('flow');
module.exports = Connection;
}).call(this)}).call(this,require('_process'),require("buffer").Buffer)
},{"./endpoint.js":2,"./errors.js":3,"./frames.js":6,"./log.js":8,"./sasl.js":10,"./session.js":11,"./transport.js":13,"./util.js":15,"_process":43,"buffer":21,"events":27,"fs":20,"net":20,"os":41,"path":42,"tls":20}],2:[function(require,module,exports){
/*
* Copyright 2015 Red Hat Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var EndpointState = function () {
this.init();
};
EndpointState.prototype.init = function () {
this.local_open = false;
this.remote_open = false;
this.open_requests = 0;
this.close_requests = 0;
this.initialised = false;
this.marker = undefined;
};
EndpointState.prototype.mark = function (o) {
this.marker = o || Date.now();
return this.marker;
};
EndpointState.prototype.open = function () {
this.marker = undefined;
this.initialised = true;
if (!this.local_open) {
this.local_open = true;
this.open_requests++;
return true;
} else {
return false;
}
};
EndpointState.prototype.close = function () {
this.marker = undefined;
if (this.local_open) {
this.local_open = false;
this.close_requests++;
return true;
} else {
return false;
}
};
EndpointState.prototype.disconnected = function () {
var was_initialised = this.initialised;
this.was_open = this.local_open;
this.init();
this.initialised = was_initialised;
};
EndpointState.prototype.reconnect = function () {
if (this.was_open) {
this.open();
this.was_open = undefined;
}
};
EndpointState.prototype.remote_opened = function () {
if (!this.remote_open) {
this.remote_open = true;
return true;
} else {
return false;
}
};
EndpointState.prototype.remote_closed = function () {
if (this.remote_open) {
this.remote_open = false;
return true;
} else {
return false;
}
};
EndpointState.prototype.is_open = function () {
return this.local_open && this.remote_open;
};
EndpointState.prototype.is_closed = function () {
return this.initialised && !(this.local_open || this.was_open) && !this.remote_open;
};
EndpointState.prototype.has_settled = function () {
return this.open_requests === 0 && this.close_requests === 0;
};
EndpointState.prototype.need_open = function () {
if (this.open_requests > 0) {
this.open_requests--;
return true;
} else {
return false;
}
};
EndpointState.prototype.need_close = function () {
if (this.close_requests > 0) {
this.close_requests--;
return true;
} else {
return false;
}
};
module.exports = EndpointState;
},{}],3:[function(require,module,exports){
/*
* Copyright 2015 Red Hat Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var util = require('util');
function ProtocolError(message) {
Error.call(this);
this.message = message;
this.name = 'ProtocolError';
}
util.inherits(ProtocolError, Error);
function TypeError(message) {
ProtocolError.call(this, message);
this.message = message;
this.name = 'TypeError';
}
util.inherits(TypeError, ProtocolError);
function ConnectionError(message, condition, connection) {
Error.call(this, message);
this.message = message;
this.name = 'ConnectionError';
this.condition = condition;
this.description = message;
Object.defineProperty(this, 'connection', { value: connection });
}
util.inherits(ConnectionError, Error);
ConnectionError.prototype.toJSON = function () {
return {
type: this.name,
code: this.condition,
message: this.description
};
};
module.exports = {
ProtocolError: ProtocolError,
TypeError: TypeError,
ConnectionError: ConnectionError
};
},{"util":46}],4:[function(require,module,exports){
/*
* Copyright 2018 Red Hat Inc.
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var ReceiverEvents;
(function (ReceiverEvents) {
/**
* @property {string} message Raised when a message is received.
*/
ReceiverEvents['message'] = 'message';
/**
* @property {string} receiverOpen Raised when the remote peer indicates the link is
* open (i.e. attached in AMQP parlance).
*/
ReceiverEvents['receiverOpen'] = 'receiver_open';
/**
* @property {string} receiverDrained Raised when the remote peer
* indicates that it has drained all credit (and therefore there
* are no more messages at present that it can send).
*/
ReceiverEvents['receiverDrained'] = 'receiver_drained';
/**
* @property {string} receiverFlow Raised when a flow is received for receiver.
*/
ReceiverEvents['receiverFlow'] = 'receiver_flow';
/**
* @property {string} receiverError Raised when the remote peer
* closes the receiver with an error. The context may also have an
* error property giving some information about the reason for the
* error.
*/
ReceiverEvents['receiverError'] = 'receiver_error';
/**
* @property {string} receiverClose Raised when the remote peer indicates the link is closed.
*/
ReceiverEvents['receiverClose'] = 'receiver_close';
/**
* @property {string} settled Raised when the receiver link receives a disposition.
*/
ReceiverEvents['settled'] = 'settled';
})(ReceiverEvents || (ReceiverEvents = {}));
var SenderEvents;
(function (SenderEvents) {
/**
* @property {string} sendable Raised when the sender has sufficient credit to be able
* to transmit messages to its peer.
*/
SenderEvents['sendable'] = 'sendable';
/**
* @property {string} senderOpen Raised when the remote peer indicates the link is
* open (i.e. attached in AMQP parlance).
*/
SenderEvents['senderOpen'] = 'sender_open';
/**
* @property {string} senderDraining Raised when the remote peer
* requests that the sender drain its credit; sending all
* available messages within the credit limit and ensuring credit
* is used up..
*/
SenderEvents['senderDraining'] = 'sender_draining';
/**
* @property {string} senderFlow Raised when a flow is received for sender.
*/
SenderEvents['senderFlow'] = 'sender_flow';
/**
* @property {string} senderError Raised when the remote peer
* closes the sender with an error. The context may also have an
* error property giving some information about the reason for the
* error.
*/
SenderEvents['senderError'] = 'sender_error';
/**
* @property {string} senderClose Raised when the remote peer indicates the link is closed.
*/
SenderEvents['senderClose'] = 'sender_close';
/**
* @property {string} accepted Raised when a sent message is accepted by the peer.
*/
SenderEvents['accepted'] = 'accepted';
/**
* @property {string} released Raised when a sent message is released by the peer.
*/
SenderEvents['released'] = 'released';
/**
* @property {string} rejected Raised when a sent message is rejected by the peer.
*/
SenderEvents['rejected'] = 'rejected';
/**
* @property {string} modified Raised when a sent message is modified by the peer.
*/
SenderEvents['modified'] = 'modified';
/**
* @property {string} settled Raised when the sender link receives a disposition.
*/
SenderEvents['settled'] = 'settled';
})(SenderEvents || (SenderEvents = {}));
var SessionEvents;
(function (SessionEvents) {
/**
* @property {string} sessionOpen Raised when the remote peer indicates the session is
* open (i.e. attached in AMQP parlance).
*/
SessionEvents['sessionOpen'] = 'session_open';
/**
* @property {string} sessionError Raised when the remote peer receives an error. The context
* may also have an error property giving some information about the reason for the error.
*/
SessionEvents['sessionError'] = 'session_error';
/**
* @property {string} sessionClose Raised when the remote peer indicates the session is closed.
*/
SessionEvents['sessionClose'] = 'session_close';
/**
* @property {string} settled Raised when the session receives a disposition.
*/
SessionEvents['settled'] = 'settled';
})(SessionEvents || (SessionEvents = {}));
var ConnectionEvents;
(function (ConnectionEvents) {
/**
* @property {string} connectionOpen Raised when the remote peer indicates the connection is open.
*/
ConnectionEvents['connectionOpen'] = 'connection_open';
/**
* @property {string} connectionClose Raised when the remote peer indicates the connection is closed.
*/
ConnectionEvents['connectionClose'] = 'connection_close';
/**
* @property {string} connectionError Raised when the remote peer indicates an error occurred on
* the connection.
*/
ConnectionEvents['connectionError'] = 'connection_error';
/**
* @property {string} protocolError Raised when a protocol error is received on the underlying socket.
*/
ConnectionEvents['protocolError'] = 'protocol_error',
/**
* @property {string} error Raised when an error is received on the underlying socket.
*/
ConnectionEvents['error'] = 'error',
/**
* @property {string} disconnected Raised when the underlying tcp connection is lost. The context
* has a reconnecting property which is true if the library is attempting to automatically reconnect
* and false if it has reached the reconnect limit. If reconnect has not been enabled or if the connection
* is a tcp server, then the reconnecting property is undefined. The context may also have an error
* property giving some information about the reason for the disconnect.
*/
ConnectionEvents['disconnected'] = 'disconnected';
/**
* @property {string} settled Raised when the connection receives a disposition.
*/
ConnectionEvents['settled'] = 'settled';
})(ConnectionEvents || (ConnectionEvents = {}));
module.exports = {
ReceiverEvents: ReceiverEvents,
SenderEvents: SenderEvents,
SessionEvents: SessionEvents,
ConnectionEvents: ConnectionEvents
};
},{}],5:[function(require,module,exports){
/*
* Copyright 2015 Red Hat Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var amqp_types = require('./types.js');
module.exports = {
selector : function (s) {
return {'jms-selector':amqp_types.wrap_described(s, 0x468C00000004)};
}
};
},{"./types.js":14}],6:[function(require,module,exports){
/*
* Copyright 2015 Red Hat Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var types = require('./types.js');
var errors = require('./errors.js');
var frames = {};
var by_descriptor = {};
frames.read_header = function(buffer) {
var offset = 4;
var header = {};
var name = buffer.toString('ascii', 0, offset);
if (name !== 'AMQP') {
// output name in hex (null-bytes can be tough to deal with in ascii)
throw new errors.ProtocolError('Invalid protocol header for AMQP: ' + buffer.toString('hex', 0, offset));
}
header.protocol_id = buffer.readUInt8(offset++);
header.major = buffer.readUInt8(offset++);
header.minor = buffer.readUInt8(offset++);
header.revision = buffer.readUInt8(offset++);
//the protocol header is interpreted in different ways for
//different versions(!); check some special cases to give clearer
//error messages:
if (header.protocol_id === 0 && header.major === 0 && header.minor === 9 && header.revision === 1) {
throw new errors.ProtocolError('Unsupported AMQP version: 0-9-1');
}
if (header.protocol_id === 1 && header.major === 1 && header.minor === 0 && header.revision === 10) {
throw new errors.ProtocolError('Unsupported AMQP version: 0-10');
}
if (header.major !== 1 || header.minor !== 0) {
throw new errors.ProtocolError('Unsupported AMQP version: ' + JSON.stringify(header));
}
return header;
};
frames.write_header = function(buffer, header) {
var offset = 4;
buffer.write('AMQP', 0, offset, 'ascii');
buffer.writeUInt8(header.protocol_id, offset++);
buffer.writeUInt8(header.major, offset++);
buffer.writeUInt8(header.minor, offset++);
buffer.writeUInt8(header.revision, offset++);
return 8;
};
//todo: define enumeration for frame types
frames.TYPE_AMQP = 0x00;
frames.TYPE_SASL = 0x01;
frames.read_frame = function(buffer) {
var reader = new types.Reader(buffer);
var frame = {};
frame.size = reader.read_uint(4);
if (reader.remaining() < (frame.size-4)) {
return null;
}
var doff = reader.read_uint(1);
if (doff < 2) {
throw new errors.ProtocolError('Invalid data offset, must be at least 2 was ' + doff);
}
frame.type = reader.read_uint(1);
if (frame.type === frames.TYPE_AMQP) {
frame.channel = reader.read_uint(2);
} else if (frame.type === frames.TYPE_SASL) {
reader.skip(2);
frame.channel = 0;
} else {
throw new errors.ProtocolError('Unknown frame type ' + frame.type);
}
if (doff > 1) {
//ignore any extended header
reader.skip(doff * 4 - 8);
}
if (reader.remaining()) {
frame.performative = reader.read();
var c = by_descriptor[frame.performative.descriptor.value];
if (c) {
frame.performative = new c(frame.performative.value);
}
if (reader.remaining()) {
frame.payload = reader.read_bytes(reader.remaining());
}
}
return frame;
};
frames.write_frame = function(frame) {
var writer = new types.Writer();
writer.skip(4);//skip size until we know how much we have written
writer.write_uint(2, 1);//doff
writer.write_uint(frame.type, 1);
if (frame.type === frames.TYPE_AMQP) {
writer.write_uint(frame.channel, 2);
} else if (frame.type === frames.TYPE_SASL) {
writer.write_uint(0, 2);
} else {
throw new errors.ProtocolError('Unknown frame type ' + frame.type);
}
if (frame.performative) {
writer.write(frame.performative);
if (frame.payload) {
writer.write_bytes(frame.payload);
}
}
var buffer = writer.toBuffer();
buffer.writeUInt32BE(buffer.length, 0);//fill in the size
return buffer;
};
frames.amqp_frame = function(channel, performative, payload) {
return {'channel': channel || 0, 'type': frames.TYPE_AMQP, 'performative': performative, 'payload': payload};
};
frames.sasl_frame = function(performative) {
return {'channel': 0, 'type': frames.TYPE_SASL, 'performative': performative};
};
function define_frame(type, def) {
var c = types.define_composite(def);
frames[def.name] = c.create;
by_descriptor[Number(c.descriptor.numeric).toString(10)] = c;
by_descriptor[c.descriptor.symbolic] = c;
}
var open = {
name: 'open',
code: 0x10,
fields: [
{name: 'container_id', type: 'string', mandatory: true},
{name: 'hostname', type: 'string'},
{name: 'max_frame_size', type: 'uint', default_value: 4294967295},
{name: 'channel_max', type: 'ushort', default_value: 65535},
{name: 'idle_time_out', type: 'uint'},
{name: 'outgoing_locales', type: 'symbol', multiple: true},
{name: 'incoming_locales', type: 'symbol', multiple: true},
{name: 'offered_capabilities', type: 'symbol', multiple: true},
{name: 'desired_capabilities', type: 'symbol', multiple: true},
{name: 'properties', type: 'symbolic_map'}
]
};
var begin = {
name: 'begin',
code: 0x11,
fields:[
{name: 'remote_channel', type: 'ushort'},
{name: 'next_outgoing_id', type: 'uint', mandatory: true},
{name: 'incoming_window', type: 'uint', mandatory: true},
{name: 'outgoing_window', type: 'uint', mandatory: true},
{name: 'handle_max', type: 'uint', default_value: '4294967295'},
{name: 'offered_capabilities', type: 'symbol', multiple: true},
{name: 'desired_capabilities', type: 'symbol', multiple: true},
{name: 'properties', type: 'symbolic_map'}
]
};
var attach = {
name: 'attach',
code: 0x12,
fields:[
{name: 'name', type: 'string', mandatory: true},
{name: 'handle', type: 'uint', mandatory: true},
{name: 'role', type: 'boolean', mandatory: true},
{name: 'snd_settle_mode', type: 'ubyte', default_value: 2},
{name: 'rcv_settle_mode', type: 'ubyte', default_value: 0},
{name: 'source', type: '*'},
{name: 'target', type: '*'},
{name: 'unsettled', type: 'map'},
{name: 'incomplete_unsettled', type: 'boolean', default_value: false},
{name: 'initial_delivery_count', type: 'uint'},
{name: 'max_message_size', type: 'ulong'},
{name: 'offered_capabilities', type: 'symbol', multiple: true},
{name: 'desired_capabilities', type: 'symbol', multiple: true},
{name: 'properties', type: 'symbolic_map'}
]
};
var flow = {
name: 'flow',
code: 0x13,
fields:[
{name: 'next_incoming_id', type: 'uint'},
{name: 'incoming_window', type: 'uint', mandatory: true},
{name: 'next_outgoing_id', type: 'uint', mandatory: true},
{name: 'outgoing_window', type: 'uint', mandatory: true},
{name: 'handle', type: 'uint'},
{name: 'delivery_count', type: 'uint'},
{name: 'link_credit', type: 'uint'},
{name: 'available', type: 'uint'},
{name: 'drain', type: 'boolean', default_value: false},
{name: 'echo', type: 'boolean', default_value: false},
{name: 'properties', type: 'symbolic_map'}
]
};
var transfer = {
name: 'transfer',
code: 0x14,
fields:[
{name: 'handle', type: 'uint', mandatory: true},
{name: 'delivery_id', type: 'uint'},
{name: 'delivery_tag', type: 'binary'},
{name: 'message_format', type: 'uint'},
{name: 'settled', type: 'boolean'},
{name: 'more', type: 'boolean', default_value: false},
{name: 'rcv_settle_mode', type: 'ubyte'},
{name: 'state', type: 'delivery_state'},
{name: 'resume', type: 'boolean', default_value: false},
{name: 'aborted', type: 'boolean', defaul