123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- /*!
- * utility - lib/utility.js
- *
- * Copyright(c) 2012 - 2014 fengmk2 <fengmk2@gmail.com>
- * MIT Licensed
- */
- "use strict";
- /**
- * Module dependencies.
- */
- var crypto = require('crypto');
- var address = require('address');
- /**
- * A empty function.
- *
- * @return {Function}
- * @public
- */
- exports.noop = function () {};
- function sortObject(o) {
- if (!o || Array.isArray(o) || typeof o !== 'object') {
- return o;
- }
- var keys = Object.keys(o);
- keys.sort();
- var values = [];
- for (var i = 0; i < keys.length; i++) {
- var k = keys[i];
- values.push([k, sortObject(o[k])]);
- }
- return values;
- }
- /**
- * hash
- *
- * @param {String} method hash method, e.g.: 'md5', 'sha1'
- * @param {String|Buffer} s
- * @param {String} [format] output string format, could be 'hex' or 'base64'. default is 'hex'.
- * @return {String} md5 hash string
- * @public
- */
- exports.hash = function hash(method, s, format) {
- var sum = crypto.createHash(method);
- var isBuffer = Buffer.isBuffer(s);
- if (!isBuffer && typeof s === 'object') {
- s = JSON.stringify(sortObject(s));
- }
- sum.update(s, isBuffer ? 'binary' : 'utf8');
- return sum.digest(format || 'hex');
- };
- /**
- * md5 hash
- *
- * @param {String|Buffer} s
- * @param {String} [format] output string format, could be 'hex' or 'base64'. default is 'hex'.
- * @return {String} md5 hash string
- * @public
- */
- exports.md5 = function (s, format) {
- return exports.hash('md5', s, format);
- };
- /**
- * sha1 hash
- *
- * @param {String|Buffer} s
- * @param {String} [format] output string format, could be 'hex' or 'base64'. default is 'hex'.
- * @return {String} sha1 hash string
- * @public
- */
- exports.sha1 = function (s, format) {
- return exports.hash('sha1', s, format);
- };
- /**
- * HMAC algorithm.
- *
- * Equal bash:
- *
- * ```bash
- * $ echo -n "$data" | openssl dgst -binary -$algorithm -hmac "$key" | openssl $encoding
- * ```
- *
- * @param {String} algorithm, dependent on the available algorithms supported by the version of OpenSSL on the platform.
- * Examples are 'sha1', 'md5', 'sha256', 'sha512', etc.
- * On recent releases, `openssl list-message-digest-algorithms` will display the available digest algorithms.
- * @param {String} key, the hmac key to be used.
- * @param {String|Buffer} data, content string.
- * @param {String} [encoding='base64']
- * @return {String} digest string.
- */
- exports.hmac = function (algorithm, key, data, encoding) {
- encoding = encoding || 'base64';
- var hmac = crypto.createHmac(algorithm, key);
- hmac.update(data, Buffer.isBuffer(data) ? 'binary' : 'utf8');
- return hmac.digest(encoding);
- };
- /**
- * Base64 encode string.
- *
- * @param {String|Buffer} s
- * @param {Boolean} [urlsafe=false] Encode string s using a URL-safe alphabet,
- * which substitutes - instead of + and _ instead of / in the standard Base64 alphabet.
- * @return {String} base64 encode format string.
- */
- exports.base64encode = function (s, urlsafe) {
- if (!Buffer.isBuffer(s)) {
- s = new Buffer(s);
- }
- var encode = s.toString('base64');
- if (urlsafe) {
- encode = encode.replace(/\+/g, '-').replace(/\//g, '_');
- }
- return encode;
- };
- /**
- * Base64 string decode.
- *
- * @param {String} encode, base64 encoding string.
- * @param {Boolean} [urlsafe=false] Decode string s using a URL-safe alphabet,
- * which substitutes - instead of + and _ instead of / in the standard Base64 alphabet.
- * @return {String} plain text.
- */
- exports.base64decode = function (encode, urlsafe) {
- if (urlsafe) {
- encode = encode.replace(/\-/g, '+').replace(/_/g, '/');
- }
- encode = new Buffer(encode, 'base64');
- return encode.toString();
- };
- /**
- * Escape the given string of `html`.
- *
- * @param {String} html
- * @return {String}
- * @public
- */
- exports.escape = function (html) {
- return String(html)
- .replace(/&(?!\w+;)/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/"/g, '"');
- };
- /**
- * Array random slice with items count.
- * @param {Array} arr
- * @param {Number} num, number of sub items.
- * @return {Array}
- */
- exports.randomSlice = function (arr, num) {
- if (!num || num >= arr.length) {
- return arr.slice();
- }
- var index = Math.floor(Math.random() * arr.length);
- var a = [];
- for (var i = 0, j = index; i < num; i++) {
- a.push(arr[j++]);
- if (j === arr.length) {
- j = 0;
- }
- }
- return a;
- };
- /**
- * Safe encodeURIComponent, won't throw any error.
- * If `encodeURIComponent` error happen, just return the original value.
- *
- * @param {String} text
- * @return {String} URL encode string.
- */
- exports.encodeURIComponent = function (text) {
- try {
- return encodeURIComponent(text);
- } catch (e) {
- return text;
- }
- };
- /**
- * Safe decodeURIComponent, won't throw any error.
- * If `decodeURIComponent` error happen, just return the original value.
- *
- * @param {String} encodeText
- * @return {String} URL decode original string.
- */
- exports.decodeURIComponent = function (encodeText) {
- try {
- return decodeURIComponent(encodeText);
- } catch (e) {
- return encodeText;
- }
- };
- var MONTHS = [
- 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
- ];
- // only set once.
- var TIMEZONE = ' ';
- var _hourOffset = parseInt(-(new Date().getTimezoneOffset()) / 60, 10);
- if (_hourOffset >= 0) {
- TIMEZONE += '+';
- } else {
- TIMEZONE += '-';
- }
- _hourOffset = Math.abs(_hourOffset);
- if (_hourOffset < 10) {
- _hourOffset = '0' + _hourOffset;
- }
- TIMEZONE += _hourOffset + '00';
- /**
- * Access log format date. format: `moment().format('DD/MMM/YYYY:HH:mm:ss ZZ')`
- *
- * @return {String}
- */
- exports.accessLogDate = function (d) {
- // 16/Apr/2013:16:40:09 +0800
- d = d || new Date();
- var date = d.getDate();
- if (date < 10) {
- date = '0' + date;
- }
- var hours = d.getHours();
- if (hours < 10) {
- hours = '0' + hours;
- }
- var mintues = d.getMinutes();
- if (mintues < 10) {
- mintues = '0' + mintues;
- }
- var seconds = d.getSeconds();
- if (seconds < 10) {
- seconds = '0' + seconds;
- }
- return date + '/' + MONTHS[d.getMonth()] + '/' + d.getFullYear() +
- ':' + hours + ':' + mintues + ':' + seconds + TIMEZONE;
- };
- /**
- * Normal log format date. format: `moment().format('YYYY-MM-DD HH:mm:ss.SSS')`
- *
- * @return {String}
- */
- exports.logDate = exports.YYYYMMDDHHmmssSSS = function (d, msSep) {
- if (typeof d === 'string') {
- // logDate(msSep)
- msSep = d;
- d = new Date();
- } else {
- // logDate(d, msSep)
- d = d || new Date();
- }
- var date = d.getDate();
- if (date < 10) {
- date = '0' + date;
- }
- var month = d.getMonth() + 1;
- if (month < 10) {
- month = '0' + month;
- }
- var hours = d.getHours();
- if (hours < 10) {
- hours = '0' + hours;
- }
- var mintues = d.getMinutes();
- if (mintues < 10) {
- mintues = '0' + mintues;
- }
- var seconds = d.getSeconds();
- if (seconds < 10) {
- seconds = '0' + seconds;
- }
- var milliseconds = d.getMilliseconds();
- if (milliseconds < 10) {
- milliseconds = '00' + milliseconds;
- } else if (milliseconds < 100) {
- milliseconds = '0' + milliseconds;
- }
- return d.getFullYear() + '-' + month + '-' + date + ' ' +
- hours + ':' + mintues + ':' + seconds + (msSep || '.') + milliseconds;
- };
- /**
- * `moment().format('YYYY-MM-DD HH:mm:ss')` format date string.
- *
- * @return {String}
- */
- exports.YYYYMMDDHHmmss = function (d, options) {
- d = d || new Date();
- var dateSep = '-';
- var timeSep = ':';
- if (options) {
- if (options.dateSep) {
- dateSep = options.dateSep;
- }
- if (options.timeSep) {
- timeSep = options.timeSep;
- }
- }
- var date = d.getDate();
- if (date < 10) {
- date = '0' + date;
- }
- var month = d.getMonth() + 1;
- if (month < 10) {
- month = '0' + month;
- }
- var hours = d.getHours();
- if (hours < 10) {
- hours = '0' + hours;
- }
- var mintues = d.getMinutes();
- if (mintues < 10) {
- mintues = '0' + mintues;
- }
- var seconds = d.getSeconds();
- if (seconds < 10) {
- seconds = '0' + seconds;
- }
- return d.getFullYear() + dateSep + month + dateSep + date + ' ' +
- hours + timeSep + mintues + timeSep + seconds;
- };
- /**
- * `moment().format('YYYY-MM-DD')` format date string.
- *
- * @return {String}
- */
- exports.YYYYMMDD = function YYYYMMDD(d, sep) {
- if (typeof d === 'string') {
- // YYYYMMDD(sep)
- sep = d;
- d = new Date();
- } else {
- // YYYYMMDD(d, sep)
- d = d || new Date();
- if (typeof sep !== 'string') {
- sep = '-';
- }
- }
- var date = d.getDate();
- if (date < 10) {
- date = '0' + date;
- }
- var month = d.getMonth() + 1;
- if (month < 10) {
- month = '0' + month;
- }
- return d.getFullYear() + sep + month + sep + date;
- };
- /**
- * return datetime struct.
- *
- * @return {Object} date
- * - {Number} YYYYMMDD, 20130401
- * - {Number} H, 0, 1, 9, 12, 23
- */
- exports.datestruct = function (now) {
- now = now || new Date();
- return {
- YYYYMMDD: now.getFullYear() * 10000 + (now.getMonth() + 1) * 100 + now.getDate(),
- H: now.getHours()
- };
- };
- var _showWarnning = false;
- /**
- * Get current machine IPv4
- *
- * @param {String} [interfaceName] interface name, default is 'eth' on linux, 'en' on mac os.
- * @return {String} IP address
- */
- exports.getIP = exports.getIPv4 = function (interfaceName) {
- if (!_showWarnning) {
- _showWarnning = true;
- console.warn('[WARNNING] getIP() remove, PLEASE use `https://github.com/fengmk2/address` module instead');
- }
- return address.ip(interfaceName);
- };
- /**
- * Get current machine IPv6
- *
- * @param {String} [interfaceName] interface name, default is 'eth' on linux, 'en' on mac os.
- * @return {String} IP address
- */
- exports.getIPv6 = function (interfaceName) {
- return address.ipv6(interfaceName);
- };
- /**
- * Get a function parameter's names.
- *
- * @param {Function} func
- * @param {Boolean} [useCache], default is true
- * @return {Array} names
- */
- exports.getParamNames = function (func, cache) {
- cache = cache !== false;
- if (cache && func.__cache_names) {
- return func.__cache_names;
- }
- var str = func.toString();
- var names = str.slice(str.indexOf('(') + 1, str.indexOf(')')).match(/([^\s,]+)/g) || [];
- func.__cache_names = names;
- return names;
- };
- // http://www.2ality.com/2013/10/safe-integers.html
- // http://es6.ruanyifeng.com/#docs/number
- exports.MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;
- exports.MIN_SAFE_INTEGER = -exports.MAX_SAFE_INTEGER;
- var MAX_SAFE_INTEGER_STR = exports.MAX_SAFE_INTEGER_STR = String(exports.MAX_SAFE_INTEGER);
- var MAX_SAFE_INTEGER_STR_LENGTH = MAX_SAFE_INTEGER_STR.length;
- /**
- * Detect a number string can safe convert to Javascript Number.
- *
- * @param {String} s number format string, like `"123"`, `"-1000123123123123123123"`
- * @return {Boolean}
- */
- exports.isSafeNumberString = function (s) {
- if (s[0] === '-') {
- s = s.substring(1);
- }
- if (s.length < MAX_SAFE_INTEGER_STR_LENGTH || (s.length === MAX_SAFE_INTEGER_STR_LENGTH && s <= MAX_SAFE_INTEGER_STR)) {
- return true;
- }
- return false;
- };
- /**
- * Convert string to Number if string in safe Number scope.
- *
- * @param {String} s number format string.
- * @return {Number|String} success will return Number, otherise return the original string.
- */
- exports.toSafeNumber = function (s) {
- if (typeof s === 'number') {
- return s;
- }
- return exports.isSafeNumberString(s) ? Number(s) : s;
- };
- /**
- * Get Unix's timestamp in seconds.
- * @return {Number}
- */
- exports.timestamp = function (t) {
- if (t) {
- var v = t;
- if (typeof v === 'string') {
- v = Number(v);
- }
- if (String(t).length === 10) {
- v *= 1000;
- }
- return new Date(v);
- }
- return Math.round(Date.now() / 1000);
- };
- var _setImmediate = typeof setImmediate === 'function' ? setImmediate : process.nextTick;
- exports.setImmediate = function (callback) {
- _setImmediate(callback);
- };
- exports.randomString = function (length, charSet) {
- var result = [];
- length = length || 16;
- charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- while (length--) {
- result.push(charSet[Math.floor(Math.random() * charSet.length)]);
- }
- return result.join('');
- };
- exports.has = function (obj, prop) {
- return Object.prototype.hasOwnProperty.call(obj, prop);
- };
- /**
- * generate a real map object, no constructor, no __proto__
- * @param {Object} [obj], init object, optional
- * @return {Object}
- */
- exports.map = function (obj) {
- var map = Object.create(null);
- if (!obj) {
- return map;
- }
- for (var key in obj) {
- map[key] = obj[key];
- }
- return map;
- };
|