mqlight-dev
Advanced tools
Comparing version 0.1.2014060800 to 0.1.2014062300
@@ -96,3 +96,3 @@ #!/usr/bin/env node | ||
} else if (parsed.ffdc) { | ||
command = 'log.debug()'; | ||
command = 'log.ffdc()'; | ||
} else if (parsed.log) { | ||
@@ -99,0 +99,0 @@ command = 'log.setLevel(\'' + parsed.log + '\')'; |
@@ -25,63 +25,62 @@ /* %Z% %W% %I% %E% %U% */ | ||
// on Linux x86_64 we need to do some pre-req checking for openssl libraries | ||
if (os.platform() === 'linux' && process.arch === 'x64') { | ||
fs.exists('/etc/redhat-release', function(redhat) { | ||
if (redhat) { | ||
// on Red Hat Linux we need to check openssl 0.9.8 is installed and also | ||
// symlink it to match the official openssl naming conventions. | ||
fs.exists('/usr/lib64/libssl.so.6', function(exists) { | ||
if (!exists) { | ||
console.error('Before using MQ Light on Linux, you will also need ' + | ||
'the 0.9.8 version of an OpenSSL package. This version of the ' + | ||
'package is not installed by default, so to use the module ' + | ||
'you will need to install it.'); | ||
console.error(); | ||
console.error('* To install the package on RedHat, run: sudo yum ' + | ||
'install openssl098e'); | ||
process.exit(1); | ||
} | ||
// on Red Hat Linux we need to check openssl 0.9.8 is installed and also add | ||
// a correctly named symlink within our module's installation directory to | ||
// workaround a mismatch between the official openssl naming conventions and | ||
// what is deployed on Redhat | ||
var redhat = fs.existsSync('/etc/redhat-release'); | ||
if (redhat) { | ||
var hasSSL = fs.existsSync('/usr/lib64/libssl.so.6'); | ||
if (!hasSSL) { | ||
console.error('Before using MQ Light on Linux, you will also need ' + | ||
'the 0.9.8 version of an OpenSSL package. This version of the ' + | ||
'package is not installed by default, so to use the module ' + | ||
'you will need to install it.'); | ||
console.error(); | ||
console.error('* To install the package on RedHat, run: sudo yum ' + | ||
'install openssl098e'); | ||
process.exit(1); | ||
} | ||
var child = childProcess.spawn('ln', [ | ||
'-s', | ||
'/usr/lib64/libssl.so.6', | ||
'./lib/linux-x64/libssl.so.0.9.8' | ||
], { stdio: 'inherit' }); | ||
child.on('exit', function(code, signal) { | ||
if (signal) { | ||
console.error('ln killed by signal: ' + signal); | ||
process.exit(1); | ||
} else { | ||
if (code > 0) console.error('ln failed with return code: ' + code); | ||
process.exit(code); | ||
} | ||
}).on('error', function(err) { | ||
console.error('Unable to run ln for reason: %s', err); | ||
process.exit(1); | ||
}); | ||
}); | ||
} else { | ||
// else we assume we are running on Ubuntu or generic Linux and just | ||
// report if the library is missing from the install. | ||
fs.exists('/usr/lib64/libssl.so.0.9.8', function(exists) { | ||
if (!exists) { | ||
fs.exists('/usr/lib/x86_64-linux-gnu/libssl.so.0.9.8', | ||
function(exists) { | ||
if (!exists) { | ||
console.error('Before using MQ Light on Linux, you will ' + | ||
'also need the 0.9.8 version of an OpenSSL ' + | ||
'package. This version of the package is not ' + | ||
'installed by default, so to use the module you ' + | ||
'will need to install it.'); | ||
console.error(); | ||
console.error('* To install the package on Ubuntu, run: ' + | ||
'sudo apt-get install libssl0.9.8'); | ||
console.error('* To install the package on other distros ' + | ||
'refer to your package manager documentation'); | ||
process.exit(1); | ||
} | ||
}); | ||
} | ||
}); | ||
// if we did find libssl on redhat, we still need to add a symlink | ||
// within our module's lib folder (node_modules/mqlight/lib/linux-x64) | ||
var child = childProcess.spawn('ln', [ | ||
'-s', | ||
'/usr/lib64/libssl.so.6', | ||
'./lib/linux-x64/libssl.so.0.9.8' | ||
], { stdio: 'inherit' }); | ||
child.on('exit', function(code, signal) { | ||
if (signal) { | ||
console.error('ln killed by signal: ' + signal); | ||
process.exit(1); | ||
} else { | ||
if (code > 0) console.error('ln failed with return code: ' + code); | ||
process.exit(code); | ||
} | ||
}).on('error', function(err) { | ||
console.error('Unable to run ln for reason: %s', err); | ||
process.exit(1); | ||
}); | ||
} else { | ||
// else we assume we are running on Ubuntu or a generic Linux distro | ||
// so we will simply check and report to the user if the prereq openssl | ||
// library version is missing from their operating system install. | ||
var hasSSL = fs.existsSync('/usr/lib64/libssl.so.0.9.8') || | ||
fs.existsSync('/usr/lib/x86_64-linux-gnu/libssl.so.0.9.8'); | ||
if (!hasSSL) { | ||
console.error('Before using MQ Light on Linux, you will ' + | ||
'also need the 0.9.8 version of an OpenSSL ' + | ||
'package. This version of the package is not ' + | ||
'installed by default, so to use the module you ' + | ||
'will need to install it.'); | ||
console.error(); | ||
console.error('* To install the package on Ubuntu, run: ' + | ||
'sudo apt-get install libssl0.9.8'); | ||
console.error('* To install the package on other distros ' + | ||
'refer to your package manager documentation'); | ||
process.exit(1); | ||
} | ||
}); | ||
} | ||
} | ||
@@ -19,2 +19,5 @@ /* %Z% %W% %I% %E% %U% */ | ||
*/ | ||
/* jslint node: true */ | ||
/* jshint -W083,-W097 */ | ||
'use strict'; | ||
var log = exports; | ||
@@ -35,2 +38,5 @@ | ||
var fd = 0; | ||
var dataSize; | ||
var exceptionThrown = null; | ||
var processedExceptions = 0; | ||
@@ -90,2 +96,3 @@ var ENTRY_IND = '>-----------------------------------------------------------'; | ||
write(lvl, clientId, '| Log Level :-', logger.level); | ||
write(lvl, clientId, '| Data Size :-', dataSize); | ||
if ('fnc' in options) { | ||
@@ -100,2 +107,3 @@ write(lvl, clientId, '| Function :-', options.fnc); | ||
} | ||
write(lvl, clientId, '| Exceptions :-', processedExceptions); | ||
write(lvl, clientId, HEADER_BANNER); | ||
@@ -121,20 +129,20 @@ write(lvl, clientId, ''); | ||
log.log('debug', log.NO_CLIENT_ID, 'Setting PN_TRACE_FRM'); | ||
process.env['PN_TRACE_FRM'] = '1'; | ||
process.env.PN_TRACE_FRM = '1'; | ||
if (logger.levels[logger.level] <= logger.levels.raw) { | ||
// Set PN_TRACE_RAW if raw level logging is enabled. | ||
log.log('debug', log.NO_CLIENT_ID, 'Setting PN_TRACE_RAW'); | ||
process.env['PN_TRACE_RAW'] = '1'; | ||
process.env.PN_TRACE_RAW = '1'; | ||
} else { | ||
log.log('debug', log.NO_CLIENT_ID, 'Unsetting PN_TRACE_RAW'); | ||
delete process.env['PN_TRACE_RAW']; | ||
delete process.env.PN_TRACE_RAW; | ||
} | ||
} | ||
else { | ||
if (process.env['PN_TRACE_RAW']) { | ||
if (process.env.PN_TRACE_RAW) { | ||
log.log('debug', log.NO_CLIENT_ID, 'Unsetting PN_TRACE_RAW'); | ||
delete process.env['PN_TRACE_RAW']; | ||
delete process.env.PN_TRACE_RAW; | ||
} | ||
if (process.env['PN_TRACE_FRM']) { | ||
if (process.env.PN_TRACE_FRM) { | ||
log.log('debug', log.NO_CLIENT_ID, 'Unsetting PN_TRACE_FRM'); | ||
delete process.env['PN_TRACE_FRM']; | ||
delete process.env.PN_TRACE_FRM; | ||
} | ||
@@ -193,3 +201,3 @@ } | ||
// Open the specified file. | ||
fd = fs.openSync(stream, 'a', 0644); | ||
fd = fs.openSync(stream, 'a', '0644'); | ||
@@ -213,2 +221,34 @@ // Set up a listener for log events. | ||
/** | ||
* Set the amount of message data that will get logged. | ||
* | ||
* @param {Number} size amount of message data that will get logged. | ||
*/ | ||
log.setDataSize = function(size) { | ||
log.entry('log.setDataSize', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'size:', size); | ||
if (typeof size === 'string') { | ||
dataSize = parseInt(size); | ||
if (isNaN(dataSize)) { | ||
throw new TypeError('MQLIGHT_NODE_MESSAGE_DATA_SIZE is not a number'); | ||
} | ||
} else { | ||
dataSize = size; | ||
} | ||
log.exit('log.setDataSize', log.NO_CLIENT_ID); | ||
}; | ||
/** | ||
* Get the amount of message data that will get logged. | ||
* | ||
* @return {Number} The data size. | ||
*/ | ||
log.getDataSize = function() { | ||
return dataSize; | ||
}; | ||
/** | ||
* Log entry into a function, specifying the logging level to | ||
@@ -223,2 +263,10 @@ * write at. | ||
log.entryLevel = function(lvl, name, id) { | ||
if (exceptionThrown) { | ||
log.log('error', id, '* Uncaught exception'); | ||
processedExceptions++; | ||
exceptionThrown = null; | ||
while(stack.length > 1) { | ||
stack.pop(); | ||
} | ||
} | ||
write(lvl, id, ENTRY_IND.substring(0, stack.length), name); | ||
@@ -252,11 +300,14 @@ stack.push(name); | ||
log.exitLevel = function(lvl, name, id, rc) { | ||
write(lvl, id, EXIT_IND.substring(0, stack.length - 1), | ||
write(lvl, id, EXIT_IND.substring(0, Math.max(1, stack.length - 1)), | ||
name, rc ? rc : ''); | ||
var last; | ||
do | ||
{ | ||
if (stack.length == 1) { | ||
log.ffdc('log.exitLevel', 10, null, name); | ||
if (processedExceptions == 0) { | ||
log.ffdc('log.exitLevel', 10, null, name); | ||
} | ||
break; | ||
} | ||
var last = stack.pop(); | ||
last = stack.pop(); | ||
} while (last != name); | ||
@@ -275,3 +326,3 @@ }; | ||
log.exit = function(name, id, rc) { | ||
log.exitLevel('exit', name, id); | ||
log.exitLevel('exit', name, id, rc); | ||
}; | ||
@@ -296,31 +347,142 @@ | ||
/** | ||
* Log message body. | ||
* | ||
* @this {log} | ||
* @param {String} id The id of the client logging the data. | ||
* @param {Object} data The message body to be logged subject to | ||
* specified data size. Must be either a string or a | ||
* Buffer object. | ||
*/ | ||
log.body = function(id, data) { | ||
if (logger.levels[logger.level] <= logger.levels.data) { | ||
write('data', id, '! length:', data.length); | ||
if (typeof data === 'string') { | ||
if ((dataSize >= data.length) || (dataSize < 0)) { | ||
write('data', id, '! string:', data); | ||
} else { | ||
write('data', id, '! string:', data.substring(0, dataSize), '...'); | ||
} | ||
} else { | ||
if ((dataSize >= data.length) || (dataSize < 0)) { | ||
write('data', id, '! buffer:', | ||
data.toString('hex')); | ||
} else { | ||
write('data', id, '! buffer:', | ||
data.toString('hex', 0, dataSize), '...'); | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* Log an exception being thrown, specifying the logging level to | ||
* write at. | ||
* | ||
* @this {log} | ||
* @param {String} lvl The logging level to write at. | ||
* @param {String} name The name of the function throwing the | ||
* exception. | ||
* @param {String} id The id of the client logging the | ||
* exception. | ||
* @param {Object} err The exception being thrown. | ||
*/ | ||
log.throwLevel = function(lvl, name, id, err) { | ||
log.log('error', id, '* Thrown exception:', err); | ||
exceptionThrown = err; | ||
log.exitLevel(lvl, name, id, 'Exception thrown'); | ||
}; | ||
/** | ||
* Log an exception being thrown. | ||
* | ||
* @this {log} | ||
* @param {String} name The name of the function throwing the | ||
* exception. | ||
* @param {String} id The id of the client logging the | ||
* exception. | ||
* @param {Error} err The exception being thrown. | ||
*/ | ||
log.throw = function(name, id, err) { | ||
log.throwLevel('exit', name, id, err); | ||
}; | ||
/** | ||
* Log an exception being caught, specifying the logging level to | ||
* write at. | ||
* | ||
* @this {log} | ||
* @param {String} lvl The logging level to write at. | ||
* @param {String} name The name of the function catching the | ||
* exception. | ||
* @param {String} id The id of the client logging the data. | ||
* @param {Error} err The exception being caught. | ||
*/ | ||
log.caughtLevel = function(lvl, name, id, err) { | ||
log.log('error', id, '* Caught exception:', err); | ||
if (exceptionThrown) { | ||
processedExceptions++; | ||
exceptionThrown = null; | ||
while(stack.length > 1) { | ||
if (stack[stack.length - 1] === name) { | ||
break; | ||
} | ||
stack.pop(); | ||
} | ||
if (stack.length == 1) { | ||
log.entryLevel(lvl, name, id); | ||
} | ||
} | ||
}; | ||
/** | ||
* Log an exception being caught. | ||
* | ||
* @this {log} | ||
* @param {String} name The name of the function catching the | ||
* exception. | ||
* @param {String} id The id of the client logging the data. | ||
* @param {Error} err The exception being caught. | ||
*/ | ||
log.caught = function(name, id, err) { | ||
log.caughtLevel('entry', name, id, err); | ||
}; | ||
/** | ||
* Dump First Failure Data Capture information in the event of | ||
* failure to aid in diagnosis of an error. | ||
* | ||
* @param {String} fnc The name of the calling function. | ||
* @param {Number} probeId An identifier for the error location. | ||
* @param {Client} client The client having a problem. | ||
* @param {Object} data Extra data to aid in problem diagnosis. | ||
* @param {String=} opt_fnc The name of the calling function. | ||
* @param {Number=} opt_probeId An identifier for the error | ||
* location. | ||
* @param {Client=} opt_client The client having a problem. | ||
* @param {Object=} opt_data Extra data to aid in problem | ||
* diagnosis. | ||
*/ | ||
log.ffdc = function(fnc, probeId, client, data) { | ||
var clientId = client ? client.Id : log.NO_CLIENT_ID; | ||
log.ffdc = function(opt_fnc, opt_probeId, opt_client, opt_data) { | ||
var opts = { | ||
title: 'First Failure Data Capture', | ||
fnc: opt_fnc || 'User-requested FFDC by function', | ||
probeId: opt_probeId || 255, | ||
ffdcSequence: ffdcSequence++, | ||
clientId: opt_client ? opt_client.id : log.NO_CLIENT_ID | ||
}; | ||
log.entry('log.ffdc', clientId); | ||
log.log('parms', clientId, 'fnc:', fnc); | ||
log.log('parms', clientId, 'probeId:', probeId); | ||
log.log('parms', clientId, 'data:', data); | ||
log.entry('log.ffdc', opts.clientId); | ||
log.log('parms', opts.clientId, 'fnc:', opt_fnc); | ||
log.log('parms', opts.clientId, 'probeId:', opt_probeId); | ||
log.log('parms', opts.clientId, 'data:', opt_data); | ||
if (logger.levels[logger.level] <= logger.levels.ffdc) { | ||
header('ffdc', clientId, { | ||
title: 'First Failure Data Capture', | ||
fnc: fnc, | ||
probeId: probeId, | ||
ffdcSequence: ffdcSequence++ | ||
}); | ||
write('ffdc', clientId, new Error().stack); | ||
write('ffdc', clientId, ''); | ||
write('ffdc', clientId, 'Function Stack'); | ||
write('ffdc', clientId, stack.slice(1)); | ||
write('ffdc', clientId, ''); | ||
write('ffdc', clientId, 'Function History'); | ||
header('ffdc', opts.clientId, opts); | ||
write('ffdc', opts.clientId, new Error().stack); | ||
write('ffdc', opts.clientId, ''); | ||
write('ffdc', opts.clientId, 'Function Stack'); | ||
write('ffdc', opts.clientId, stack.slice(1)); | ||
write('ffdc', opts.clientId, ''); | ||
write('ffdc', opts.clientId, 'Function History'); | ||
for (var idx = 0; idx < logger.record.length; idx++) { | ||
@@ -330,28 +492,28 @@ var rec = logger.record[idx]; | ||
(logger.levels[rec.level] >= logger.levels[historyLevel])) { | ||
write('ffdc', clientId, '%d %s %s %s', | ||
write('ffdc', opts.clientId, '%d %s %s %s', | ||
rec.id, logger.disp[rec.level], rec.prefix, rec.message); | ||
} | ||
} | ||
if (client) { | ||
write('ffdc', clientId, ''); | ||
write('ffdc', clientId, 'Client'); | ||
write('ffdc', clientId, client); | ||
if (opt_client) { | ||
write('ffdc', opts.clientId, ''); | ||
write('ffdc', opts.clientId, 'Client'); | ||
write('ffdc', opts.clientId, opt_client); | ||
} | ||
if (data) { | ||
write('ffdc', clientId, ''); | ||
write('ffdc', clientId, 'Data'); | ||
write('ffdc', clientId, data); | ||
if (opt_data) { | ||
write('ffdc', opts.clientId, ''); | ||
write('ffdc', opts.clientId, 'Data'); | ||
write('ffdc', opts.clientId, opt_data); | ||
} | ||
write('ffdc', clientId, ''); | ||
write('ffdc', clientId, 'Memory Usage'); | ||
write('ffdc', clientId, process.memoryUsage()); | ||
if ((ffdcSequence === 1) || (probeId === 255)) { | ||
write('ffdc', clientId, ''); | ||
write('ffdc', clientId, 'Environment Variables'); | ||
write('ffdc', clientId, process.env); | ||
write('ffdc', opts.clientId, ''); | ||
write('ffdc', opts.clientId, 'Memory Usage'); | ||
write('ffdc', opts.clientId, process.memoryUsage()); | ||
if ((ffdcSequence === 1) || (opts.probeId === 255)) { | ||
write('ffdc', opts.clientId, ''); | ||
write('ffdc', opts.clientId, 'Environment Variables'); | ||
write('ffdc', opts.clientId, process.env); | ||
} | ||
write('ffdc', clientId, ''); | ||
write('ffdc', opts.clientId, ''); | ||
} | ||
log.exit('log.ffdc', clientId, null); | ||
log.exit('log.ffdc', opts.clientId, null); | ||
}; | ||
@@ -361,10 +523,2 @@ | ||
/** | ||
* Easily dump an FFDC when running under the node debugger. | ||
*/ | ||
log.debug = function() { | ||
log.ffdc('log.debug', 255, null, 'User-requested FFDC by function'); | ||
}; | ||
/** | ||
* The identifier used when a log entry is not associated with a | ||
@@ -404,2 +558,11 @@ * particular client. | ||
/** | ||
* Set the amount of message data that will get logged. The | ||
* default is 100 bytes, but this can be altered by setting the | ||
* environment variable MQLIGHT_NODE_MESSAGE_DATA_SIZE to a | ||
* different number. | ||
*/ | ||
log.setDataSize(process.env.MQLIGHT_NODE_MESSAGE_DATA_SIZE || 100); | ||
/** | ||
* Set the level of logging. By default only 'ffdc' entries will | ||
@@ -406,0 +569,0 @@ * be logged, but this can be altered by setting the environment |
439
mqlight.js
@@ -19,2 +19,5 @@ /* %Z% %W% %I% %E% %U% */ | ||
*/ | ||
/* jslint node: true */ | ||
/* jshint -W083,-W097 */ | ||
'use strict'; | ||
@@ -27,3 +30,3 @@ | ||
*/ | ||
log = require('./mqlight-log'); | ||
GLOBAL.log = require('./mqlight-log'); | ||
@@ -35,5 +38,6 @@ | ||
* An ffdc can be generated programmatically by calling | ||
* log.debug() | ||
* log.ffdc() | ||
*/ | ||
exports.log = log; | ||
exports.log = GLOBAL.log; | ||
var log = GLOBAL.log; | ||
@@ -67,2 +71,3 @@ var os = require('os'); | ||
var url = require('url'); | ||
var fs = require('fs'); | ||
var http = require('http'); | ||
@@ -90,35 +95,35 @@ | ||
/** The status unknown. */ | ||
PN_STATUS_UNKNOWN = 0; | ||
var PN_STATUS_UNKNOWN = 0; | ||
/** The message is in flight. */ | ||
PN_STATUS_PENDING = 1; | ||
var PN_STATUS_PENDING = 1; | ||
/** The message was accepted. */ | ||
PN_STATUS_ACCEPTED = 2; | ||
var PN_STATUS_ACCEPTED = 2; | ||
/** The message was rejected. */ | ||
PN_STATUS_REJECTED = 3; | ||
var PN_STATUS_REJECTED = 3; | ||
/** The message was released. */ | ||
PN_STATUS_RELEASED = 4; | ||
var PN_STATUS_RELEASED = 4; | ||
/** The message was modified. */ | ||
PN_STATUS_MODIFIED = 5; | ||
var PN_STATUS_MODIFIED = 5; | ||
/** The message was aborted. */ | ||
PN_STATUS_ABORTED = 6; | ||
var PN_STATUS_ABORTED = 6; | ||
/** The remote party has settled the message. */ | ||
PN_STATUS_SETTLED = 7; | ||
var PN_STATUS_SETTLED = 7; | ||
/** The connection retry interval in milliseconds. */ | ||
CONNECT_RETRY_INTERVAL = 10000; | ||
var CONNECT_RETRY_INTERVAL = 10000; | ||
if (process.env.NODE_ENV === 'unittest') CONNECT_RETRY_INTERVAL = 0; | ||
@@ -151,3 +156,3 @@ | ||
* both try to connect then the first instance to establish its | ||
* connection is diconnected in favour of the second instance. If | ||
* connection is disconnected in favour of the second instance. If | ||
* this property is not specified then the client will generate a | ||
@@ -172,3 +177,7 @@ * probabalistically unique ID. | ||
if (!options) throw TypeError('options object missing'); | ||
if (!options) { | ||
var err = new TypeError('options object missing'); | ||
log.throw('createClient', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
var client = new Client(options.service, options.id, | ||
@@ -179,2 +188,4 @@ options.user, options.password); | ||
process.once('exit', function() { | ||
log.entry('createClient.on.exit', log.NO_CLIENT_ID); | ||
if (client && client.getState() == 'connected') { | ||
@@ -184,4 +195,8 @@ try { | ||
client.disconnect(); | ||
} catch (_) {} | ||
} catch (err) { | ||
log.caught('createClient.on.exit', client.id, err); | ||
} | ||
} | ||
log.exit('createClient.on.exit', log.NO_CLIENT_ID); | ||
}); | ||
@@ -212,5 +227,9 @@ | ||
var err; | ||
// Validate the parameter list length | ||
if (arguments.length > 1) { | ||
throw new Error('Too many arguments'); | ||
err = new Error('Too many arguments'); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -221,8 +240,14 @@ | ||
if (!service) { | ||
throw new Error('service is undefined'); | ||
err = new Error('service is undefined'); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} else if (service instanceof Function) { | ||
throw new TypeError('service cannot be a function'); | ||
err = new TypeError('service cannot be a function'); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} else if (service instanceof Array) { | ||
if (service.length === 0) { | ||
throw new Error('service array is empty'); | ||
err = new Error('service array is empty'); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -233,3 +258,5 @@ inputServiceList = service; | ||
} else { | ||
throw new TypeError('service must be a string or array type'); | ||
err = new TypeError('service must be a string or array type'); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -256,3 +283,5 @@ | ||
'be supplied as options for createClient'; | ||
throw new Error(msg); | ||
err = new Error(msg); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -263,4 +292,6 @@ // Check we are trying to use the amqp protocol | ||
"' specified for service. Only the amqp or amqps protocol are " + | ||
' supported.'; | ||
throw new Error(msg); | ||
'supported.'; | ||
err = new Error(msg); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -271,3 +302,5 @@ // Check we have a hostname | ||
'service. Must supply a hostname.'; | ||
throw new Error(msg); | ||
err = new Error(msg); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -282,3 +315,5 @@ // Set default port if not supplied | ||
" ) can't be part of a service URL."; | ||
throw new Error(msg); | ||
err = new Error(msg); | ||
log.throw('generateServiceList', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -294,2 +329,74 @@ serviceList[i] = protocol + '//' + host + ':' + port; | ||
/** | ||
* Function to take a single FILE URL and using the JSON retrieved from it to | ||
* return an array of service URLs. | ||
* | ||
* @param {String} | ||
* fileUrl - Required; a FILE address to retrieve service info | ||
* from (e.g., file:///tmp/config.json). | ||
* @return {function(callback)} a function which will call the given callback | ||
* with a list of AMQP service URLs retrieved from the FILE. | ||
* @throws TypeError | ||
* If fileUrl is not a string. | ||
* @throws Error | ||
* if an unsupported or invalid FILE address is specified. | ||
*/ | ||
var getFileServiceFunction = function(fileUrl) { | ||
log.entry('getFileServiceFunction', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'fileUrl:', fileUrl); | ||
if (typeof fileUrl !== 'string') { | ||
var err = new TypeError('fileUrl must be a string type'); | ||
log.throw('getFileServiceFunction', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
var fileServiceFunction = function(callback) { | ||
log.entry('fileServiceFunction', log.NO_CLIENT_ID); | ||
fs.readFile(fileUrl, { encoding: 'utf8' }, function(err, data) { | ||
log.entry('fileServiceFunction.readFile.callback', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'err:', err); | ||
log.log('parms', log.NO_CLIENT_ID, 'data:', data); | ||
if (err) { | ||
err.message = 'attempt to read ' + fileUrl + ' failed with the ' + | ||
'following error: ' + err.message; | ||
log.log('error', log.NO_CLIENT_ID, err); | ||
log.entry('fileServiceFunction.callback', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'err:', err); | ||
callback(err); | ||
log.exit('fileServiceFunction.callback', log.NO_CLIENT_ID, null); | ||
} else { | ||
var obj; | ||
try { | ||
obj = JSON.parse(data); | ||
} catch (err) { | ||
err.message = 'the content read from ' + fileUrl + ' contained ' + | ||
'unparseable JSON: ' + err.message; | ||
log.caught('fileServiceFunction.readFile.callback', | ||
log.NO_CLIENT_ID, err); | ||
log.entry('fileServiceFunction.callback', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'err:', err); | ||
callback(err); | ||
log.exit('fileServiceFunction.callback', log.NO_CLIENT_ID, null); | ||
} | ||
if (obj) { | ||
log.entry('fileServiceFunction.callback', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'service:', obj.service); | ||
callback(undefined, obj.service); | ||
log.exit('fileServiceFunction.callback', log.NO_CLIENT_ID, null); | ||
} | ||
} | ||
log.exit('fileServiceFunction.readFile.callback', log.NO_CLIENT_ID, null); | ||
}); | ||
log.exit('fileServiceFunction', log.NO_CLIENT_ID, null); | ||
}; | ||
log.exit('getFileServiceFunction', log.NO_CLIENT_ID, fileServiceFunction); | ||
return fileServiceFunction; | ||
}; | ||
/** | ||
* Function to take a single HTTP URL and using the JSON retrieved from it to | ||
@@ -301,3 +408,4 @@ * return an array of service URLs. | ||
* from. | ||
* @return {Array} a list of AMQP service URLs retrieved from the URL. | ||
* @return {function(callback)} a function which will call the given callback | ||
* with a list of AMQP service URLs retrieved from the URL. | ||
* @throws TypeError | ||
@@ -313,3 +421,5 @@ * If serviceUrl is not a string. | ||
if (typeof serviceUrl !== 'string') { | ||
throw new TypeError('serviceUrl must be a string type'); | ||
var err = new TypeError('serviceUrl must be a string type'); | ||
log.throw('getHttpServiceFunction', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -333,10 +443,10 @@ | ||
if (res.statusCode === 200) { | ||
var obj; | ||
try { | ||
var obj = JSON.parse(data); | ||
log.entry('httpServiceFunction.callback', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'service:', obj.service); | ||
callback(undefined, obj.service); | ||
log.exit('httpServiceFunction.callback', log.NO_CLIENT_ID, null); | ||
obj = JSON.parse(data); | ||
} catch (err) { | ||
log.log('error', log.NO_CLIENT_ID, err); | ||
err.message = 'http request to ' + serviceUrl + ' returned ' + | ||
'unparseable JSON: ' + err.message; | ||
log.caught('httpServiceFunction.req.on.end.callback', | ||
log.NO_CLIENT_ID, err); | ||
log.entry('httpServiceFunction.callback', log.NO_CLIENT_ID); | ||
@@ -347,4 +457,13 @@ log.log('parms', log.NO_CLIENT_ID, 'err:', err); | ||
} | ||
if (obj) { | ||
log.entry('httpServiceFunction.callback', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'service:', obj.service); | ||
callback(undefined, obj.service); | ||
log.exit('httpServiceFunction.callback', log.NO_CLIENT_ID, null); | ||
} | ||
} else { | ||
var err = new Error(data); | ||
var err = new Error(); | ||
err.message = 'http request to ' + serviceUrl + ' failed with a ' + | ||
'status code of ' + res.statusCode; | ||
if (data) err.message += ': ' + data; | ||
log.log('error', log.NO_CLIENT_ID, err); | ||
@@ -361,2 +480,4 @@ log.entry('httpServiceFunction.callback', log.NO_CLIENT_ID); | ||
}).on('error', function(err) { | ||
err.message = 'http request to ' + serviceUrl + ' failed ' + | ||
'with an error: ' + err.message; | ||
log.log('error', log.NO_CLIENT_ID, err); | ||
@@ -368,3 +489,11 @@ log.entry('httpServiceFunction.callback', log.NO_CLIENT_ID); | ||
}); | ||
req.setTimeout(5000); | ||
req.setTimeout(5000, function() { | ||
var err = new Error('http request to ' + serviceUrl + ' timed out ' + | ||
'after 5000 milliseconds'); | ||
log.log('error', log.NO_CLIENT_ID, err); | ||
log.entry('httpServiceFunction.callback', log.NO_CLIENT_ID); | ||
log.log('parms', log.NO_CLIENT_ID, 'err:', err); | ||
callback(err); | ||
log.exit('httpServiceFunction.callback', log.NO_CLIENT_ID, null); | ||
}); | ||
req.end(); | ||
@@ -428,2 +557,4 @@ | ||
var err, msg; | ||
// Ensure the service is an Array or Function | ||
@@ -437,2 +568,11 @@ var serviceList, serviceFunction; | ||
serviceFunction = getHttpServiceFunction(service); | ||
} else if (serviceUrl.protocol === 'file:') { | ||
if (serviceUrl.host.length > 0 && serviceUrl.host !== 'localhost') { | ||
msg = 'service contains unsupported file URI of ' + service + | ||
', only file:///path or file://localhost/path are supported.'; | ||
err = new Error(msg); | ||
log.throw('Client.constructor', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
serviceFunction = getFileServiceFunction(serviceUrl.path); | ||
} | ||
@@ -449,5 +589,7 @@ } | ||
if (id.length > 48) { | ||
var msg = "Client identifier '" + id + "' is longer than the maximum ID " + | ||
'length of 48.'; | ||
throw new RangeError(msg); | ||
msg = "Client identifier '" + id + "' is longer than the maximum ID " + | ||
'length of 48.'; | ||
err = new RangeError(msg); | ||
log.throw('Client.constructor', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -460,5 +602,6 @@ | ||
if (validClientIdChars.indexOf(id[i]) == -1) { | ||
var err = "Client Identifier '" + id + "' contains invalid char: " + | ||
id[i]; | ||
throw new Error(err); | ||
msg = "Client Identifier '" + id + "' contains invalid char: " + id[i]; | ||
err = new Error(msg); | ||
log.throw('Client.constructor', log.NO_CLIENT_ID, err); | ||
throw err; | ||
} | ||
@@ -469,4 +612,6 @@ } | ||
if ((user && !password) || (!user && password)) { | ||
throw new TypeError('both user and password properties ' + | ||
err = new TypeError('both user and password properties ' + | ||
'must be specified together'); | ||
log.throw('Client.constructor', id, err); | ||
throw err; | ||
} | ||
@@ -554,3 +699,5 @@ // Save the required data as client fields | ||
if (callback && (typeof callback !== 'function')) { | ||
throw new TypeError('Callback must be a function'); | ||
var err = new TypeError('Callback must be a function'); | ||
log.throw('Client.connect', this.id, err); | ||
throw err; | ||
} | ||
@@ -569,2 +716,4 @@ | ||
}); | ||
log.exit('Client.connect.performConnect', client.id, null); | ||
return; | ||
@@ -598,4 +747,12 @@ } else { | ||
} else { | ||
client.serviceList = generateServiceList(service); | ||
client.connectToService(callback); | ||
try { | ||
client.serviceList = generateServiceList(service); | ||
client.connectToService(callback); | ||
} catch (err) { | ||
log.entry('Client.connect.performConnect.serviceFunction.callback', | ||
client.id); | ||
callback(err); | ||
log.exit('Client.connect.performConnect.serviceFunction.callback', | ||
client.id, null); | ||
} | ||
} | ||
@@ -650,4 +807,4 @@ }); | ||
if (client.getState() === 'diconnecting' || | ||
client.getState() === 'diconnected') { | ||
if (client.getState() === 'disconnecting' || | ||
client.getState() === 'disconnected') { | ||
if (callback) { | ||
@@ -689,3 +846,5 @@ log.entry('Client.connectToService.callback', client.id); | ||
error = err; | ||
log.caught('Client.connectToService', client.id, err); | ||
log.ffdc('Client.connectToService', 'ffdc001', client.id, err); | ||
log.throw('Client.connectToService', client.id, err); | ||
throw err; | ||
@@ -721,2 +880,23 @@ } | ||
// Setup heartbeat timer to ensure that while connected we send heartbeat | ||
// frames to keep the connection alive, when required. | ||
var remoteIdleTimeout = | ||
client.messenger.getRemoteIdleTimeout(client.service); | ||
var heartbeatInterval = remoteIdleTimeout > 0 ? | ||
remoteIdleTimeout / 2 : remoteIdleTimeout; | ||
log.log('data', client.id, 'set heartbeatInterval to: ', heartbeatInterval); | ||
if (heartbeatInterval > 0) { | ||
var performHeartbeat = function(client, heartbeatInterval) { | ||
log.entry('Client.connectToService.performHeartbeat', client.id); | ||
if (client.messenger) { | ||
client.messenger.work(0); | ||
client.heartbeatTimeout = setTimeout(performHeartbeat, | ||
heartbeatInterval, client, heartbeatInterval); | ||
} | ||
log.exit('Client.connectToService.performHeartbeat', client.id); | ||
}; | ||
client.heartbeatTimeout = setTimeout(performHeartbeat, heartbeatInterval, | ||
client, heartbeatInterval); | ||
} | ||
} else { | ||
@@ -799,4 +979,6 @@ // We've tried all services without success. Pause for a while before | ||
if (client.outstandingSends.length === 0) { | ||
if (client.messenger) { | ||
client.messenger.stop(); | ||
var messenger = client.messenger; | ||
if (messenger && !messenger.stopped) { | ||
messenger.stop(); | ||
if (client.heartbeatTimeout) clearTimeout(client.heartbeatTimeout); | ||
} | ||
@@ -826,6 +1008,10 @@ | ||
setImmediate(performDisconnect, client, callback); | ||
log.exit('Client.disconnect.performDisconnect', client.id, null); | ||
}; | ||
if (callback && !(callback instanceof Function)) { | ||
throw new TypeError('callback must be a function'); | ||
var err = new TypeError('callback must be a function'); | ||
log.throw('Client.disconnect', client.id, err); | ||
throw err; | ||
} | ||
@@ -871,10 +1057,26 @@ | ||
if (client.getState() !== 'connected') { | ||
if (client.getState() === 'disconnected' || | ||
client.getState() === 'disconnecting') { | ||
log.exit('Client.reconnect', client.id, null); | ||
return undefined; | ||
} else if (client.getState() === 'retrying') { | ||
log.exit('Client.reconnect', client.id, client); | ||
return client; | ||
} | ||
} | ||
client.state = 'retrying'; | ||
// stop the messenger to free the object then attempt a reconnect | ||
client.messenger.stop(); | ||
var messenger = client.messenger; | ||
if (messenger && !messenger.stopped) { | ||
messenger.stop(); | ||
if (client.heartbeatTimeout) clearTimeout(client.heartbeatTimeout); | ||
} | ||
var reestablishSubsList = []; | ||
// clear the subscriptions list, if the cause of the reconnect happens during | ||
// check for messages we need a 0 length so it will check once reconnected. | ||
// TODO: need to resubscribe to the existing subs so this logic may change | ||
while (client.subscriptions.length > 0) { | ||
client.subscriptions.pop(); | ||
reestablishSubsList.push(client.subscriptions.pop()); | ||
} | ||
@@ -886,2 +1088,22 @@ // also clear any left over outstanding sends | ||
var resubscribe = function() { | ||
log.entry('Client.reconnect.resubscribe', client.id); | ||
while (reestablishSubsList.length > 0) { | ||
var sub = reestablishSubsList.pop(); | ||
client.subscribe(sub.topicPattern, sub.share, sub.options, | ||
function(err, pattern) { | ||
//if err we don't wanto 'lose' subs in the reestablish list add to | ||
//clients subscriptions list so the next reconnect picks them up. | ||
if (err) { | ||
client.subscriptions.push(sub); | ||
//rather than keep looping add the rest of the loop to | ||
//subscriptions here so we don't try another subscribe | ||
while (reestablishSubsList.length > 0) { | ||
client.subscriptions.push(reestablishSubsList.pop()); | ||
} | ||
} | ||
}); | ||
} | ||
log.exit('Client.reconnect.resubscribe'); | ||
}; | ||
// if client is using serviceFunction, re-generate the list of services | ||
@@ -895,9 +1117,11 @@ // TODO: merge these copy & paste | ||
} else { | ||
client.serviceList = generateServiceList(service); | ||
client.connectToService(undefined); | ||
setImmediate(function() { | ||
client.serviceList = generateServiceList(service); | ||
client.connectToService.apply(client, [resubscribe]); | ||
}); | ||
} | ||
}); | ||
} else { | ||
setImmediate(function() { | ||
client.connectToService.apply(client, undefined); | ||
setImmediate(function() { | ||
client.connectToService.apply(client, [resubscribe]); | ||
}); | ||
@@ -1003,5 +1227,9 @@ } | ||
var err; | ||
// Validate the passed parameters | ||
if (!topic) { | ||
throw new TypeError('Cannot send to undefined topic'); | ||
err = new TypeError('Cannot send to undefined topic'); | ||
log.throw('Client.send', this.id, err); | ||
throw err; | ||
} else { | ||
@@ -1011,8 +1239,12 @@ topic = String(topic); | ||
log.log('parms', this.id, 'topic:', topic); | ||
log.log('parms', this.id, 'data: typeof', typeof data); | ||
if (data === undefined) { | ||
throw new TypeError('Cannot send undefined data'); | ||
err = new TypeError('Cannot send undefined data'); | ||
log.throw('Client.send', this.id, err); | ||
throw err; | ||
} else if (data instanceof Function) { | ||
throw new TypeError('Cannot send a function'); | ||
err = new TypeError('Cannot send a function'); | ||
log.throw('Client.send', this.id, err); | ||
throw err; | ||
} | ||
log.log('parms', this.id, 'data:', data); | ||
@@ -1033,4 +1265,6 @@ // If the last argument is a Function then it must be a callback, and not | ||
} else { | ||
throw new TypeError('options must be an object type not a ' + | ||
err = new TypeError('options must be an object type not a ' + | ||
(typeof options) + ')'); | ||
log.throw('Client.send', this.id, err); | ||
throw err; | ||
} | ||
@@ -1047,4 +1281,6 @@ } | ||
} else { | ||
throw new TypeError("options:qos value '" + options.qos + | ||
err = new TypeError("options:qos value '" + options.qos + | ||
"' is invalid must evaluate to 0 or 1"); | ||
log.throw('Client.send', this.id, err); | ||
throw err; | ||
} | ||
@@ -1058,11 +1294,19 @@ } | ||
if (!(callback instanceof Function)) { | ||
throw new TypeError('callback must be a function type'); | ||
err = new TypeError('callback must be a function type'); | ||
log.throw('Client.send', this.id, err); | ||
throw err; | ||
} | ||
} else if (qos === exports.QOS_AT_LEAST_ONCE) { | ||
throw new TypeError('callback must be specified when options:qos value ' + | ||
err = new TypeError('callback must be specified when options:qos value ' + | ||
'of 1 (at least once) is specified'); | ||
log.throw('Client.send', this.id, err); | ||
throw err; | ||
} | ||
// Ensure we have attempted a connect | ||
if (!this.hasConnected()) throw new Error('not connected'); | ||
if (!this.hasConnected()) { | ||
err = new Error('not connected'); | ||
log.throw('Client.send', this.id, err); | ||
throw err; | ||
} | ||
@@ -1178,3 +1422,3 @@ // Send the data as a message to the specified topic | ||
} catch (e) { | ||
log.log('error', client.id, e); | ||
log.caught('Client.send.utilSendComplete', client.id, e); | ||
//error condition so won't retry send remove from list of unsent | ||
@@ -1202,5 +1446,5 @@ index = client.outstandingSends.indexOf(localMessageId); | ||
} catch (err) { | ||
log.log('error', client.id, err); | ||
log.caught('Client.send', client.id, err); | ||
//error condition so won't retry send need to remove it from list of unsent | ||
index = client.outstandingSends.indexOf(localMessageId); | ||
var index = client.outstandingSends.indexOf(localMessageId); | ||
if (index >= 0) client.outstandingSends.splice(index, 1); | ||
@@ -1236,3 +1480,3 @@ process.nextTick(function() { | ||
if (client.state !== 'connected' || client.subscriptions.length === 0) { | ||
log.exitLevel('entry_often', 'checkForMessages', client.id); | ||
log.exitLevel('exit_often', 'checkForMessages', client.id); | ||
return; | ||
@@ -1256,3 +1500,3 @@ } | ||
} catch (_) { | ||
log.log('error', client.id, _); | ||
log.caughtLevel('entry_often', 'checkForMessages', client.id, _); | ||
console.warn(_); | ||
@@ -1264,3 +1508,4 @@ } | ||
var topic = url.parse(protonMsg.address).path.substring(1); | ||
var topic = | ||
decodeURIComponent(url.parse(protonMsg.address).path.substring(1)); | ||
var autoConfirm = true; | ||
@@ -1343,9 +1588,12 @@ var qos = exports.QOS_AT_MOST_ONCE; | ||
protonMsg.destroy(); | ||
throw new Error('No listener for "malformed" event.'); | ||
var err = new Error('No listener for "malformed" event.'); | ||
log.throwLevel('exit_often', 'checkForMessages', this.id, err); | ||
throw err; | ||
} | ||
} else { | ||
log.log('emit', client.id, 'message', data, delivery); | ||
log.log('emit', client.id, 'message', delivery); | ||
try { | ||
client.emit('message', data, delivery); | ||
} catch (err) { | ||
log.caughtLevel('entry_often', 'checkForMessages', client.id, err); | ||
log.log('emit', client.id, 'error', err); | ||
@@ -1368,3 +1616,3 @@ client.emit('error', err); | ||
} catch (err) { | ||
log.log('error', client.id, err); | ||
log.caughtLevel('entry_often', 'checkForMessages', client.id, err); | ||
process.nextTick(function() { | ||
@@ -1377,3 +1625,3 @@ log.log('emit', client.id, 'error', err); | ||
log.exitLevel('entry_often', 'checkForMessages', client.id); | ||
log.exitLevel('exit_often', 'checkForMessages', client.id); | ||
@@ -1436,6 +1684,10 @@ setImmediate(function() { | ||
if (arguments.length === 0) { | ||
throw new TypeError("You must specify a 'topicPattern' argument"); | ||
err = new TypeError("You must specify a 'topicPattern' argument"); | ||
log.throw('Client.subscribe', this.id, err); | ||
throw err; | ||
} | ||
if (!topicPattern) { | ||
throw new TypeError("You must specify a 'topicPattern' argument"); | ||
err = new TypeError("You must specify a 'topicPattern' argument"); | ||
log.throw('Client.subscribe', this.id, err); | ||
throw err; | ||
} | ||
@@ -1478,4 +1730,6 @@ topicPattern = String(topicPattern); | ||
if (share.indexOf(':') >= 0) { | ||
throw new Error("share argument value '" + share + "' is invalid " + | ||
err = new Error("share argument value '" + share + "' is invalid " + | ||
"because it contains a colon (\':\') character"); | ||
log.throw('Client.subscribe', this.id, err); | ||
throw err; | ||
} | ||
@@ -1492,4 +1746,6 @@ share = 'share:' + share + ':'; | ||
} else { | ||
throw new TypeError('options must be an object type not a ' + | ||
err = new TypeError('options must be an object type not a ' + | ||
(typeof options) + ')'); | ||
log.throw('Client.subscribe', this.id, err); | ||
throw err; | ||
} | ||
@@ -1507,4 +1763,6 @@ } | ||
} else { | ||
throw new TypeError("options:qos value '" + options.qos + | ||
err = new TypeError("options:qos value '" + options.qos + | ||
"' is invalid must evaluate to 0 or 1"); | ||
log.throw('Client.subscribe', this.id, err); | ||
throw err; | ||
} | ||
@@ -1518,5 +1776,7 @@ } | ||
} else { | ||
throw new TypeError("options:autoConfirm value '" + | ||
err = new TypeError("options:autoConfirm value '" + | ||
options.autoConfirm + | ||
"' is invalid must evaluate to true or false"); | ||
log.throw('Client.subscribe', this.id, err); | ||
throw err; | ||
} | ||
@@ -1530,7 +1790,13 @@ } | ||
if (callback && !(callback instanceof Function)) { | ||
throw new TypeError('callback must be a function type'); | ||
err = new TypeError('callback must be a function type'); | ||
log.throw('Client.subscribe', this.id, err); | ||
throw err; | ||
} | ||
// Ensure we have attempted a connect | ||
if (!this.hasConnected()) throw new Error('not connected'); | ||
if (!this.hasConnected()) { | ||
err = new Error('not connected'); | ||
log.throw('Client.subscribe', this.id, err); | ||
throw err; | ||
} | ||
@@ -1563,6 +1829,7 @@ // Subscribe using the specified topic pattern and share options | ||
client.subscriptions.push({ address: subscriptionAddress, | ||
qos: qos, autoConfirm: autoConfirm }); | ||
qos: qos, autoConfirm: autoConfirm, topicPattern: topicPattern, | ||
share: originalShareValue, options: options }); | ||
} catch (e) { | ||
log.log('error', client.id, e); | ||
log.caught('Client.subscribe', client.id, e); | ||
err = e; | ||
@@ -1569,0 +1836,0 @@ } |
{ | ||
"name": "mqlight-dev", | ||
"version": "0.1.2014060800", | ||
"version": "0.1.2014062300", | ||
"description": "IBM MQ Light Client Module", | ||
@@ -5,0 +5,0 @@ "main": "mqlight.js", |
@@ -241,8 +241,13 @@ # node-mqlight (beta) | ||
``` | ||
Usage: recv.js [options] <address> | ||
address: amqp://<domain>/<name> | ||
(default amqp://localhost/public) | ||
Usage: recv.js [options] | ||
Options: | ||
-h, --help show this help message and exit | ||
-s URL, --service=URL service to connect to (default: amqp://localhost) | ||
-t TOPICPATTERN, --topic-pattern=TOPICPATTERN | ||
subscribe to receive messages matching TOPICPATTERN | ||
(default: public) | ||
-n NAME, --share-name NAME | ||
optionally, subscribe to a shared destination using | ||
NAME as the share name. | ||
``` | ||
@@ -257,5 +262,5 @@ | ||
-h, --help show this help message and exit | ||
-a ADDRESS, --address=ADDRESS | ||
address: amqp://<domain>/<name> | ||
(default amqp://localhost/public) | ||
-s URL, --service=URL service to connect to (default: amqp://localhost) | ||
-t TOPIC, --topic=TOPIC | ||
send messages to topic TOPIC (default: public) | ||
-d NUM, --delay=NUM add a NUM seconds time delay between each request | ||
@@ -280,4 +285,12 @@ ``` | ||
### 0.1.0 | ||
### 0.1.2014062300 | ||
* Second beta release. | ||
* Support for Mac OS X. | ||
* Support for sending and receiving 'at-least-once' messages either with | ||
automatic or manual confirmation by the receiver. | ||
* Updated samples to use service/topic arguments instead of address. | ||
### 0.1.2014042204 | ||
* Initial beta release. | ||
@@ -284,0 +297,0 @@ * Support for sending and receiving 'at-most-once' messages. |
@@ -19,2 +19,5 @@ /* %Z% %W% %I% %E% %U% */ | ||
*/ | ||
/* jslint node: true */ | ||
/* jshint -W083,-W097 */ | ||
'use strict'; | ||
@@ -27,7 +30,11 @@ var mqlight = require('mqlight'); | ||
var types = { | ||
share: String | ||
'share-name': String, | ||
service: String, | ||
'topic-pattern': String | ||
}; | ||
var shorthands = { | ||
h: ['--help'], | ||
s: ['--share'] | ||
n: ['--share-name'], | ||
s: ['--service'], | ||
t: ['--topic-pattern'] | ||
}; | ||
@@ -37,14 +44,19 @@ var parsed = nopt(types, shorthands, process.argv, 2); | ||
if (parsed.help || remain.length > 1) { | ||
console.log('Usage: recv.js [options] <address>'); | ||
console.log(' address: amqp://<domain>/<name>'); | ||
console.log(' (default amqp://localhost/public)'); | ||
if (parsed.help || remain.length > 0) { | ||
console.log('Usage: recv.js [options]'); | ||
console.log(''); | ||
console.log('Options:'); | ||
console.log(' -h, --help show this help message and exit'); | ||
console.log(' -s, --share specify an optional share name to ' + | ||
'create or join a'); | ||
console.log(' shared subscription for the given ' + | ||
'topic'); | ||
console.log(' -s URL, --service=URL service to connect to' + | ||
' (default: amqp://localhost)'); | ||
console.log(' -t TOPICPATTERN, --topic-pattern=TOPICPATTERN'); | ||
console.log(' subscribe to receive messages matching' + | ||
' TOPICPATTERN'); | ||
console.log(' (default: public)'); | ||
console.log(' -n NAME, --share-name NAME'); | ||
console.log(' optionally, subscribe to a shared' + | ||
' destination using'); | ||
console.log(' NAME as the share name.'); | ||
console.log(''); | ||
if (parsed.help) { | ||
@@ -57,28 +69,5 @@ process.exit(0); | ||
// defaults | ||
var hostname = 'localhost'; | ||
var port = 5672; | ||
var topic = 'public'; | ||
var service = parsed.service ? parsed.service : 'amqp://localhost'; | ||
var topic = parsed['topic-pattern'] ? parsed['topic-pattern'] : 'public'; | ||
// extract override values from cmdline arguments (if given) | ||
if (remain[0]) { | ||
var addr = remain[0]; | ||
if (addr.indexOf('amqp://') === 0) { | ||
hostname = addr.replace('amqp://', ''); | ||
} | ||
if (hostname.indexOf('/') > -1) { | ||
topic = hostname.substring(hostname.indexOf('/') + 1); | ||
hostname = hostname.substring(0, hostname.indexOf('/')); | ||
} else { | ||
topic = addr; | ||
} | ||
if (hostname.indexOf(':') > -1) { | ||
var split = hostname.split(':'); | ||
hostname = split[0]; | ||
port = split[1]; | ||
} | ||
} | ||
var service = 'amqp://' + hostname + ':' + port; | ||
// connect client to broker | ||
@@ -96,3 +85,3 @@ var opts = { | ||
// now subscribe to topic for publications | ||
client.subscribe(topic, parsed.share, function(err, pattern) { | ||
client.subscribe(topic, parsed['share-name'], function(err, pattern) { | ||
if (err) { | ||
@@ -115,5 +104,5 @@ console.error('Problem with subscribe request: %s', err.message); | ||
client.on('malformed', function(data, delivery) { | ||
console.log('*** received malformed message (%d)', (++i)); | ||
console.log(data); | ||
console.log(delivery); | ||
console.error('*** received malformed message (%d)', (++i)); | ||
console.error(data); | ||
console.error(delivery); | ||
}); | ||
@@ -123,8 +112,8 @@ }); | ||
client.on('error', function(error) { | ||
console.log('*** error ***'); | ||
console.error('*** error ***'); | ||
if (error) { | ||
if (error.message) console.log('message: '+error.message); | ||
else if (error.stack) console.log(error.stack); | ||
if (error.message) console.error('message: %s', error.message); | ||
else if (error.stack) console.error(error.stack); | ||
} | ||
console.log('exiting.'); | ||
console.error('exiting.'); | ||
process.exit(1); | ||
@@ -131,0 +120,0 @@ }); |
@@ -19,2 +19,5 @@ /* %Z% %W% %I% %E% %U% */ | ||
*/ | ||
/* jslint node: true */ | ||
/* jshint -W083,-W097 */ | ||
'use strict'; | ||
@@ -27,7 +30,9 @@ var mqlight = require('mqlight'); | ||
var types = { | ||
address: String, | ||
service: String, | ||
topic: String, | ||
delay: Number | ||
}; | ||
var shorthands = { | ||
a: ['--address'], | ||
s: ['--service'], | ||
t: ['--topic'], | ||
d: ['--delay'], | ||
@@ -43,5 +48,7 @@ h: ['--help'] | ||
console.log(' -h, --help show this help message and exit'); | ||
console.log(' -a ADDRESS, --address=ADDRESS'); | ||
console.log(' address: amqp://<domain>/<name>'); | ||
console.log(' (default amqp://localhost/public)'); | ||
console.log(' -s URL, --service=URL service to connect to' + | ||
' (default: amqp://localhost)'); | ||
console.log(' -t TOPIC, --topic=TOPIC'); | ||
console.log(' send messages to topic TOPIC' + | ||
' (default: public)'); | ||
console.log(' -d NUM, --delay=NUM add a NUM seconds time delay between' + | ||
@@ -53,28 +60,5 @@ ' each request'); | ||
// defaults | ||
var hostname = 'localhost'; | ||
var port = 5672; | ||
var topic = 'public'; | ||
var topic = parsed.topic ? parsed.topic : 'public'; | ||
var service = parsed.service ? parsed.service : 'amqp://localhost'; | ||
// extract override values from cmdline arguments (if given) | ||
if (parsed.address) { | ||
var addr = parsed.address; | ||
if (addr.indexOf('amqp://') === 0) { | ||
hostname = addr.replace('amqp://', ''); | ||
} | ||
if (hostname.indexOf('/') > -1) { | ||
topic = hostname.substring(hostname.indexOf('/') + 1); | ||
hostname = hostname.substring(0, hostname.indexOf('/')); | ||
} else { | ||
topic = addr; | ||
} | ||
if (hostname.indexOf(':') > -1) { | ||
var split = hostname.split(':'); | ||
hostname = split[0]; | ||
port = split[1]; | ||
} | ||
} | ||
var service = 'amqp://' + hostname + ':' + port; | ||
// create client to connect to broker with | ||
@@ -129,8 +113,8 @@ var opts = { | ||
client.on('error', function(error) { | ||
console.log('*** error ***'); | ||
console.error('*** error ***'); | ||
if (error) { | ||
if (error.message) console.log('message: '+error.message); | ||
else if (error.stack) console.log(error.stack); | ||
if (error.message) console.error('message: %s', error.message); | ||
else if (error.stack) console.error(error.stack); | ||
} | ||
console.log('exiting.'); | ||
console.error('exiting.'); | ||
process.exit(1); | ||
@@ -137,0 +121,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
9363608
66
5352
298
34
10