happn-3
Version:
pub/sub api as a service using primus and mongo & redis or nedb, can work as cluster, single process or embedded using nedb
290 lines (242 loc) • 8.59 kB
JavaScript
let commons = require("happn-commons"),
fastClone = commons.fastClone,
ms = require("ms"),
happnUtils = commons.utils,
fs = commons.fs,
LRU = commons.lruCache,
_ = commons._;
module.exports = UtilsService;
function UtilsService() {
this.regexCaches = {};
this.selfSignedCertUtil = require("./self-signed-cert-util").create();
}
UtilsService.prototype.clone = function (obj, circular) {
if (!obj) return obj;
if (typeof obj === "string") return obj.toString();
if (!circular) return happnUtils.clone(obj);
else return fastClone(obj); //does not exist for browser
};
UtilsService.prototype.ensureRegexCache = ensureRegexCache;
UtilsService.prototype.wildcardMatch = wildcardMatch;
UtilsService.prototype.checkPath = happnUtils.checkPath;
UtilsService.prototype.removeLast = happnUtils.removeLast;
UtilsService.prototype.computeiv = happnUtils.computeiv;
UtilsService.prototype.asyncCallback = happnUtils.asyncCallback;
UtilsService.prototype.escapeRegex = happnUtils.escapeRegex;
UtilsService.prototype.wrapImmediate = happnUtils.wrapImmediate;
UtilsService.prototype.getMethodNames = getMethodNames;
UtilsService.prototype.buildBoundProxy = buildBoundProxy;
UtilsService.create = function () {
return new UtilsService();
};
function getMethodNames(obj) {
return Object.getOwnPropertyNames(obj).filter((item) => typeof obj[item] === "function");
}
function buildBoundProxy(propertyNames, bindTo) {
return propertyNames.reduce((proxy, propertyName) => {
if (typeof bindTo[propertyName] === "function") {
proxy[propertyName] = bindTo[propertyName].bind(bindTo);
} else {
try {
proxy[propertyName] = this.clone(bindTo[propertyName], true);
} catch (e) {
// absorb
}
}
return proxy;
}, {});
}
function ensureRegexCache(cacheKey, cacheSize, cacheAsObject) {
cacheKey = cacheKey || "default";
if (cacheAsObject && cacheKey === "default")
throw new Error("The default regex cache must be of type LRU");
if (!this.regexCaches[cacheKey]) {
if (cacheAsObject)
this.regexCaches[cacheKey] = {
length: 0,
data: {},
has: function (key) {
return this.data[key] != null;
},
get: function (key) {
return this.data[key];
},
set: function (key, data) {
this.data[key] = data;
this.length = Object.keys(this.data).length;
},
};
else {
this.regexCaches[cacheKey] = new LRU({
max: cacheSize || 10e3,
maxAge: 0,
});
}
}
return this.regexCaches[cacheKey];
}
function wildcardMatch(pattern, matchTo, cacheKey, cacheSize, cacheAsObject) {
const preparedOrMatched = happnUtils.wildcardPreliminaryMatch(pattern, matchTo);
if (typeof preparedOrMatched === "boolean") return preparedOrMatched; //we have a match result, return it
const cache = this.ensureRegexCache(cacheKey, cacheSize, cacheAsObject);
if (!cache.has(preparedOrMatched))
cache.set(preparedOrMatched, happnUtils.makeRe(preparedOrMatched));
const regex = cache.get(preparedOrMatched);
regex.lastIndex = 0;
return regex.test(matchTo);
}
UtilsService.prototype.wildcardMatchMultiple = function (patterns, matchTo, cacheKey, cacheSize) {
for (var patternIndex in patterns)
if ((this.wildcardMatch(patterns[patternIndex], matchTo), cacheKey, cacheSize)) return true;
return false;
};
UtilsService.prototype.replacePrefix = function (str, prefix, rep) {
if (rep == null) rep = "";
if (str && prefix && str.indexOf(prefix) === 0)
return rep + str.substring(prefix.length, str.length);
return str;
};
UtilsService.prototype.replaceSuffix = function (str, suffix, rep) {
if (rep == null) rep = "";
if (str && suffix && str.substring(str.length - suffix.length, str.length) === suffix)
return str.substring(0, str.length - suffix.length) + rep;
return str;
};
UtilsService.prototype.isNumeric = function (n) {
return !isNaN(parseFloat(n)) && isFinite(n);
};
UtilsService.prototype.toMilliseconds = function (input) {
if (!input || input === Infinity) return input;
if (this.isNumeric(input)) return input;
else return ms(input);
};
UtilsService.prototype.hrtimeDiffInMilliseconds = function (previousTime) {
// Return the difference between 2 hrtimes in milliseconds
// with appropriate decimal fraction from the nano portion
// eg. 0.001763 milliseconds or 1000.030201 milliseconds
var diff = process.hrtime(previousTime);
return diff[0] * 1000 + diff[1] / 1000000;
};
UtilsService.prototype.stringContainsAny = function (str, segments, caseInSensitive) {
var containsAny = false;
segments.every(function (segment) {
var compareSegment = segment;
var compareStr = str;
if (caseInSensitive) {
compareSegment = segment.toUpperCase();
compareStr = str.toUpperCase();
}
if (compareStr.indexOf(compareSegment) > -1) {
containsAny = true;
return false;
} else return true;
});
return containsAny;
};
UtilsService.prototype.stringifyError = function (err) {
var plainError = {};
Object.getOwnPropertyNames(err).forEach(function (key) {
plainError[key] = err[key];
});
return JSON.stringify(plainError);
};
UtilsService.prototype.getFirstMatchingProperty = function (properties, obj) {
var checkProperties = [];
properties.map(function (propertyName) {
checkProperties.push(propertyName.toLowerCase());
});
for (var propertyName in obj)
if (checkProperties.indexOf(propertyName.toLowerCase()) > -1) return obj[propertyName];
return null;
};
UtilsService.prototype.mergeObjects = function (obj1, obj2, opts) {
var _this = this;
if (!opts) opts = {};
var newObj = {};
var getProp = function (obj, propertyName) {
if (!opts.clone) return obj[propertyName];
return _this.clone(obj[propertyName]);
};
for (var propertyName1 in obj1) {
newObj[propertyName1] = getProp(obj1, propertyName1);
}
for (var propertyName2 in obj2) {
if (newObj[propertyName2] && !opts.overwrite) continue;
newObj[propertyName2] = getProp(obj2, propertyName2);
}
return newObj;
};
UtilsService.prototype.promisify = function (originalFunction, opts) {
return function () {
var args = Array.prototype.slice.call(arguments);
var _this = this;
if (opts && opts.unshift) args.unshift(opts.unshift);
// No promisify if last passed arg is function (ie callback)
if (typeof args[args.length - 1] === "function") {
return originalFunction.apply(this, args);
}
return new Promise(function (resolve, reject) {
// push false callback into arguments
args.push(function (error, result, more) {
if (error) return reject(error);
if (more) {
var args = Array.prototype.slice.call(arguments);
args.shift(); // toss undefined error
return resolve(args); // resolve array of args passed to callback
}
return resolve(result);
});
try {
return originalFunction.apply(_this, args);
} catch (error) {
return reject(error);
}
});
};
};
UtilsService.prototype.fileExists = function (path) {
try {
return fs.statSync(path).isFile();
} catch (e) {
return false;
}
};
UtilsService.prototype.isEmptyObject = function (obj) {
for (let _property in obj) {
return false;
}
return true;
};
UtilsService.prototype.replaceAll = function (str, search, replacement) {
return str.replaceAll(search, replacement);
};
UtilsService.prototype.coerceArray = function (possibleArray) {
let first = possibleArray,
rest = [null];
if (Array.isArray(possibleArray)) {
[first, ...rest] = possibleArray;
}
return [first, ...rest];
};
UtilsService.prototype.getTemplatedPathCombinations = function (template, context, validator) {
let templates = [template];
let templatedRegex = /\{\{(.*?)\}\}/g;
let templateMatch = templatedRegex.exec(template);
while (templateMatch) {
let possibleValueArray = _.get(context, templateMatch[1]);
if (possibleValueArray == null) return [];
let values = Array.isArray(possibleValueArray) ? possibleValueArray : [possibleValueArray];
templates = templates.reduce(
(temps, current) =>
temps.concat(
values.map((val) => {
if (validator) validator(val, templateMatch[1], template);
return this.replaceAll(current, templateMatch[0], val);
})
),
[]
);
templateMatch = templatedRegex.exec(template);
}
return templates;
};