diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 31b2172..0000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "stage": 1 -} \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..528d46d --- /dev/null +++ b/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "eslint-config-taskcluster" +} diff --git a/package.json b/package.json index 32f97b5..cee9de1 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "compile": "babel-compile -p taskcluster src:lib test:.test", "prepublish": "npm run compile", "pretest": "npm run compile", - "test": "mocha ./.test/*_test.js" + "test": "mocha .test/lint.js ./.test/*_test.js" }, "repository": { "type": "git", @@ -17,10 +17,14 @@ "dependencies": { "amqplib": "^0.5.1", "babel-compile": "^2.0.0", + "babel-eslint": "^8", "babel-preset-taskcluster": "^3.0.0", "debug": "^3.1.0", + "eslint-config-taskcluster": "^2.0.0", + "eslint-plugin-taskcluster": "^1.0.2", "hawk": "^6.0.2", "lodash": "^4.17.4", + "mocha-eslint": "^3.0.1", "promise": "^8.0.1", "pulse-publisher": "^2.0.0", "slugid": "^1.1.0", diff --git a/src/client.js b/src/client.js index b442de3..d4bad4f 100644 --- a/src/client.js +++ b/src/client.js @@ -19,7 +19,7 @@ var querystring = require('querystring'); var AGENT_OPTIONS = { maxSockets: 50, maxFreeSockets: 0, - keepAlive: false + keepAlive: false, }; /** @@ -29,7 +29,7 @@ var AGENT_OPTIONS = { */ var DEFAULT_AGENTS = { http: new http.Agent(AGENT_OPTIONS), - https: new https.Agent(AGENT_OPTIONS) + https: new https.Agent(AGENT_OPTIONS), }; // Exports agents, consumers can provide their own default agents and tests @@ -42,7 +42,7 @@ var _defaultOptions = { credentials: { clientId: process.env.TASKCLUSTER_CLIENT_ID, accessToken: process.env.TASKCLUSTER_ACCESS_TOKEN, - certificate: process.env.TASKCLUSTER_CERTIFICATE + certificate: process.env.TASKCLUSTER_CERTIFICATE, }, // Request time out (defaults to 30 seconds) timeout: 30 * 1000, @@ -94,9 +94,9 @@ var makeRequest = function(client, method, url, payload, query) { credentials: { id: client._options.credentials.clientId, key: client._options.credentials.accessToken, - algorithm: 'sha256' + algorithm: 'sha256', }, - ext: client._extData + ext: client._extData, }); req.set('Authorization', header.field); } @@ -105,7 +105,6 @@ var makeRequest = function(client, method, url, payload, query) { return req; }; - /** * Create a client class from a JSON reference, and an optional `name`, which is * mostly intended for debugging, error messages and stats. @@ -135,7 +134,7 @@ var makeRequest = function(client, method, url, payload, query) { * `baseUrl` and `exchangePrefix` defaults to values from reference. */ exports.createClient = function(reference, name) { - if (!name || typeof(name) !== 'string') { + if (!name || typeof name !== 'string') { name = 'Unknown'; } @@ -143,19 +142,19 @@ exports.createClient = function(reference, name) { var Client = function(options) { this._options = _.defaults({}, options || {}, { baseUrl: reference.baseUrl || '', - exchangePrefix: reference.exchangePrefix || '' + exchangePrefix: reference.exchangePrefix || '', }, _defaultOptions); // Remove possible trailing slash from baseUrl - this._options.baseUrl = this._options.baseUrl.replace(/\/$/, '') + this._options.baseUrl = this._options.baseUrl.replace(/\/$/, ''); if (this._options.stats) { - throw new Error("options.stats is now deprecated! Use options.monitor instead."); + throw new Error('options.stats is now deprecated! Use options.monitor instead.'); } if (this._options.randomizationFactor < 0 || this._options.randomizationFactor >= 1) { - throw new Error("options.randomizationFactor must be between 0 and 1!"); + throw new Error('options.randomizationFactor must be between 0 and 1!'); } // Shortcut for which default agent to use... @@ -188,14 +187,13 @@ exports.createClient = function(reference, name) { if (this._options.credentials.certificate) { ext.certificate = this._options.credentials.certificate; // Parse as JSON if it's a string - if (typeof(ext.certificate) === 'string') { + if (typeof ext.certificate === 'string') { try { ext.certificate = JSON.parse(ext.certificate); - } - catch(err) { - debug("Failed to parse credentials.certificate, err: %s, JSON: %j", + } catch (err) { + debug('Failed to parse credentials.certificate, err: %s, JSON: %j', err, err); - throw new Error("JSON.parse(): Failed for configured certificate"); + throw new Error('JSON.parse(): Failed for configured certificate'); } } } @@ -237,18 +235,18 @@ exports.createClient = function(reference, name) { // Validate number of arguments var N = args.length; if (N != nb_args && (optKeys.length === 0 || N != nb_args + 1)) { - throw new Error("Function " + entry.name + " takes " + nb_args + - " arguments, but was given " + N + - " arguments"); + throw new Error('Function ' + entry.name + ' takes ' + nb_args + + ' arguments, but was given ' + N + + ' arguments'); } // Substitute parameters into route var endpoint = entry.route.replace(/<([^<>]+)>/g, function(text, arg) { var index = entry.args.indexOf(arg); if (index !== -1) { var param = args[index]; - if (typeof(param) !== 'string' && typeof(param) !== 'number') { - throw new Error("URL parameter " + arg + " must be a string, but " + - "we received a: " + typeof(param)); + if (typeof param !== 'string' && typeof param !== 'number') { + throw new Error('URL parameter ' + arg + ' must be a string, but ' + + 'we received a: ' + typeof param); } return encodeURIComponent(param); } @@ -266,8 +264,8 @@ exports.createClient = function(reference, name) { if (query) { _.keys(query).forEach(function(key) { if (!_.includes(optKeys, key)) { - throw new Error("Function " + entry.name + " takes options: " + - optKeys.join(', ') + " but was given " + key); + throw new Error('Function ' + entry.name + ' takes options: ' + + optKeys.join(', ') + ' but was given ' + key); } }); } @@ -285,7 +283,7 @@ exports.createClient = function(reference, name) { var retryRequest = function() { // Send request var sendRequest = function() { - debug("Calling: %s, retry: %s", entry.name, attempts - 1); + debug('Calling: %s, retry: %s', entry.name, attempts - 1); // Make request and handle response or error return makeRequest( that, @@ -295,15 +293,15 @@ exports.createClient = function(reference, name) { query ).then(function(res) { // If request was successful, accept the result - debug("Success calling: %s, (%s retries)", + debug('Success calling: %s, (%s retries)', entry.name, attempts - 1); if (monitor) { var d = process.hrtime(start); monitor.measure([entry.name, 'success'], d[0] * 1000 + d[1] / 1000000); monitor.count([entry.name, 'success']); } - if(!_.includes(res.headers['content-type'], 'application/json') || !res.body) { - debug("Empty response from server: call: %s, method: %s",entry.name,entry.method); + if (!_.includes(res.headers['content-type'], 'application/json') || !res.body) { + debug('Empty response from server: call: %s, method: %s', entry.name, entry.method); return undefined; } return res.body; @@ -313,21 +311,21 @@ exports.createClient = function(reference, name) { if (res) { // Decide if we should retry if (attempts <= that._options.retries && - 500 <= res.status && // Check if it's a 5xx error + res.status >= 500 && // Check if it's a 5xx error res.status < 600) { - debug("Error calling: %s now retrying, info: %j", + debug('Error calling: %s now retrying, info: %j', entry.name, res.body); return retryRequest(); } // If not retrying, construct error object and reject - debug("Error calling: %s NOT retrying!, info: %j", + debug('Error calling: %s NOT retrying!, info: %j', entry.name, res.body); - var message = "Unknown Server Error"; + var message = 'Unknown Server Error'; if (res.status === 401) { - message = "Authentication Error"; + message = 'Authentication Error'; } if (res.status === 500) { - message = "Internal Server Error"; + message = 'Internal Server Error'; } err = new Error(res.body.message || message); err.body = res.body; @@ -348,11 +346,11 @@ exports.createClient = function(reference, name) { // Decide if we should retry if (attempts <= that._options.retries) { - debug("Request error calling %s (retrying), err: %s, JSON: %s", + debug('Request error calling %s (retrying), err: %s, JSON: %s', entry.name, err, err); return retryRequest(); } - debug("Request error calling %s NOT retrying!, err: %s, JSON: %s", + debug('Request error calling %s NOT retrying!, err: %s, JSON: %s', entry.name, err, err); if (monitor) { var d = process.hrtime(start); @@ -361,7 +359,7 @@ exports.createClient = function(reference, name) { } throw err; }); - } + }; // Increment attempt count, but track how many we had before. attempts += 1; @@ -377,7 +375,7 @@ exports.createClient = function(reference, name) { delay = Math.pow(2, attempts - 1) * that._options.delayFactor; // Apply randomization factor var rf = that._options.randomizationFactor; - delay = delay * (Math.random() * 2 * rf + 1 - rf); + delay *= Math.random() * 2 * rf + 1 - rf; // Always limit with a maximum delay delay = Math.min(delay, that._options.maxDelay); // Sleep then send the request @@ -402,7 +400,7 @@ exports.createClient = function(reference, name) { }).forEach(function(entry) { // Create function for routing-key pattern construction Client.prototype[entry.name] = function(routingKeyPattern) { - if (typeof(routingKeyPattern) !== 'string') { + if (typeof routingKeyPattern !== 'string') { // Allow for empty routing key patterns if (routingKeyPattern === undefined || routingKeyPattern === null) { @@ -410,7 +408,7 @@ exports.createClient = function(reference, name) { } // Check that the routing key pattern is an object assert(routingKeyPattern instanceof Object, - "routingKeyPattern must be an object"); + 'routingKeyPattern must be an object'); // Construct routingkey pattern as string from reference routingKeyPattern = entry.routingKey.map(function(key) { @@ -421,21 +419,21 @@ exports.createClient = function(reference, name) { value = key.constant; } // If number convert to string - if (typeof(value) === 'number') { + if (typeof value === 'number') { return '' + value; } // Validate string and return - if (typeof(value) === 'string') { + if (typeof value === 'string') { // Check for multiple words assert(key.multipleWords || value.indexOf('.') === -1, - "routingKey pattern '" + value + "' for " + key.name + - " cannot contain dots as it does not hold multiple words"); + 'routingKey pattern \'' + value + '\' for ' + key.name + + ' cannot contain dots as it does not hold multiple words'); return value; } // Check that we haven't got an invalid value assert(value === null || value === undefined, - "Value: '" + value + "' is not supported as routingKey "+ - "pattern for " + key.name); + 'Value: \'' + value + '\' is not supported as routingKey '+ + 'pattern for ' + key.name); // Return default pattern for entry not being matched return key.multipleWords ? '#' : '*'; }).join('.'); @@ -445,7 +443,7 @@ exports.createClient = function(reference, name) { return { exchange: this._options.exchangePrefix + entry.exchange, routingKeyPattern: routingKeyPattern, - routingKeyReference: _.cloneDeep(entry.routingKey) + routingKeyReference: _.cloneDeep(entry.routingKey), }; }; }); @@ -454,144 +452,143 @@ exports.createClient = function(reference, name) { // input parameters Client.prototype.buildUrl = function() { // Convert arguments to actual array - var args = Array.prototype.slice.call(arguments); - if (args.length == 0) { - throw new Error("buildUrl(method, arg1, arg2, ...) takes a least one " + - "argument!"); - } + var args = Array.prototype.slice.call(arguments); + if (args.length == 0) { + throw new Error('buildUrl(method, arg1, arg2, ...) takes a least one ' + + 'argument!'); + } // Find the method - var method = args.shift(); - var entry = method.entryReference; - if (!entry || entry.type !== 'function') { - throw new Error("method in buildUrl(method, arg1, arg2, ...) must be " + - "an API method from the same object!"); - } + var method = args.shift(); + var entry = method.entryReference; + if (!entry || entry.type !== 'function') { + throw new Error('method in buildUrl(method, arg1, arg2, ...) must be ' + + 'an API method from the same object!'); + } // Get the query-string options taken - var optKeys = entry.query || []; - var supportsOpts = (optKeys.length !== 0); + var optKeys = entry.query || []; + var supportsOpts = optKeys.length !== 0; - debug("build url for: " + entry.name); + debug('build url for: ' + entry.name); // Validate number of arguments - var N = entry.args.length; - if (args.length !== N && (!supportsOpts || args.length !== N + 1)) { - throw new Error("Function " + entry.name + "buildUrl() takes " + - (N + 1) + " arguments, but was given " + - (args.length + 1) + " arguments"); - } + var N = entry.args.length; + if (args.length !== N && (!supportsOpts || args.length !== N + 1)) { + throw new Error('Function ' + entry.name + 'buildUrl() takes ' + + (N + 1) + ' arguments, but was given ' + + (args.length + 1) + ' arguments'); + } // Substitute parameters into route - var endpoint = entry.route.replace(/<([^<>]+)>/g, function(text, arg) { - var index = entry.args.indexOf(arg); - if (index !== -1) { - var param = args[index]; - if (typeof(param) !== 'string' && typeof(param) !== 'number') { - throw new Error("URL parameter " + arg + " must be a string, but " + - "we received a: " + typeof(param)); - } - return encodeURIComponent(param); + var endpoint = entry.route.replace(/<([^<>]+)>/g, function(text, arg) { + var index = entry.args.indexOf(arg); + if (index !== -1) { + var param = args[index]; + if (typeof param !== 'string' && typeof param !== 'number') { + throw new Error('URL parameter ' + arg + ' must be a string, but ' + + 'we received a: ' + typeof param); } - return text; // Preserve original - }); + return encodeURIComponent(param); + } + return text; // Preserve original + }); // Find query string options (if present) - var query = args[N] || ''; - if (query) { - _.keys(query).forEach(function(key) { - if (!_.includes(optKeys, key)) { - throw new Error("Function " + entry.name + " takes options: " + - optKeys.join(', ') + " but was given " + key); - } - }); - - query = querystring.stringify(query); - if (query.length > 0) { - query = '?' + query; + var query = args[N] || ''; + if (query) { + _.keys(query).forEach(function(key) { + if (!_.includes(optKeys, key)) { + throw new Error('Function ' + entry.name + ' takes options: ' + + optKeys.join(', ') + ' but was given ' + key); } + }); + + query = querystring.stringify(query); + if (query.length > 0) { + query = '?' + query; } + } - return this._options.baseUrl + endpoint + query; - }; + return this._options.baseUrl + endpoint + query; + }; // Utility function to construct a bewit URL for GET requests - Client.prototype.buildSignedUrl = function() { + Client.prototype.buildSignedUrl = function() { // Convert arguments to actual array - var args = Array.prototype.slice.call(arguments); - if (args.length == 0) { - throw new Error("buildSignedUrl(method, arg1, arg2, ..., [options]) " + - "takes a least one argument!"); - } + var args = Array.prototype.slice.call(arguments); + if (args.length == 0) { + throw new Error('buildSignedUrl(method, arg1, arg2, ..., [options]) ' + + 'takes a least one argument!'); + } // Find method and reference entry - var method = args[0]; - var entry = method.entryReference; - if (entry.method !== 'get') { - throw new Error("buildSignedUrl only works for GET requests"); - } + var method = args[0]; + var entry = method.entryReference; + if (entry.method !== 'get') { + throw new Error('buildSignedUrl only works for GET requests'); + } // Default to 15 minutes before expiration - var expiration = 15 * 60; + var expiration = 15 * 60; // Check if method supports query-string options - var supportsOpts = ((entry.query || []).length !== 0) + var supportsOpts = (entry.query || []).length !== 0; // if longer than method + args, then we have options too - var N = entry.args.length + 1; - if (supportsOpts) { - N += 1; - } - if (args.length > N) { + var N = entry.args.length + 1; + if (supportsOpts) { + N += 1; + } + if (args.length > N) { // Get request options - var options = args.pop(); + var options = args.pop(); // Get expiration from options - expiration = options.expiration || expiration; + expiration = options.expiration || expiration; // Complain if expiration isn't a number - if (typeof(expiration) !== 'number') { - throw new Error("options.expiration must be a number"); - } + if (typeof expiration !== 'number') { + throw new Error('options.expiration must be a number'); } + } // Build URL - var requestUrl = this.buildUrl.apply(this, args); + var requestUrl = this.buildUrl.apply(this, args); // Check that we have credentials - if (!this._options.credentials.clientId) { - throw new Error("credentials must be given"); - } - if (!this._options.credentials.accessToken) { - throw new Error("accessToken must be given"); - } + if (!this._options.credentials.clientId) { + throw new Error('credentials must be given'); + } + if (!this._options.credentials.accessToken) { + throw new Error('accessToken must be given'); + } // Create bewit (this is messed up, function differs in browser) - var bewit = (hawk.client.getBewit || hawk.client.bewit)(requestUrl, { - credentials: { - id: this._options.credentials.clientId, - key: this._options.credentials.accessToken, - algorithm: 'sha256' - }, - ttlSec: expiration, - ext: this._extData - }); + var bewit = (hawk.client.getBewit || hawk.client.bewit)(requestUrl, { + credentials: { + id: this._options.credentials.clientId, + key: this._options.credentials.accessToken, + algorithm: 'sha256', + }, + ttlSec: expiration, + ext: this._extData, + }); // Add bewit to requestUrl - var urlParts = url.parse(requestUrl); - if (urlParts.search) { - urlParts.search += "&bewit=" + bewit; - } else { - urlParts.search = "?bewit=" + bewit; - } + var urlParts = url.parse(requestUrl); + if (urlParts.search) { + urlParts.search += '&bewit=' + bewit; + } else { + urlParts.search = '?bewit=' + bewit; + } // Return formatted URL - return url.format(urlParts); - }; + return url.format(urlParts); + }; // Return client class return Client; }; - // Load data from apis.js var apis = require('./apis'); @@ -631,7 +628,7 @@ exports.config = function(options) { * Returns an object on the form: {clientId, accessToken, certificate} */ exports.createTemporaryCredentials = function(options) { - assert(options, "options are required"); + assert(options, 'options are required'); // Get now as default value for start var now = new Date(); @@ -640,34 +637,34 @@ exports.createTemporaryCredentials = function(options) { // Set default options options = _.defaults({}, options, { start: now, - scopes: [] + scopes: [], }, _defaultOptions); // Validate options - assert(options.credentials, "options.credentials is required"); + assert(options.credentials, 'options.credentials is required'); assert(options.credentials.clientId, - "options.credentials.clientId is required"); + 'options.credentials.clientId is required'); assert(options.credentials.accessToken, - "options.credentials.accessToken is required"); + 'options.credentials.accessToken is required'); assert(options.credentials.certificate === undefined || options.credentials.certificate === null, - "temporary credentials cannot be used to make new temporary " + - "credentials; ensure that options.credentials.certificate is null"); - assert(options.start instanceof Date, "options.start must be a Date"); - assert(options.expiry instanceof Date, "options.expiry must be a Date"); - assert(options.scopes instanceof Array, "options.scopes must be an array"); + 'temporary credentials cannot be used to make new temporary ' + + 'credentials; ensure that options.credentials.certificate is null'); + assert(options.start instanceof Date, 'options.start must be a Date'); + assert(options.expiry instanceof Date, 'options.expiry must be a Date'); + assert(options.scopes instanceof Array, 'options.scopes must be an array'); options.scopes.forEach(function(scope) { - assert(typeof(scope) === 'string', - "options.scopes must be an array of strings"); + assert(typeof scope === 'string', + 'options.scopes must be an array of strings'); }); assert(options.expiry.getTime() - options.start.getTime() <= - 31 * 24 * 60 * 60 * 1000, "Credentials cannot span more than 31 days"); + 31 * 24 * 60 * 60 * 1000, 'Credentials cannot span more than 31 days'); var isNamed = !!options.clientId; if (isNamed) { assert(options.clientId !== options.credentials.clientId, - "Credential issuer must be different from the name"); + 'Credential issuer must be different from the name'); } // Construct certificate @@ -677,7 +674,7 @@ exports.createTemporaryCredentials = function(options) { start: options.start.getTime(), expiry: options.expiry.getTime(), seed: slugid.v4() + slugid.v4(), - signature: null // generated later + signature: null, // generated later }; if (isNamed) { cert.issuer = options.credentials.clientId; @@ -710,7 +707,7 @@ exports.createTemporaryCredentials = function(options) { return { clientId: isNamed ? options.clientId : options.credentials.clientId, accessToken: accessToken, - certificate: JSON.stringify(cert) + certificate: JSON.stringify(cert), }; }; @@ -742,9 +739,9 @@ exports.credentialInformation = function(credentials) { // distinguish permacreds from temporary creds if (credentials.certificate) { - result.type = "temporary"; + result.type = 'temporary'; var cert; - if (typeof credentials.certificate === "string") { + if (typeof credentials.certificate === 'string') { try { cert = JSON.parse(credentials.certificate); } catch (err) { @@ -761,7 +758,7 @@ exports.credentialInformation = function(credentials) { issuer = cert.issuer; } } else { - result.type = "permanent"; + result.type = 'permanent'; } var anonClient = new exports.Auth(); diff --git a/src/parsetime.js b/src/parsetime.js index f6f1a7c..3b7c59c 100644 --- a/src/parsetime.js +++ b/src/parsetime.js @@ -1,5 +1,3 @@ -"use strict"; - // Regular expression matching: // A years B months C days D hours E minutes F seconds var timeExp = new RegExp([ @@ -11,28 +9,27 @@ var timeExp = new RegExp([ '(\\s*(\\d+)\\s*h((ours?)|r)?)?', '(\\s*(\\d+)\\s*m(in(utes?)?)?)?', '(\\s*(\\d+)\\s*s(ec(onds?)?)?)?', - '\\s*$' + '\\s*$', ].join(''), 'i'); - /** Parse time string */ var parseTime = function(str) { // Parse the string var match = timeExp.exec(str || ''); if (!match) { - throw new Error("String: '" + str + "' isn't a time expression"); + throw new Error('String: \'' + str + '\' isn\'t a time expression'); } // Negate if needed - var neg = (match[2] === '-' ? - 1 : 1); + var neg = match[2] === '-' ? - 1 : 1; // Return parsed values return { - years: parseInt(match[4] || 0) * neg, - months: parseInt(match[8] || 0) * neg, - weeks: parseInt(match[11] || 0) * neg, - days: parseInt(match[15] || 0) * neg, - hours: parseInt(match[18] || 0) * neg, - minutes: parseInt(match[22] || 0) * neg, - seconds: parseInt(match[25] || 0) * neg + years: parseInt(match[4] || 0, 10) * neg, + months: parseInt(match[8] || 0, 10) * neg, + weeks: parseInt(match[11] || 0, 10) * neg, + days: parseInt(match[15] || 0, 10) * neg, + hours: parseInt(match[18] || 0, 10) * neg, + minutes: parseInt(match[22] || 0, 10) * neg, + seconds: parseInt(match[25] || 0, 10) * neg, }; }; diff --git a/src/pulselistener.js b/src/pulselistener.js index b957df4..286f3c7 100644 --- a/src/pulselistener.js +++ b/src/pulselistener.js @@ -17,8 +17,8 @@ var URL = require('url'); * } */ var buildPulseConnectionString = function(options) { - assert(options.username, "options.username password is required"); - assert(options.password, "options.password is required"); + assert(options.username, 'options.username password is required'); + assert(options.password, 'options.password is required'); // Construct connection string return [ @@ -29,7 +29,7 @@ var buildPulseConnectionString = function(options) { '@', options.hostname || 'pulse.mozilla.org', ':', - 5671 // Port for SSL + 5671, // Port for SSL ].join(''); }; @@ -37,7 +37,7 @@ var buildPulseConnectionString = function(options) { var retryConnect = function(connectionString, retries) { return amqplib.connect(connectionString, { noDelay: true, - timeout: 30 * 1000 + timeout: 30 * 1000, }).catch(function(err) { if (retries > 0) { return retryConnect(connectionString, retries - 1); @@ -61,9 +61,9 @@ var retryConnect = function(connectionString, retries) { * } */ var PulseConnection = function(options) { - assert(typeof(options) === 'object', "options is required"); + assert(typeof options === 'object', 'options is required'); options = _.defaults({}, options, { - namespace: options.username || '' + namespace: options.username || '', }); // a fake connection does notihng but signal its fake-ness to listeners @@ -75,9 +75,9 @@ var PulseConnection = function(options) { if (!options.connectionString) { options.connectionString = buildPulseConnectionString(options); } else { - assert(!options.username, "Can't take `username` along with `connectionString`"); - assert(!options.password, "Can't take `password` along with `connectionString`"); - assert(!options.hostname, "Can't take `hostname` along with `connectionString`"); + assert(!options.username, 'Can\'t take `username` along with `connectionString`'); + assert(!options.password, 'Can\'t take `password` along with `connectionString`'); + assert(!options.hostname, 'Can\'t take `hostname` along with `connectionString`'); } // If namespace was not explicitly set infer it from connection string... @@ -125,16 +125,16 @@ PulseConnection.prototype.connect = function() { // Setup error handling conn.on('error', function(err) { - debug("Connection error in Connection: %s", err, err.stack); + debug('Connection error in Connection: %s', err, err.stack); that.emit('error', err); }); conn.on('close', function() { if (!that._conn) { return; // Forget this, if close() was called } - debug("Connection closed unexpectedly"); + debug('Connection closed unexpectedly'); that.emit('error', new Error( - "Connection closed unexpectedly, likely server initiated shutdown" + 'Connection closed unexpectedly, likely server initiated shutdown' )); }); @@ -162,7 +162,6 @@ PulseConnection.prototype.close = function() { return Promise.resolve(undefined); }; - // Export PulseConnection exports.PulseConnection = PulseConnection; @@ -193,18 +192,18 @@ exports.PulseConnection = PulseConnection; */ var PulseListener = function(options) { var that = this; - assert(options, "options are required"); + assert(options, 'options are required'); assert(options.connection || - options.credentials, "options.connection or credentials is required"); + options.credentials, 'options.connection or credentials is required'); this._bindings = []; this._options = _.defaults(options, { prefetch: 5, queueName: undefined, - maxLength: undefined + maxLength: undefined, }); - this._fake = (options.credentials && options.credentials.fake) || - (options.connection && options.connection.fake); + this._fake = options.credentials && options.credentials.fake || + options.connection && options.connection.fake; // Ensure that we have connection object this._connection = options.connection || null; @@ -239,13 +238,13 @@ util.inherits(PulseListener, events.EventEmitter); * instance of `Client`, see `createClient`. */ PulseListener.prototype.bind = function(binding) { - assert(typeof(binding.exchange) === 'string', - "Can't bind to unspecified exchange!"); - assert(typeof(binding.routingKeyPattern) === 'string', - "routingKeyPattern is required!"); + assert(typeof binding.exchange === 'string', + 'Can\'t bind to unspecified exchange!'); + assert(typeof binding.routingKeyPattern === 'string', + 'routingKeyPattern is required!'); this._bindings.push(binding); - if(!this._fake && this._channel) { - debug("Binding %s to %s with pattern '%s'", + if (!this._fake && this._channel) { + debug('Binding %s to %s with pattern \'%s\'', this._queueName || 'exclusive queue', binding.exchange, binding.routingKeyPattern); return this._channel.bindQueue( @@ -262,7 +261,7 @@ PulseListener.prototype.bind = function(binding) { PulseListener.prototype.connect = function() { var that = this; - assert(!this._fake, "Fake listeners can't connect"); + assert(!this._fake, 'Fake listeners can\'t connect'); // Return channel if we have one if (this._channel) { @@ -280,16 +279,16 @@ PulseListener.prototype.connect = function() { // Prevent invalidation of the connection, by someone calling .close() // this way channel.close() won't be called when .close() is called. that._channel = null; - debug("Channel error in PulseListener: ", err.stack); + debug('Channel error in PulseListener: ', err.stack); that.emit('error', err); }); channel.on('close', function() { if (!that._channel) { return; // Ignore if close() was called } - debug("Channel was closed unexpectedly"); + debug('Channel was closed unexpectedly'); that.emit('error', new Error( - "Channel closed unexpectedly, likely server initiated shutdown" + 'Channel closed unexpectedly, likely server initiated shutdown' )); }); return channel.prefetch(that._options.prefetch); @@ -301,8 +300,8 @@ PulseListener.prototype.connect = function() { this._queueName = [ 'queue', // Required by pulse security model this._connection.namespace, // Required by pulse security model - this._options.queueName || 'exclusive/' + slugid.v4() - ].join('/') + this._options.queueName || 'exclusive/' + slugid.v4(), + ].join('/'); // Create queue var queueCreated = channelCreated.then(function() { @@ -322,7 +321,7 @@ PulseListener.prototype.connect = function() { var bindingsCreated = queueCreated.then(function() { that._channel = channel; return Promise.all(that._bindings.map(function(binding) { - debug("Binding %s to %s with pattern %s", + debug('Binding %s to %s with pattern %s', that._queueName || 'exclusive queue', binding.exchange, binding.routingKeyPattern); return channel.bindQueue( @@ -342,16 +341,16 @@ PulseListener.prototype.connect = function() { /** Pause consumption of messages */ PulseListener.prototype.pause = function() { if (this._fake) { - assert(this._fakeListening, "cannot pause when not listening"); + assert(this._fakeListening, 'cannot pause when not listening'); this._fakeListening = false; return Promise.resolve(); } if (!this._channel) { - debug("WARNING: Paused PulseListener instance was wasn't connected yet"); + debug('WARNING: Paused PulseListener instance was wasn\'t connected yet'); return Promise.resolve(); } - assert(this._channel, "Can't pause when not connected"); + assert(this._channel, 'Can\'t pause when not connected'); return this._channel.cancel(this._consumerTag); }; @@ -360,7 +359,7 @@ PulseListener.prototype.resume = function() { var that = this; if (this._fake) { - assert(!this._fakeListening, "cannot resume when already listening"); + assert(!this._fakeListening, 'cannot resume when already listening'); this._fakeListening = true; return Promise.resolve(); } @@ -385,10 +384,10 @@ PulseListener.prototype.resume = function() { * } */ PulseListener.prototype.fakeMessage = function(message) { - assert(this._fake, "fakeMessage can only be called on a fake PulseListener"); - assert(this._fakeListening, "fakeMessage must be called on a resume'd listener"); + assert(this._fake, 'fakeMessage can only be called on a fake PulseListener'); + assert(this._fakeListening, 'fakeMessage must be called on a resume\'d listener'); var msg = { - content: new Buffer(JSON.stringify(message.payload), "utf-8"), + content: new Buffer(JSON.stringify(message.payload), 'utf-8'), fields: { exchange: message.exchange, routingKey: message.routingKey, @@ -401,7 +400,7 @@ PulseListener.prototype.fakeMessage = function(message) { }, }; return this._handle(msg); -} +}; /** Handle message*/ PulseListener.prototype._handle = function(msg) { @@ -412,7 +411,7 @@ PulseListener.prototype._handle = function(msg) { exchange: msg.fields.exchange, routingKey: msg.fields.routingKey, redelivered: msg.fields.redelivered, - routes: [] + routes: [], }; // Find CC'ed routes @@ -430,7 +429,7 @@ PulseListener.prototype._handle = function(msg) { // Find routing key reference, if any is available to us var routingKeyReference = null; this._bindings.forEach(function(binding) { - if(binding.exchange === message.exchange && binding.routingKeyReference) { + if (binding.exchange === message.exchange && binding.routingKeyReference) { routingKeyReference = binding.routingKeyReference; } }); @@ -441,7 +440,7 @@ PulseListener.prototype._handle = function(msg) { var routing = {}; var keys = message.routingKey.split('.'); // first handle non-multi keys from the beginning - for(var i = 0; i < routingKeyReference.length; i++) { + for (var i = 0; i < routingKeyReference.length; i++) { var ref = routingKeyReference[i]; if (ref.multipleWords) { break; @@ -451,7 +450,7 @@ PulseListener.prototype._handle = function(msg) { // If we reached a multi key if (i < routingKeyReference.length) { // then handle non-multi keys from the end - for(var j = routingKeyReference.length - 1; j > i; j--) { + for (var j = routingKeyReference.length - 1; j > i; j--) { var ref = routingKeyReference[j]; if (ref.multipleWords) { break; @@ -459,21 +458,20 @@ PulseListener.prototype._handle = function(msg) { routing[ref.name] = keys.pop(); } // Check that we only have one multiWord routing key - assert(i == j, "i != j really shouldn't be the case"); + assert(i == j, 'i != j really shouldn\'t be the case'); routing[routingKeyReference[i].name] = keys.join('.'); } // Provide parsed routing key message.routing = routing; - } - catch(err) { + } catch (err) { // Ideally we should rethrow the exception. But since it's not quite // possible to promise that `routing` (the parsed routing key) is // available... As you can subscribe without providing a routing // key reference. // In short people can assume this is present in most cases, and if they // assume this we get the error at a level where they can handle it. - debug("Failed to parse routingKey: %s for %s with err: %s, as JSON: %j", + debug('Failed to parse routingKey: %s for %s with err: %s, as JSON: %j', message.routingKey, message.exchange, err, err, err.stack); } } @@ -487,16 +485,16 @@ PulseListener.prototype._handle = function(msg) { if (!that._fake) { return that._channel.ack(msg); } else { - debug("Processed fake message %j from %s", message, message.exchange); + debug('Processed fake message %j from %s', message, message.exchange); } }).then(null, function(err) { - debug("Failed to process message %j from %s with error: %s, as JSON: %j", + debug('Failed to process message %j from %s with error: %s, as JSON: %j', message, message.exchange, err, err, err.stack); if (that._fake) { return; } if (message.redelivered) { - debug("Nack (without requeueing) message %j from %s", + debug('Nack (without requeueing) message %j from %s', message, message.exchange); return that._channel.nack(msg, false, false); } else { @@ -504,7 +502,7 @@ PulseListener.prototype._handle = function(msg) { return that._channel.nack(msg, false, true); } }).then(null, function(err) { - debug("CRITICAL: Failed to nack message"); + debug('CRITICAL: Failed to nack message'); that.emit('error', err); }); }; diff --git a/src/sockjs.js b/src/sockjs.js deleted file mode 100644 index 0b77dbf..0000000 --- a/src/sockjs.js +++ /dev/null @@ -1,29 +0,0 @@ -/* SockJS client, version 0.3.4, http://sockjs.org, MIT License - -Copyright (c) 2011-2012 VMware, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -// JSON2 by Douglas Crockford (minified). -var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c1?this._listeners[a]=d.slice(0,e).concat(d.slice(e+1)):delete this._listeners[a];return}return},d.prototype.dispatchEvent=function(a){var b=a.type,c=Array.prototype.slice.call(arguments,0);this["on"+b]&&this["on"+b].apply(this,c);if(this._listeners&&b in this._listeners)for(var d=0;d=3e3&&a<=4999},c.countRTO=function(a){var b;return a>100?b=3*a:b=a+200,b},c.log=function(){b.console&&console.log&&console.log.apply&&console.log.apply(console,arguments)},c.bind=function(a,b){return a.bind?a.bind(b):function(){return a.apply(b,arguments)}},c.flatUrl=function(a){return a.indexOf("?")===-1&&a.indexOf("#")===-1},c.amendUrl=function(b){var d=a.location;if(!b)throw new Error("Wrong url for SockJS");if(!c.flatUrl(b))throw new Error("Only basic urls are supported in SockJS");return b.indexOf("//")===0&&(b=d.protocol+b),b.indexOf("/")===0&&(b=d.protocol+"//"+d.host+b),b=b.replace(/[/]+$/,""),b},c.arrIndexOf=function(a,b){for(var c=0;c=0},c.delay=function(a,b){return typeof a=="function"&&(b=a,a=0),setTimeout(b,a)};var i=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j={"\0":"\\u0000","\x01":"\\u0001","\x02":"\\u0002","\x03":"\\u0003","\x04":"\\u0004","\x05":"\\u0005","\x06":"\\u0006","\x07":"\\u0007","\b":"\\b","\t":"\\t","\n":"\\n","\x0b":"\\u000b","\f":"\\f","\r":"\\r","\x0e":"\\u000e","\x0f":"\\u000f","\x10":"\\u0010","\x11":"\\u0011","\x12":"\\u0012","\x13":"\\u0013","\x14":"\\u0014","\x15":"\\u0015","\x16":"\\u0016","\x17":"\\u0017","\x18":"\\u0018","\x19":"\\u0019","\x1a":"\\u001a","\x1b":"\\u001b","\x1c":"\\u001c","\x1d":"\\u001d","\x1e":"\\u001e","\x1f":"\\u001f",'"':'\\"',"\\":"\\\\","\x7f":"\\u007f","\x80":"\\u0080","\x81":"\\u0081","\x82":"\\u0082","\x83":"\\u0083","\x84":"\\u0084","\x85":"\\u0085","\x86":"\\u0086","\x87":"\\u0087","\x88":"\\u0088","\x89":"\\u0089","\x8a":"\\u008a","\x8b":"\\u008b","\x8c":"\\u008c","\x8d":"\\u008d","\x8e":"\\u008e","\x8f":"\\u008f","\x90":"\\u0090","\x91":"\\u0091","\x92":"\\u0092","\x93":"\\u0093","\x94":"\\u0094","\x95":"\\u0095","\x96":"\\u0096","\x97":"\\u0097","\x98":"\\u0098","\x99":"\\u0099","\x9a":"\\u009a","\x9b":"\\u009b","\x9c":"\\u009c","\x9d":"\\u009d","\x9e":"\\u009e","\x9f":"\\u009f","\xad":"\\u00ad","\u0600":"\\u0600","\u0601":"\\u0601","\u0602":"\\u0602","\u0603":"\\u0603","\u0604":"\\u0604","\u070f":"\\u070f","\u17b4":"\\u17b4","\u17b5":"\\u17b5","\u200c":"\\u200c","\u200d":"\\u200d","\u200e":"\\u200e","\u200f":"\\u200f","\u2028":"\\u2028","\u2029":"\\u2029","\u202a":"\\u202a","\u202b":"\\u202b","\u202c":"\\u202c","\u202d":"\\u202d","\u202e":"\\u202e","\u202f":"\\u202f","\u2060":"\\u2060","\u2061":"\\u2061","\u2062":"\\u2062","\u2063":"\\u2063","\u2064":"\\u2064","\u2065":"\\u2065","\u2066":"\\u2066","\u2067":"\\u2067","\u2068":"\\u2068","\u2069":"\\u2069","\u206a":"\\u206a","\u206b":"\\u206b","\u206c":"\\u206c","\u206d":"\\u206d","\u206e":"\\u206e","\u206f":"\\u206f","\ufeff":"\\ufeff","\ufff0":"\\ufff0","\ufff1":"\\ufff1","\ufff2":"\\ufff2","\ufff3":"\\ufff3","\ufff4":"\\ufff4","\ufff5":"\\ufff5","\ufff6":"\\ufff6","\ufff7":"\\ufff7","\ufff8":"\\ufff8","\ufff9":"\\ufff9","\ufffa":"\\ufffa","\ufffb":"\\ufffb","\ufffc":"\\ufffc","\ufffd":"\\ufffd","\ufffe":"\\ufffe","\uffff":"\\uffff"},k=/[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g,l,m=JSON&&JSON.stringify||function(a){return i.lastIndex=0,i.test(a)&&(a=a.replace(i,function(a){return j[a]})),'"'+a+'"'},n=function(a){var b,c={},d=[];for(b=0;b<65536;b++)d.push(String.fromCharCode(b));return a.lastIndex=0,d.join("").replace(a,function(a){return c[a]="\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4),""}),a.lastIndex=0,c};c.quote=function(a){var b=m(a);return k.lastIndex=0,k.test(b)?(l||(l=n(k)),b.replace(k,function(a){return l[a]})):b};var o=["websocket","xdr-streaming","xhr-streaming","iframe-eventsource","iframe-htmlfile","xdr-polling","xhr-polling","iframe-xhr-polling","jsonp-polling"];c.probeProtocols=function(){var a={};for(var b=0;b0&&h(a)};return c.websocket!==!1&&h(["websocket"]),d["xhr-streaming"]&&!c.null_origin?e.push("xhr-streaming"):d["xdr-streaming"]&&!c.cookie_needed&&!c.null_origin?e.push("xdr-streaming"):h(["iframe-eventsource","iframe-htmlfile"]),d["xhr-polling"]&&!c.null_origin?e.push("xhr-polling"):d["xdr-polling"]&&!c.cookie_needed&&!c.null_origin?e.push("xdr-polling"):h(["iframe-xhr-polling","jsonp-polling"]),e};var p="_sockjs_global";c.createHook=function(){var a="a"+c.random_string(8);if(!(p in b)){var d={};b[p]=function(a){return a in d||(d[a]={id:a,del:function(){delete d[a]}}),d[a]}}return b[p](a)},c.attachMessage=function(a){c.attachEvent("message",a)},c.attachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.addEventListener(c,d,!1):(a.attachEvent("on"+c,d),b.attachEvent("on"+c,d))},c.detachMessage=function(a){c.detachEvent("message",a)},c.detachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.removeEventListener(c,d,!1):(a.detachEvent("on"+c,d),b.detachEvent("on"+c,d))};var q={},r=!1,s=function(){for(var a in q)q[a](),delete q[a]},t=function(){if(r)return;r=!0,s()};c.attachEvent("unload",t),c.unload_add=function(a){var b=c.random_string(8);return q[b]=a,r&&c.delay(s),b},c.unload_del=function(a){a in q&&delete q[a]},c.createIframe=function(b,d){var e=a.createElement("iframe"),f,g,h=function(){clearTimeout(f);try{e.onload=null}catch(a){}e.onerror=null},i=function(){e&&(h(),setTimeout(function(){e&&e.parentNode.removeChild(e),e=null},0),c.unload_del(g))},j=function(a){e&&(i(),d(a))},k=function(a,b){try{e&&e.contentWindow&&e.contentWindow.postMessage(a,b)}catch(c){}};return e.src=b,e.style.display="none",e.style.position="absolute",e.onerror=function(){j("onerror")},e.onload=function(){clearTimeout(f),f=setTimeout(function(){j("onload timeout")},2e3)},a.body.appendChild(e),f=setTimeout(function(){j("timeout")},15e3),g=c.unload_add(i),{post:k,cleanup:i,loaded:h}},c.createHtmlfile=function(a,d){var e=new ActiveXObject("htmlfile"),f,g,i,j=function(){clearTimeout(f)},k=function(){e&&(j(),c.unload_del(g),i.parentNode.removeChild(i),i=e=null,CollectGarbage())},l=function(a){e&&(k(),d(a))},m=function(a,b){try{i&&i.contentWindow&&i.contentWindow.postMessage(a,b)}catch(c){}};e.open(),e.write('