noodlefrenzy/node-amqp10

View on GitHub
lib/utilities.js

Summary

Maintainability
C
1 day
Test Coverage
'use strict';
var _ = require('lodash'),
    //errors = require('./errors'),
    crypto = require('crypto');

var utilities = module.exports = {};

// lodash aliases
utilities.defaults = _.defaultsDeep;
utilities.includes = _.includes;
utilities.isObject = _.isObject;
utilities.isNumber = _.isNumber;
utilities.values = _.values;
utilities.merge = _.merge;
utilities.clone = _.cloneDeep;

function bufferEqualsLegacy(lhs, rhs, offset1, offset2, size) {
  if (offset1 === undefined && offset2 === undefined && size === undefined) {
    if (lhs.length !== rhs.length) return false;
  }
  var slice1 = (offset1 === undefined && size === undefined) ? lhs : lhs.slice(offset1 || 0, size || lhs.length);
  var slice2 = (offset2 === undefined && size === undefined) ? rhs : rhs.slice(offset2 || 0, size || rhs.length);
  for (var idx = 0; idx < slice1.length; ++idx) {
    if (slice1[idx] !== slice2[idx]) return false;
  }
  return true;
}

function bufferEquals(lhs, rhs) {
  return lhs.compare(rhs) === 0;
}

utilities.bufferEquals =
  (typeof Buffer.compare === 'function') ? bufferEquals: bufferEqualsLegacy;

function deepMerge() {
  var args = Array.prototype.slice.call(arguments);
  var helper = function(tgt, src, key) {
    var s2, t2;
    if (key === undefined) {
      t2 = tgt;
      s2 = src;
    } else {
      if (!tgt[key]) {
        if (src[key] instanceof Buffer) {
          tgt[key] = new Buffer(src[key]);
        } else {
          tgt[key] = new src[key].constructor();
        }
      }
      t2 = tgt[key];
      s2 = src[key];
    }

    for (var k2 in s2) {
      if (s2.hasOwnProperty(k2)) {
        var v2 = s2[k2];
        if (v2 !== null && typeof v2 === 'object') {
          helper(t2, s2, k2);
        } else {
          t2[k2] = s2[k2];
        }
      }
    }
  };

  var merged = null;
  for (var idx = args.length - 1; idx >= 0; --idx) {
    var curObj = args[idx];
    if (merged === null) {
      merged = curObj.constructor();
    }
    helper(merged, curObj);
  }
  return merged;
}

utilities.deepMerge = deepMerge;
utilities.deepCopy = deepMerge;

/**
 * Convenience method to assert that a given options object contains the required arguments.
 *
 * @param options
 * @param argnames
 */
function assertArguments(options, argnames) {
  if (!argnames) return;
  if (!options) throw new TypeError('missing arguments: ' + argnames);
  argnames.forEach(function (argname) {
    if (!options.hasOwnProperty(argname)) {
      throw new TypeError('missing argument: ' + argname);
    }
  });
}

utilities.assertArguments = assertArguments;

function assertArgument(arg, argname) {
  if (arg === undefined) throw new TypeError('missing argument: ' + argname);
}

utilities.assertArgument = assertArgument;

function range(start, end) {
  var result = [], c = end - start + 1;
  while(c--) result[c] = end--;
  return result;
}

utilities.generateTimeouts = function(options) {
  if (options.strategy === 'exponential')
    return range(0, options.retries - 1)
      .map(function(i) { return Math.pow(2, i) * 1000; });

  // default to fibonacci
  return range(0, options.retries - 1)
    .reduce(function(result, value, idx) {
      if (idx === 0) {
        result.push(0);
      } else if (idx === 1) {
        result.push(1);
      } else {
        result.push((result[idx - 2] + result[idx - 1]));
      }

      return result;
    }, [])
    .map(function(i) { return i * 1000; });
};

/**
 * Calculates the start and end for a disposition frame
 *
 * @param message    either a single message or an array of them
 * @return {Object}
 */
utilities.dispositionRange = function(message) {
  var first, last;
  if (_.isArray(message)) {
    first = message[0]._deliveryId;
    last = message[message.length - 1]._deliveryId;
  } else {
    first = last = message._deliveryId;
  }

  return {
    first: first,
    last: last
  };
};

/**
 * Generates a link name for a given address
 *
 * @param address             link address
 * @param [policyOverrides]   link creation policy overrides
 * @return {String}
 */
utilities.linkName = function(address, policyOverrides) {
  var name = ((!!policyOverrides && !!policyOverrides.name) ?
    policyOverrides.name : address + '_' + uuidV4());
  if (policyOverrides.hasOwnProperty('attach') &&
      policyOverrides.attach.hasOwnProperty('source') &&
      policyOverrides.attach.source.hasOwnProperty('dynamic') &&
      policyOverrides.attach.source.dynamic === true) {
    name = 'dynamic' + name;
  }

  return name;
};

utilities.camelCase = function(name) {
  return name.toLowerCase()
    .replace(/[-_:]+/g, ' ')
    .replace(/[^\w\s]/g, '')
    .replace(/ (.)/g, function($1) { return $1.toUpperCase(); })
    .replace(/ /g, '' );
};

// Maps for number <-> hex string conversion
var BYTE_TO_HEX = [];
var HEX_TO_BYTE = {};
for (var i = 0; i < 256; i++) {
  BYTE_TO_HEX[i] = (i + 0x100).toString(16).substr(1);
  HEX_TO_BYTE[BYTE_TO_HEX[i]] = i;
}

function parseUuid(s, buf, offset) {
  var i = (buf && offset) || 0, ii = 0;
  buf = buf || [];
  s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
    if (ii < 16) { // Don't overflow!
      buf[i + ii++] = HEX_TO_BYTE[oct];
    }
  });

  // Zero out remaining bytes if string was short
  while (ii < 16) {
    buf[i + ii++] = 0;
  }

  return buf;
}

function unparseUuid(buf, offset) {
  var i = offset || 0;
  return  BYTE_TO_HEX[buf[i++]] + BYTE_TO_HEX[buf[i++]] +
          BYTE_TO_HEX[buf[i++]] + BYTE_TO_HEX[buf[i++]] + '-' +
          BYTE_TO_HEX[buf[i++]] + BYTE_TO_HEX[buf[i++]] + '-' +
          BYTE_TO_HEX[buf[i++]] + BYTE_TO_HEX[buf[i++]] + '-' +
          BYTE_TO_HEX[buf[i++]] + BYTE_TO_HEX[buf[i++]] + '-' +
          BYTE_TO_HEX[buf[i++]] + BYTE_TO_HEX[buf[i++]] +
          BYTE_TO_HEX[buf[i++]] + BYTE_TO_HEX[buf[i++]] +
          BYTE_TO_HEX[buf[i++]] + BYTE_TO_HEX[buf[i++]];
}

function uuidV4() {
  var data = crypto.randomBytes(16);
  data[6] = (data[6] & 0x0f) | 0x40;
  data[8] = (data[8] & 0x3f) | 0x80;
  return unparseUuid(data);
}

utilities.parseUuid = parseUuid;
utilities.unparseUuid = unparseUuid;
utilities.uuidV4 = uuidV4;