wo-core-toolkit/index.js
2022-03-25 20:04:42 +08:00

193 lines
7.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 基础小工具,可通用于服务端和用户端
*/
module.exports = {
sleep: (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms)),
parseJsonPossible(value) {
try {
return JSON.parse(value)
} catch (e) {
return value
}
},
// 按顺序展开,哪怕嵌套。
stringifyOrdered (obj, {cmp, cycles = false, space = '', replacer, schemaColumns, excludeKeys = []} = {}) {
/* 这个解决方法不考虑缺省值,不能把嵌套对象也按顺序展开。*/
// return JSON.stringify(obj, Object.keys(schemaColumns || entity).sort().filter(key => ! excludeKeys.includes(key))) // JSON.stringify 可根据第二个数组参数的顺序排序
let newObj = {}
if (schemaColumns) {
for (let key in schemaColumns){
if (schemaColumns.hasOwnProperty(key) && ! schemaColumns[key].hashExclusive && ! excludeKeys.includes(key)) {
// JSON.stringify (包括本函数)会把 NaN 或 Infinity 输出为 null会把 undefined 忽略掉。
// 而在typeorm sqlite数据库中undefined 会自动存为 schemaColumns[key].default 或 null。从数据库读出时就会和事先JSON.stringify的结果不一致。
// 为了和数据库保持一致习惯对schemaColumns里的键值最好把 undefined 也设为 default 或 null。
if (obj[key] === undefined || Number.isNaN(obj[key]) || obj[key] === Infinity) {
newObj[key] = schemaColumns[key].default || null
obj[key] = schemaColumns[key].default || null // 确保内存中的数据和数据库保持一致
}else {
newObj[key] = obj[key]
}
}
}
}else{
newObj = obj
}
/* 以下代码来自 https://github.com/substack/json-stable-stringify 可把嵌套的复杂值也按顺序输出,例如 { c: 8, b: [{z:6,y:5,x:4},7], a: 3 } */
if (typeof space === 'number') space = Array(space+1).join(' ')
var cycles = (typeof cycles === 'boolean') ? cycles : false
var replacer = replacer || function(key, value) { return value }
var cmp = cmp && (function (f) {
return function (node) {
return function (a, b) {
var aobj = { key: a, value: node[a] }
var bobj = { key: b, value: node[b] }
return f(aobj, bobj)
}
}
})(cmp)
var seen = []
return (function stringify (parent, key, node, level) {
var indent = space ? ('\n' + new Array(level + 1).join(space)) : ''
var colonSeparator = space ? ': ' : ':'
if (node && node.toJSON && typeof node.toJSON === 'function') {
node = node.toJSON()
}
node = replacer.call(parent, key, node)
if (node === undefined) {
return
}
if (typeof node !== 'object' || node === null) {
return JSON.stringify(node)
}
if (Array.isArray(node)) {
var out = []
for (var i = 0; i < node.length; i++) {
var item = stringify(node, i, node[i], level+1) || JSON.stringify(null)
out.push(indent + space + item)
}
return '[' + out.join(',') + indent + ']'
}
else {
if (seen.indexOf(node) !== -1) {
if (cycles) return JSON.stringify('__cycle__')
throw new TypeError('Converting circular structure to JSON')
}
else seen.push(node)
var keys = Object.keys(node).sort(cmp && cmp(node))
var out = []
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
var value = stringify(node, key, node[key], level+1)
if(!value) continue
var keyValue = JSON.stringify(key)
+ colonSeparator
+ value
out.push(indent + space + keyValue)
}
seen.splice(seen.indexOf(node), 1)
return '{' + out.join(',') + indent + '}'
}
})({ '': newObj }, '', newObj, 0)
},
name2port(name='') {
let port = name.toLowerCase()
.replace(/[abc]/g, 2)
.replace(/[def]/g, 3)
.replace(/[ghi]/g, 4)
.replace(/[jkl]/g, 5)
.replace(/[mno]/g, 6)
.replace(/[pqrs]/g, 7)
.replace(/[tuv]/g, 8)
.replace(/[wxyz]/g, 9)
return parseInt(port)
},
randomNumber ({ length, min, max } = {}) {
// 长度为 length 的随机数字,或者 (min||0) <= num < max
var num = 0
if (typeof length === 'number' && length > 0) {
num = parseInt(Math.random() * Math.pow(10, length))
num = num.toString().padStart(length, '0')
} else if (typeof max === 'number' && max > 0) {
min = typeof min === 'number' && min >= 0 ? min : 0
num = parseInt(Math.random() * (max - min)) + min
} else {
// 如果 option 为空
num = Math.random()
}
return num
},
hash (data, { hasher = 'sha256', salt, input = 'utf8', output = 'hex' } = {}) {
if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data)
if (salt && typeof salt === 'string') data = data + salt
const inputEncoding = input // my.INPUT_LIST.indexOf(option.input)>=0?option.input:my.INPUT // 'utf8', 'ascii' or 'latin1' for string data, default to utf8 if not specified; ignored for Buffer, TypedArray, or DataView.
const outputEncoding = output === 'buf' ? undefined : output // (my.OUTPUT_LIST.indexOf(output)>=0?output:my.OUTPUT) // option.output: 留空=》默认输出hex格式或者手动指定 'buf', hex', 'latin1' or 'base64'
return require('crypto').createHash(hasher).update(data, inputEncoding).digest(outputEncoding)
},
/**
* 用户编号转邀请码
*
* @static
* @param {*} aiid
* @return {*}
* @memberof TICrypto
*/
aiid2regcode (aiid) {
const alphabet = 'e5fcdg3hqa4b1n0pij2rstuv67mwx89klyz'
const base = 16367
let num = (aiid + base) * (base - alphabet.length)
let code = ''
let mod
while (num > 0) {
mod = num % alphabet.length
num = (num - mod) / alphabet.length
code = code + alphabet[mod] // 倒序存放
}
return code
},
/**
* 邀请码转用户编号
*
* @static
* @param {*} code
* @return {*}
* @memberof TICrypto
*/
regcode2aiid (code) {
if (typeof code === 'string' && /^[a-zA-Z0-9]+$/.test(code)) {
const alphabet = 'e5fcdg3hqa4b1n0pij2rstuv67mwx89klyz'
const base = 16367
code = code.toLowerCase()
let len = code.length
let num = 0
for (let i = 0; i < len; i++) {
num += alphabet.indexOf(code[i]) * Math.pow(alphabet.length, i)
}
let aiid = num / (base - alphabet.length) - base
if (aiid >= 0 && Number.isInteger(aiid)) {
// 允许 aiid===0当第一个用户aiid==1登录时需要一个系统默认的邀请码。
return aiid
}
}
return null // null 代表一切非法的regcode
},
}