lemon-core
Version:
Lemon Serverless Micro-Service Platform
851 lines • 32.9 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Utilities = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const js_yaml_1 = __importDefault(require("js-yaml"));
const crypto_1 = __importDefault(require("crypto"));
const query_string_1 = __importDefault(require("query-string"));
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const uuid = __importStar(require("uuid"));
const NS = 'util';
const COLORS = {
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m',
};
/**
* class: Utilities
* - various functions
*/
class Utilities {
constructor(_$) {
/**
* parse float by decimal point 2
*/
this.F2 = (x, mode = 'round') => this.FN(x, 2, mode);
/**
* parse float by decimal point 3
*/
this.F3 = (x, mode = 'round') => this.FN(x, 3, mode);
/**
* convert and cut string like `abcd....z`
*/
this.S = (_, h, t = 32, delim = '...') => [typeof _ == 'string' ? _ : `${this.json(_) || ''}`]
.map(s => h && s.length > h + t
? s.substring(0, h) + delim + (s.length > h + t ? s.substring(s.length - t) : '')
: s)
.join('');
/**
* group as qs
*/
this.qs = {
/**
* parse qs string
*/
parse: (q) => this.qs_parse(q),
/**
* stringify qs object
*/
stringify: (q) => this.qs_stringify(q),
};
/**
* get crypto object.
*/
this.crypto = (passwd, algorithm) => {
algorithm = algorithm || 'aes-256-ctr';
const MAGIC = 'LM!#';
return new (class {
constructor() {
this.encrypt = (val) => {
val = val === undefined ? null : val;
// msg = msg && typeof msg == 'object' ? JSON_TAG+JSON.stringify(msg) : msg;
//! 어느 데이터 타입이든 저장하기 위해서, object로 만든다음, 암호화 시킨다.
const msg = JSON.stringify({ alg: algorithm, val: val });
const buffer = Buffer.from(`${MAGIC}${msg || ''}`, 'utf8');
// const key = Buffer.from(`${passwd || ''}`, 'utf8');
const cipher = crypto_1.default.createCipher(algorithm, passwd);
// const cipher = crypto.createCipheriv(algorithm, key, iv);
const crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
return crypted.toString(1 ? 'base64' : 'utf8');
};
this.decrypt = (msg) => {
const buffer = Buffer.from(`${msg || ''}`, 'base64');
// const key = Buffer.from(`${passwd || ''}`, 'utf8');
const decipher = crypto_1.default.createDecipher(algorithm, passwd);
// const decipher = crypto.createDecipheriv(algorithm, key, iv);
const dec = Buffer.concat([decipher.update(buffer), decipher.final()]).toString('utf8');
if (!dec.startsWith(MAGIC))
throw new Error('400 INVALID PASSWD - invalid magic string!');
const data = dec.substr(MAGIC.length);
if (data && !data.startsWith('{') && !data.endsWith('}'))
throw new Error('400 INVALID PASSWD - invalid json string!');
const $msg = JSON.parse(data) || {};
return $msg.val;
};
}
})();
};
/**
* get crypto2 object (w/ Cipheriv).
* - to avoid `(node:66818) Warning: Use Cipheriv for counter mode of aes-256-ctr`
*
* @param passwd password to crypt
* @param algorithm (default as `aes-256-ctr`)
* @param ivNumb iv number to populate. (default as 0, or -1 use random)
* @param magic magic string to verify (default `LM!#`)
*/
this.crypto2 = (passwd, algorithm, ivNumb, magic) => {
algorithm = algorithm || 'aes-256-ctr';
const MAGIC = magic === undefined ? 'LM!#' : `${magic || ''}`;
const iv = Buffer.from(Array.prototype.map.call(Buffer.alloc(16), () => {
return ivNumb === undefined ? 0 : ivNumb === -1 ? Math.floor(Math.random() * 256) : ivNumb;
}));
return new (class {
constructor() {
this.encrypt = (val) => {
val = val === undefined ? null : val;
//! use json string to support all data-type
const msg = JSON.stringify({ alg: algorithm, val: val });
const buffer = Buffer.from(`${MAGIC}${msg || ''}`, 'utf8');
const key = Buffer.concat([Buffer.from(passwd)], Buffer.alloc(32).length);
const cipher = crypto_1.default.createCipheriv(algorithm, key, iv);
const crypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
return crypted.toString('base64');
};
this.decrypt = (msg) => {
const buffer = Buffer.from(`${msg || ''}`, 'base64');
const key = Buffer.concat([Buffer.from(passwd)], Buffer.alloc(32).length);
const decipher = crypto_1.default.createDecipheriv(algorithm, key, iv);
const dec = Buffer.concat([decipher.update(buffer), decipher.final()]).toString('utf8');
if (!dec.startsWith(MAGIC))
throw new Error(`400 INVALID PASSWD - invalid magic string!`);
const data = dec.substr(MAGIC.length);
if (data && !data.startsWith('{') && !data.endsWith('}'))
throw new Error('400 INVALID PASSWD - invalid json string!');
const $msg = JSON.parse(data) || {};
return $msg.val;
};
}
})();
};
/**
* builder for `JWTHelper`
* @param passcode string for verification.
* @param current_ms (optional) current time in millisecond (required to verify `exp`)
*/
this.jwt = (passcode, current_ms) => {
const $U = this;
/**
* main class.
*/
return new (class JWTHelper {
constructor() {
/**
* use `jsonwebtoken` directly.
*/
this.$ = jsonwebtoken_1.default;
/**
* encode object to token string
* - Synchronous Sign with default (HS256: HMAC SHA256)
*
* @param data object
* @param algorithm algorithm to use
*/
this.encode = (data, algorithm = 'HS256') => {
data = current_ms ? Object.assign(Object.assign({}, data), { iat: Math.floor(current_ms / 1000) }) : data;
const token = jsonwebtoken_1.default.sign(data, passcode, { algorithm });
return token;
};
/**
* decode token string
*
* @param token string
*/
this.decode = (token, options) => {
const N = jsonwebtoken_1.default.decode(token, options);
return N;
};
/**
* verify token
* - Synchronous Verify with default (HS256: HMAC SHA256)
*
* @param token
* @param algorithm
* @throws `jwt expired` if exp has expired!.
*/
this.verify = (token, algorithm = 'HS256') => {
const verified = jsonwebtoken_1.default.verify(token, passcode, { algorithms: [algorithm] });
const cur = $U.N(current_ms, 0);
const exp = $U.N(verified === null || verified === void 0 ? void 0 : verified.exp, 0) * 1000;
if (cur > 0 && exp > 0 && exp < current_ms)
throw new Error(`jwt expired at ${$U.ts(exp)}`);
return verified;
};
}
})();
};
this._$ = _$;
this.log = _$.log;
this.err = _$.err;
this.name = `${NS}-utils`;
}
//! some helper function.s
get_env(name, def_val) {
if (typeof this._$.environ === 'function')
return this._$.environ(name, def_val);
// as default, load from proces.env.
const val = (process && process.env[name]) || undefined;
return val === undefined ? def_val : val;
}
env(name, def_val) {
return this.get_env(name, def_val);
}
is_dev() {
const env = this.get_env('ENV') || this.get_env('NODE_ENV') || this.get_env('STAGE');
return env === 'production' || env === 'op' ? false : true;
}
load_data_yaml(name, folder) {
if (!name)
throw new Error('param:name is required!');
folder = folder || 'data';
//! calculate the target data file.
const fname = path_1.default.resolve(__dirname, `../${folder}/` + name + (name.endsWith('.yml') ? '' : '.yml'));
this.log(NS, 'load file =', fname);
//! prepare promised.
const chain = new Promise(function (resolve, reject) {
// Get document, or throw exception on error
try {
const doc = js_yaml_1.default.load(fs_1.default.readFileSync(fname, 'utf8'));
resolve(doc);
}
catch (e) {
reject(e);
}
});
return chain;
}
load_sync_yaml(name, folder) {
if (!name)
throw new Error('param:name is required!');
folder = folder || 'data';
//! calculate the target data file.
const fname = path_1.default.resolve(__dirname, `../${folder}/` + name + (name.endsWith('.yml') ? '' : '.yml'));
// Get document, or throw exception on error
try {
this.log(NS, 'load-sync-file =', fname);
const doc = js_yaml_1.default.load(fs_1.default.readFileSync(fname, 'utf8'));
return doc;
}
catch (e) {
this.err(NS, `error:load-sync-yaml(${name})=`, e);
}
return {};
}
extend(a, b) {
for (const x in b)
a[x] = b[x];
return a;
}
isset(x) {
return x === undefined ? false : true;
}
empty(x) {
return x ? false : true;
}
min(a, b) {
return a < b ? a : b;
}
max(a, b) {
return a > b ? a : b;
}
round(a) {
return Math.round(a);
}
json(o, isSorted) {
if (isSorted) {
const output = {};
Object.keys(o)
.sort()
.forEach(key => {
output[key] = o[key];
});
o = output;
}
return o ? JSON.stringify(o) : typeof o == 'number' ? `${o}` : `${o || ''}`;
}
/**
* timestamp string like `2020-02-22`
*/
static timestamp(date, timeZone) {
const dt = date && typeof date === 'object' ? date : date ? new Date(date) : new Date();
const now = new Date();
const tzo = now.getTimezoneOffset(); // Asia/Seoul => -540
const diff = timeZone * 60 + tzo;
if (diff)
dt.setSeconds(dt.getSeconds() + 1 * diff * 60);
const y = dt.getFullYear();
const m = dt.getMonth() + 1; //Months are zero based
const d = dt.getDate();
const h = dt.getHours();
const i = dt.getMinutes();
const s = dt.getSeconds();
const d2 = (x) => `${x < 10 ? '0' : ''}${x}`;
const ret = d2(y) + '-' + d2(m) + '-' + d2(d) + ' ' + d2(h) + ':' + d2(i) + ':' + d2(s);
return ret;
}
/**
* parse timestamp to date.
*/
static datetime(dt, timeZone) {
let ret = null;
if (typeof dt == 'string') {
const now = new Date();
const tzo = now.getTimezoneOffset();
const diff = timeZone * 60 + tzo;
let tstr = '';
if (/^[12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/.test(dt)) {
// like 1978-12-01
tstr = dt + ' 12:00:00';
}
else if (/^[4-9][0-9]-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/.test(dt)) {
// like 79-12-01
tstr = '19' + dt + ' 12:00:00';
}
else if (/^[0-3][0-9]-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/.test(dt)) {
// like 19-12-01
tstr = '20' + dt + ' 12:00:00';
}
else if (/^[12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) ([01]?[0-9]|2[0-3]):[0-5][0-9]$/.test(dt)) {
// like 1978-12-01 12:34
tstr = dt + ':00';
}
else if (/^[12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) ([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/.test(dt)) {
// like 1978-12-01 12:34:20
tstr = dt + '';
}
else if (/^[12]\d{3}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])$/.test(dt)) {
// like 19781201
tstr = dt.substr(0, 4) + '-' + dt.substr(4, 2) + '-' + dt.substr(6, 2) + ' 12:00:00';
}
else if (/^[12]\d{3}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01]) ([01]?[0-9]|2[0-3])[0-5][0-9]$/.test(dt)) {
// like 19781201 1234
tstr =
dt.substr(0, 4) +
'-' +
dt.substr(4, 2) +
'-' +
dt.substr(6, 2) +
' ' +
dt.substr(9, 2) +
':' +
dt.substr(11, 2) +
':00';
}
ret = ((ts) => {
if (!ts)
return null;
const aa = ts.split(' ');
const dd = aa[0].split('-');
const hh = aa[1].split(':');
const y = parseInt(dd[0]);
const m = parseInt(dd[1]) - 1;
const d = parseInt(dd[2]);
const h = parseInt(hh[0]);
const i = parseInt(hh[1]);
const s = parseInt(hh[2]);
return new Date(y, m, d, h, i, s, 0);
})(tstr);
if (ret && diff)
ret.setSeconds(ret.getSeconds() + -1 * diff * 60);
return ret;
}
else if (typeof dt == 'number') {
ret = new Date(dt);
}
else if (typeof dt == 'object' && dt instanceof Date) {
ret = dt;
}
else if (dt === undefined) {
ret = new Date();
}
else {
throw new Error('Invalid type of dt: ' + typeof dt);
}
return ret;
}
ts(d, timeZone) {
return Utilities.timestamp(d, timeZone);
}
dt(dt, timeZone) {
return Utilities.datetime(dt, timeZone);
}
now() {
return this.dt();
}
/**
* 현재 시간값 (number of milliseconds since midnight of January 1, 1970.)
*
* @returns {number}
*/
current_time_ms(shift) {
const time_shift = this.N(shift, 0);
let ret = new Date().getTime();
ret += time_shift;
return ret;
}
/**
* NameSpace Maker.
*/
NS(ns, color, len, delim) {
if (!ns)
return ns;
len = len || 4;
len = len - ns.length;
len = len < 0 ? 0 : len;
const LC = this.env('LC', '0') === '1'; // LINE COLORING
const SPACE = ' ';
ns = SPACE.substr(0, len) + ns + (delim === undefined ? ':' : `${delim || ''}`);
if (LC && COLORS[color])
ns = `${COLORS[color]}${ns}\x1b[0m`;
return ns;
}
/**
* escape string for mysql.
*/
escape(str, urldecode) {
if (str === undefined)
return 'NULL';
if (this.isInteger(str))
return str;
str = str || '';
if (typeof str == 'object') {
str = JSON.stringify(str);
}
str = str.replace(/\\/g, '\\\\').replace(/\$/g, '\\$').replace(/'/g, "\\'").replace(/"/g, '\\"');
if (urldecode) {
// url-decode
str = decodeURI(str);
}
return "'" + str + "'";
}
/**
* check if integer
* @param x any number or string
*/
isInteger(x) {
return typeof x === 'number' && x % 1 === 0;
}
/**
* convert as integer number.
* @param x any number or string
* @param def default value.
*/
N(x, def) {
try {
if (x === '' || x === undefined || x === null)
return def;
if (typeof x === 'number' && x % 1 === 0)
return x;
if (typeof x == 'number')
return parseInt('' + x);
x = '0' + x;
x = x.startsWith('0-') || x.startsWith('0+') ? x.substr(1) : x; // minus
return parseInt(x.replace(/,/gi, '').trim());
}
catch (e) {
this.err('err at _N: x=' + x + ';' + typeof x + ';' + (e.message || ''), e);
return def;
}
}
/**
* parse as float number (like 1.01)
* @param x any number or string
* @param def default value.
*/
F(x, def) {
try {
if (x === '' || x === undefined || x === null)
return def;
if (typeof x === 'number' && x % 1 === 0)
return x;
if (typeof x == 'number')
return parseFloat('' + x);
x = '0' + x;
x = x.startsWith('0-') || x.startsWith('0+') ? x.substr(1) : x; // minus
return parseFloat(x.replace(/,/gi, '').trim());
}
catch (e) {
this.err('err at _N: x=' + x + ';' + typeof x + ';' + (e.message || ''), e);
return def;
}
}
/**
* parse float by len
* ```
* FN(0.333333, 2) = 0.33
* ```
* @param x any numbe or string
* @param len decimal length
* @param mode 'round' | 'floor'
*/
FN(x, len, mode) {
mode = mode === undefined ? 'round' : mode;
const DIV = [0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0];
if (len < 0 || len >= DIV.length)
throw new Error(`@len[${len}] is out of range!`);
const div = DIV[len];
if (div <= 0)
return this.N(x, 0); // as integer
const val = this.F(x, 0) * div;
const val2 = mode == 'round' ? Math.round(val) : Math.floor(val);
const val3 = val2 / div;
return val3;
}
/**
* remove internal properties which starts with _ or $
*/
cleanup(node) {
return Object.keys(node).reduce(function (N, key) {
if (key.startsWith('_') || key.startsWith('$'))
delete N[key];
return N;
}, node);
}
//! remove underscore variables.
updated(that, that2) {
const updated = Object.keys(that2).reduce((self, key) => {
if (that[key] !== that2[key]) {
if (that[key] === null && that2[key] === '') {
// both same.
return self;
}
self[key] = that2[key];
}
return self;
}, {});
return updated;
}
copy($N) {
return Object.keys($N).reduce(function ($n, key) {
$n[key] = $N[key];
return $n;
}, {});
}
copy_node(node, isClear) {
isClear = isClear === undefined ? false : isClear;
return Object.keys(node).reduce(function (N, key) {
if (key.startsWith('_') || key.startsWith('$'))
return N;
N[key] = isClear ? null : node[key];
return N;
}, {});
}
/**
* clean up all member without only KEY member.
*/
bare_node($N, opts) {
let $n = {};
$n._id = $N._id;
$n._current_time = $N._current_time;
if (opts)
$n = this.extend($n, opts);
return $n;
}
/**
* get keys in difference.
*/
diff(obj1, obj2) {
obj1 = obj1 || {};
obj2 = obj2 || {};
const diff = Object.keys(obj1)
.reduce((result, key) => {
if (!obj2.hasOwnProperty(key)) {
result.push(key);
}
else if (this.isEqual(obj1[key], obj2[key])) {
const resultKeyIndex = result.indexOf(key);
result.splice(resultKeyIndex, 1);
}
return result;
}, Object.keys(obj2))
.sort();
return diff;
}
/**
* check if equal between 2 object.
* - inspired from `underscore` module originally, and optimized for compartibility.
*/
isEqual(obj1, obj2) {
const keys = Object.keys;
function tagTester(name) {
return function (obj) {
return toString.call(obj) === '[object ' + name + ']';
};
}
const isFunction = tagTester('Function');
function _has(obj, path) {
return obj != null && Object.hasOwnProperty.call(obj, path);
}
// Internal recursive comparison function for `isEqual`.
function eq(a, b, aStack, bStack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the [Harmony `egal` proposal](https://wiki.ecmascript.org/doku.php?id=harmony:egal).
if (a === b)
return a !== 0 || 1 / a === 1 / b;
// `null` or `undefined` only equal to itself (strict comparison).
if (a == null || b == null)
return false;
// `NaN`s are equivalent, but non-reflexive.
if (a !== a)
return b !== b;
// Exhaust primitive checks
const type = typeof a;
if (type !== 'function' && type !== 'object' && typeof b != 'object')
return false;
return deepEq(a, b, aStack, bStack);
}
// Internal recursive comparison function for `isEqual`.
function deepEq(a, b, aStack, bStack) {
// Compare `[[Class]]` names.
const className = toString.call(a);
if (className !== toString.call(b))
return false;
switch (className) {
// Strings, numbers, regular expressions, dates, and booleans are compared by value.
case '[object RegExp]':
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
case '[object String]':
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
return '' + a === '' + b;
case '[object Number]':
// `NaN`s are equivalent, but non-reflexive.
// Object(NaN) is equivalent to NaN.
if (+a !== +a)
return +b !== +b;
// An `egal` comparison is performed for other numeric values.
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
case '[object Date]':
case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
return +a === +b;
}
const areArrays = className === '[object Array]';
if (!areArrays) {
if (typeof a != 'object' || typeof b != 'object')
return false;
// Objects with different constructors are not equivalent, but `Object`s or `Array`s
// from different frames are.
const aCtor = a.constructor, bCtor = b.constructor;
if (aCtor !== bCtor &&
!(isFunction(aCtor) && aCtor instanceof aCtor && isFunction(bCtor) && bCtor instanceof bCtor) &&
'constructor' in a &&
'constructor' in b) {
return false;
}
}
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
// Initializing stack of traversed objects.
// It's done here since we only need them for objects and arrays comparison.
aStack = aStack || [];
bStack = bStack || [];
let length = aStack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (aStack[length] === a)
return bStack[length] === b;
}
// Add the first object to the stack of traversed objects.
aStack.push(a);
bStack.push(b);
// Recursively compare objects and arrays.
if (areArrays) {
// Compare array lengths to determine if a deep comparison is necessary.
length = a.length;
if (length !== b.length)
return false;
// Deep compare the contents, ignoring non-numeric properties.
while (length--) {
if (!eq(a[length], b[length], aStack, bStack))
return false;
}
}
else {
// Deep compare objects.
const _keys = keys(a);
let key;
length = _keys.length;
// Ensure that both objects contain the same number of properties before comparing deep equality.
if (keys(b).length !== length)
return false;
while (length--) {
// Deep compare each member
key = _keys[length];
if (!(_has(b, key) && eq(a[key], b[key], aStack, bStack)))
return false;
}
}
// Remove the first object from the stack of traversed objects.
aStack.pop();
bStack.pop();
return true;
}
return eq(obj1, obj2);
}
/**
* calcualte node differences
*/
diff_node(obj1, obj2) {
obj1 = obj1 || {};
obj2 = obj2 || {};
const keys1 = Object.keys(obj1).filter(key => (key.startsWith('_') || key.startsWith('$') ? false : true));
const keys2 = Object.keys(obj2).filter(key => (key.startsWith('_') || key.startsWith('$') ? false : true));
const diff = keys1.reduce((list, key) => {
if (!obj2.hasOwnProperty(key)) {
list.push(key);
}
else if (this.isEqual(obj1[key], obj2[key])) {
const resultKeyIndex = list.indexOf(key);
list.splice(resultKeyIndex, 1);
}
return list;
}, keys2);
return diff;
}
/**
* get 32-bits hash value.
*
* @param data
*/
hash(data) {
data = data || '';
data = typeof data === 'object' ? this.json(data, true) : data; //WARN! it must be sorted json.
data = typeof data !== 'string' ? String(data) : data;
/**
* Calculate a 32 bit FNV-1a hash
* Found here: https://gist.github.com/vaiorabbit/5657561
* Ref.: http://isthe.com/chongo/tech/comp/fnv/
*
* @param {string} str the input value
* @param {boolean} [asString=false] set to true to return the hash value as
* 8-digit hex string instead of an integer
* @param {integer} [seed] optionally pass the hash of the previous chunk
* @returns {integer | string}
*/
const hashFnv32a = function (str, asString, seed) {
/*jshint bitwise:false */
let i, l;
let hval = seed === undefined ? 0x811c9dc5 : seed;
for (i = 0, l = str.length; i < l; i++) {
hval ^= str.charCodeAt(i);
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
// Convert to 8 digit hex string
return ('0000000' + (hval >>> 0).toString(16)).substr(-8);
};
return hashFnv32a(data, true);
}
//! start promise chain.
promise(param) {
return new Promise(function (resolve) {
resolve(param);
});
}
//! promise in sequence.
// example) promise_sequence([1,2,3], item => item+1);
promise_sequence(array, func) {
let chain = this.promise(array.shift());
chain = array.reduce((chain, item) => {
return chain.then(() => func(item));
}, chain.then(item => func(item)));
return chain;
}
/**
* get md5 hash
*/
md5(data, digest) {
digest = digest === undefined ? 'hex' : digest;
return crypto_1.default.createHash('md5').update(data).digest(digest);
}
/**
* get hmac hash
*/
hmac(data, KEY, algorithm, encoding) {
KEY = KEY || 'XENI';
encoding = encoding || 'base64';
algorithm = algorithm || 'sha256';
return crypto_1.default.createHmac(algorithm, KEY).update(data).digest(encoding);
}
/**
* parse query-string.
*
* @param query
*/
qs_parse(query) {
const param = query_string_1.default.parse(query);
Object.keys(param).forEach(key => {
if (false) {
}
//! 빈 파라미터의 값을 빈 문자열로 치환
else if (param[key] === null) {
param[key] = '';
}
//! 숫자로 된 문자열이 오면 숫자로 변환
else if (/^[1-9][0-9]*$/.test(param[key])) {
param[key] = this.N(param[key]);
}
});
return param;
}
/**
* stringify as querystring.
* @param query
*/
qs_stringify(query) {
const param = query_string_1.default.stringify(query);
return param;
}
/**
* get UUID as `uuid.v4()`
*/
uuid() {
return uuid.v4();
}
}
exports.Utilities = Utilities;
//# sourceMappingURL=utilities.js.map
;